示例#1
0
func (c ProjectCompiler) Compile(projectPath *string, dataFile *string, baseDir *string, workDir *string) {
	log.Notice("▶ Loading environment data from file:\n  %s", *projectPath)

	environment, source, err := loadEnvironment(*projectPath)
	if err != nil {
		util.HandleFatalError(err)
	}

	for _, provider := range environment.Providers {
		log.Notice("▶ Switching provider to: %s", provider.Name)
		log.Debug("  Creating template context")
		if context, err := createContext(&environment.Data, &provider, dataFile); err == nil {

			log.Notice("▶ Context data:")
			printContextData(context, false)

			log.Notice("▶ Compiling artifacts")

			if compiled, err := compileTemplateFromString(context, source); err == nil {
				var project data.Project
				if err := util.LoadYAMLFromString(*compiled, &project); err == nil {
					// Compile each artifact
					for _, artifact := range project.Artifacts {
						//log.Info("  Compiling:\n  artifact: %s\n  provider: %s", artifact.Name, provider.Name)
						if err := compileArtifact(context, &artifact, provider.Name, baseDir, workDir); err != nil {
							util.HandleFatalError(err)
						}
					}
				} else {
					err := errors.New(fmt.Sprintf("Error parsing project artifacts\nerror:\n  %s", err.Error()))
					util.HandleFatalError(err)
				}
			} else {
				util.HandleFatalError(err)
			}
		} else {
			util.HandleFatalError(err)
		}
	}
	log.Notice("▶ Completed successfully")
}
示例#2
0
func validateAndRunBuildCommand(flagProjectFile string, flagDataFile string) error {
	// Validate command
	if len(strings.TrimSpace(flagProjectFile)) == 0 {
		return errors.New("Error: missing project file")
	}

	// Check if project file exists
	if _, err := os.Stat(flagProjectFile); os.IsNotExist(err) {
		return errors.New("Error: Project file doesn't exist")
	}

	// Workdir
	workDir, _ := os.Getwd()
	workDir, _ = filepath.Abs(workDir)

	log.Debug("Work dir: %s", workDir)

	// Get absolute paths
	var projectRootDir string
	if projectAbsolutePath, err := filepath.Abs(flagProjectFile); err == nil {
		projectRootDir = filepath.Dir(projectAbsolutePath)

		log.Debug("Project root:\n  %s", projectRootDir)
		log.Debug("Project file:\n  %s", projectAbsolutePath)

		var dataAbsolutePath *string
		if len(flagDataFile) > 0 {
			if dataPath, err := filepath.Abs(flagDataFile); err == nil {
				dataAbsolutePath = &dataPath
				log.Debug("Extra data file:\n  %s", dataAbsolutePath)
			} else {
				return err
			}
		}

		log.Notice("▶ Building project from file:\n  %s", projectAbsolutePath)
		compiler.ProjectCompiler{}.Compile(&projectAbsolutePath, dataAbsolutePath, &projectRootDir, &workDir)

		return nil
	} else {
		return err
	}
}
示例#3
0
func compileArtifact(context *pongo2.Context, artifact *data.Artifact, providerName string, baseDir *string, workDir *string) error {
	outputFile := filepath.Join(*workDir, "build", providerName, artifact.Name, "user-data")
	outputDir := filepath.Dir(outputFile)

	// Create output directory if missing
	if exists, _ := util.FileExists(outputDir); !exists {
		if err := os.MkdirAll(outputDir, 0755); err != nil {
			return errors.New(fmt.Sprintf("Could not create output directory:\n  %s\n\nnested error:\n  %s", outputDir, err.Error()))
		}
	}

	log.Notice("▶ Compiling artifact [%s] to:\n  %s", artifact.Name, outputFile)

	log.Debug("  Setting artifact name to the context")
	c := pongo2.Context{
		"env": map[string]interface{}{
			"provider": providerName,
			"artifact": artifact.Name,
		},
	}
	if err := mergo.MergeWithOverwrite(context, c); err != nil {
		return err
	}
	printContextData(context, true)

	// Create the initial user data objects
	buffer := bytes.NewBufferString("#cloud-config\n---\n")
	writeFiles := make([]data.WriteFile, 0, 10)
	units := make([]data.Unit, 0, 10)

	// Process bricks
	bricks := artifact.Bricks
	for _, brick := range bricks {
		log.Info("  Processing brick:\n    %s", brick)

		// Load metadata
		if metadata, brickBaseDir, err := loadBrickMetadata(context, baseDir, &brick); err == nil {
			// Process brick files
			log.Debug("  Processing brick files")
			if brickWriteFiles, err := processMetadataFiles(context, metadata, brickBaseDir); err != nil {
				return err
			} else {
				writeFiles = append(writeFiles, brickWriteFiles...)
			}

			// Process brick units
			log.Debug("  Processing brick unit")
			if brickUnit, err := processMetadataUnits(context, metadata, brickBaseDir); err != nil {
				return err
			} else if brickUnit != nil {
				units = append(units, *brickUnit)
			}
		} else {
			return err
		}
	}

	// Write compiled write-files section
	if len(writeFiles) > 0 {
		writeFilesMap := make(map[string]interface{})
		writeFilesMap["write-files"] = writeFiles
		if output, err := yaml.Marshal(writeFilesMap); err != nil {
			return err
		} else {
			buffer.Write(output)
		}
	}

	// Write rest of config file
	cloudConfig := artifact.CloudConfig

	// Custom CoreOS
	if cloudConfig.CoreOS != nil {
		coreOs := cloudConfig.CoreOS

		// Add units
		//		if coreOs["units"] != nil {
		coreOs["units"] = units
		//		}

		// Write CoreOS section
		coreOsMap := make(map[string]interface{})
		coreOsMap["coreos"] = coreOs
		if output, err := yaml.Marshal(coreOsMap); err != nil {
			return err
		} else {
			buffer.Write(output)
		}
	}

	// Append everything else to the end of the file
	if cloudConfig.Generic != nil {
		if output, err := yaml.Marshal(cloudConfig.Generic); err != nil {
			return err
		} else {
			buffer.Write(output)
		}
	}

	log.Info("  Writing output file to:\n    %s", outputFile)
	if err := ioutil.WriteFile(outputFile, buffer.Bytes(), 0755); err != nil {
		return err
	}

	return nil
}
示例#4
0
func main() {
	var flagDebug bool
	var flagVerbose bool
	var flagQuiet bool
	var flagProjectFile string
	var flagDataFile string

	// Root
	var RootCommand = &cobra.Command{
		Use:   "magutt",
		Short: "Magutt is a simple tool to assemble cloud-config files for CoreOS",
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			logLevel := log.LevelInfo

			if flagQuiet && (flagDebug || flagVerbose) {
				log.Warn("I'm confused... How can I be verbose and quiet at the same time?!?!?!?")
				os.Exit(1)
			} else {
				if flagQuiet {
					logLevel = log.LevelOff
				} else {
					if flagDebug {
						logLevel = log.LevelDebug
					}

					// Verbose flag overrides debug level
					if flagVerbose {
						logLevel = log.LevelTrace
					}
				}
			}
			log.SetLogLevel(logLevel)
		},
	}
	RootCommand.PersistentFlags().BoolVarP(&flagQuiet, "quiet", "q", false, "disable logging")
	RootCommand.PersistentFlags().BoolVarP(&flagDebug, "debug", "d", false, "enable debug logging")
	RootCommand.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "enable verbose logging")

	// Build
	var CmdBuild = &cobra.Command{
		Use:   "build",
		Short: "Build a config file",
		Run: func(cmd *cobra.Command, args []string) {
			if err := validateAndRunBuildCommand(flagProjectFile, flagDataFile); err != nil {
				cmd.Usage()
				util.HandleFatalError(err)
			}
		},
	}
	CmdBuild.Flags().StringVarP(&flagProjectFile, "input", "i", "", "input project file")
	CmdBuild.Flags().StringVarP(&flagDataFile, "extra", "e", "", "extra data file")

	// Version
	var CmdVersion = &cobra.Command{
		Use:   "version",
		Short: "Print version number",
		Run: func(cmd *cobra.Command, args []string) {
			log.Notice("Magutt v%s\n", version)
		},
	}

	// Common flags
	RootCommand.AddCommand(CmdBuild)
	RootCommand.AddCommand(CmdVersion)

	// Process command line
	RootCommand.Execute()
}