Example #1
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
}
Example #2
0
func testLoader(t *testing.T) (*Loader, *app.Mock) {
	td, err := ioutil.TempDir("", "otto")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	compiler, err := appfile.NewCompiler(&appfile.CompileOpts{
		Dir: filepath.Join(td, "compile"),
	})
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Create a single mock instance that is returned so we can verify
	// calls and modify return values.
	appMock := new(app.Mock)

	return &Loader{
		Detector: &detect.Config{
			Detectors: []*detect.Detector{
				&detect.Detector{
					Type: "test",
					File: []string{"test-file"},
				},
			},
		},

		Compiler: compiler,

		Apps: map[app.Tuple]app.Factory{
			app.Tuple{"test", "*", "*"}: func() (app.App, error) {
				return appMock, nil
			},
		},
	}, appMock
}
Example #3
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 all the plugins, we use all the plugins for compilation only
	// so we have full access to detectors and app types.
	pluginMgr, err := c.PluginManager()
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing plugin manager: %s", err))
		return 1
	}
	if err := pluginMgr.LoadAll(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error loading plugins: %s", err))
		return 1
	}

	// Load the detectors from the plugins
	detectors := make([]*detect.Detector, 0, 20)
	detectors = append(detectors, c.Detectors...)
	for _, p := range pluginMgr.Plugins() {
		detectors = append(detectors, p.AppMeta.Detectors...)
	}

	// 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: detectors})
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	// Load a UI
	ui := c.OttoUi()
	ui.Header("Loading Appfile...")

	app, appPath, err := loadAppfile(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."))
	}

	// Build the appfile compiler
	var loader appfileLoad.Loader
	compiler, err := appfile.NewCompiler(&appfile.CompileOpts{
		Dir: filepath.Join(
			appPath, DefaultOutputDir, DefaultOutputDirCompiledAppfile),
		Loader:   loader.Load,
		Callback: c.compileCallback(ui),
	})
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing Appfile compiler: %s", err))
		return 1
	}

	// Create the Appfile loader
	if err := pluginMgr.ConfigureCore(c.CoreConfig); err != nil {
		panic(err)
	}
	loader.Detector = detectConfig
	loader.Compiler = compiler
	loader.Apps = c.CoreConfig.Apps

	// Load the complete Appfile
	app, err = loader.Load(app, appPath)
	if err != nil {
		c.Ui.Error(err.Error())
		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 || app.Application.Type == "" {
		c.Ui.Error(strings.TrimSpace(errCantDetectType))
		return 1
	}

	// Compile the Appfile
	ui.Header("Fetching all Appfile dependencies...")
	capp, err := compiler.Compile(app)
	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
	}

	// Store the used plugins so later calls don't have to load everything
	usedPath, err := c.AppfilePluginsPath(capp)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error compiling: %s", err))
		return 1
	}
	if err := pluginMgr.StoreUsed(usedPath); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error compiling plugin data: %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 infrastructure, 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
}