Ejemplo n.º 1
0
// 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)
}
Ejemplo n.º 2
0
// 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
}
Ejemplo n.º 3
0
// 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
}
Ejemplo n.º 4
0
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
}