// Returns a loaded copy of any appfile.File we find, otherwise returns nil, // which is valid, since Otto can detect app type and calculate defaults. func loadAppfile(flagAppfile string) (*appfile.File, error) { appfilePath, err := findAppfile(flagAppfile) if err != nil { return nil, err } if appfilePath == "" { return nil, nil } return appfile.ParseFile(appfilePath) }
// TestAppfile returns a compiled appfile for the given path. This uses // defaults for detectors and such so it is up to you to use a fairly // complete Appfile. func TestAppfile(t TestT, path string) *appfile.Compiled { def, err := appfile.Default(filepath.Dir(path), &detect.Config{ Detectors: []*detect.Detector{ &detect.Detector{ Type: "test", File: []string{"Appfile"}, }, }, }) if err != nil { t.Fatal("err: ", err) } // Default type should be "test" def.Infrastructure[0].Type = "test" def.Infrastructure[0].Flavor = "test" def.Infrastructure[0].Foundations = nil // Parse the raw file f, err := appfile.ParseFile(path) if err != nil { t.Fatal("err: ", err) } // Merge if err := def.Merge(f); err != nil { t.Fatal("err: ", err) } f = def // Create a temporary directory for the compilation data. We don't // delete this now in case we're using any of that data, but the // temp dir should get cleaned up by the system at some point. td, err := ioutil.TempDir("", "otto") if err != nil { t.Fatal("err: ", err) } // Compile it! compiler, err := appfile.NewCompiler(&appfile.CompileOpts{ Dir: td, }) if err != nil { t.Fatal("err: ", err) } result, err := compiler.Compile(f) if err != nil { t.Fatal("err: ", err) } return result }
// Returns a loaded copy of any appfile.File we find, otherwise returns nil, // which is valid, since Otto can detect app type and calculate defaults. // Also returns the base dir of the appfile, which is the current WD in the // case of a nil appfile. func loadAppfile(flagAppfile string) (*appfile.File, string, error) { appfilePath, err := findAppfile(flagAppfile) if err != nil { return nil, "", err } if appfilePath == "" { wd, err := os.Getwd() if err != nil { return nil, "", err } return nil, wd, nil } app, err := appfile.ParseFile(appfilePath) if err != nil { return nil, "", err } return app, filepath.Dir(app.Path), nil }
func (c *CompileCommand) Run(args []string) int { var flagAppfile string fs := c.FlagSet("compile", FlagSetNone) fs.Usage = func() { c.Ui.Error(c.Help()) } fs.StringVar(&flagAppfile, "appfile", "", "") if err := fs.Parse(args); err != nil { return 1 } // Load a UI ui := c.OttoUi() ui.Header("Loading Appfile...") // Determine all the Appfile paths // // First, if an Appfile was specified on the command-line, it must // exist so we validate that it exists. if flagAppfile != "" { fi, err := os.Stat(flagAppfile) if err != nil { c.Ui.Error(fmt.Sprintf( "Error loading Appfile: %s", err)) return 1 } if fi.IsDir() { flagAppfile = filepath.Join(flagAppfile, DefaultAppfile) } } // If the Appfile is still blank, just use our current directory if flagAppfile == "" { var err error flagAppfile, err = os.Getwd() if err != nil { c.Ui.Error(fmt.Sprintf( "Error loading working directory: %s", err)) return 1 } flagAppfile = filepath.Join(flagAppfile, DefaultAppfile) } // If we have the Appfile, then make sure it is an absoute path if flagAppfile != "" { var err error flagAppfile, err = filepath.Abs(flagAppfile) if err != nil { c.Ui.Error(fmt.Sprintf( "Error getting Appfile path: %s", err)) return 1 } } // Load the appfile. This is the only time we ever load the // raw Appfile. All other commands load the compiled Appfile. var app *appfile.File if fi, err := os.Stat(flagAppfile); err == nil && !fi.IsDir() { app, err = appfile.ParseFile(flagAppfile) if err != nil { c.Ui.Error(err.Error()) return 1 } } // Tell the user what is happening if they have no Appfile if app == nil { ui.Header("No Appfile found! Detecting project information...") ui.Message(fmt.Sprintf( "No Appfile was found. If there is no Appfile, Otto will do its best\n" + "to detect the type of application this is and set reasonable defaults.\n" + "This is a good way to get started with Otto, but over time we recommend\n" + "writing a real Appfile since this will allow more complex customizations,\n" + "the ability to reference dependencies, versioning, and more.")) } // Parse the detectors dataDir, err := c.DataDir() if err != nil { c.Ui.Error(err.Error()) return 1 } detectorDir := filepath.Join(dataDir, DefaultLocalDataDetectorDir) log.Printf("[DEBUG] loading detectors from: %s", detectorDir) detectConfig, err := detect.ParseDir(detectorDir) if err != nil { c.Ui.Error(err.Error()) return 1 } if detectConfig == nil { detectConfig = &detect.Config{} } err = detectConfig.Merge(&detect.Config{Detectors: c.Detectors}) if err != nil { c.Ui.Error(err.Error()) return 1 } // Load the default Appfile so we can merge in any defaults into // the loaded Appfile (if there is one). appDef, err := appfile.Default(filepath.Dir(flagAppfile), detectConfig) if err != nil { c.Ui.Error(fmt.Sprintf( "Error loading Appfile: %s", err)) return 1 } // If there was no loaded Appfile and we don't have an application // type then we weren't able to detect the type. Error. if app == nil && appDef.Application.Type == "" { c.Ui.Error(strings.TrimSpace(errCantDetectType)) return 1 } // Merge the appfiles if app != nil { if err := appDef.Merge(app); err != nil { c.Ui.Error(fmt.Sprintf( "Error loading Appfile: %s", err)) return 1 } } app = appDef // Compile the Appfile ui.Header("Fetching all Appfile dependencies...") capp, err := appfile.Compile(app, &appfile.CompileOpts{ Dir: filepath.Join( filepath.Dir(app.Path), DefaultOutputDir, DefaultOutputDirCompiledAppfile), Detect: detectConfig, Callback: c.compileCallback(ui), }) if err != nil { c.Ui.Error(fmt.Sprintf( "Error compiling Appfile: %s", err)) return 1 } // Get a core core, err := c.Core(capp) if err != nil { c.Ui.Error(fmt.Sprintf( "Error loading core: %s", err)) return 1 } // Get the active infrastructure just for UI reasons infra := app.ActiveInfrastructure() // Before the compilation, output to the user what is going on ui.Header("Compiling...") ui.Message(fmt.Sprintf( "Application: %s (%s)", app.Application.Name, app.Application.Type)) ui.Message(fmt.Sprintf("Project: %s", app.Project.Name)) ui.Message(fmt.Sprintf( "Infrastructure: %s (%s)", infra.Type, infra.Flavor)) ui.Message("") // Compile! if err := core.Compile(); err != nil { c.Ui.Error(fmt.Sprintf( "Error compiling: %s", err)) return 1 } // Success! ui.Header("[green]Compilation success!") ui.Message(fmt.Sprintf( "[green]This means that Otto is now ready to start a development environment,\n" + "deploy this application, build the supporting infastructure, and\n" + "more. See the help for more information.\n\n" + "Supporting files to enable Otto to manage your application from\n" + "development to deployment have been placed in the output directory.\n" + "These files can be manually inspected to determine what Otto will do.")) return 0 }