Example #1
0
// Compile takes the Appfile and compiles all the resulting data.
func (c *Core) Compile() error {
	// md stores the metadata about the compilation. This is only written
	// on a successful compile.
	var md CompileMetadata

	// Get the infra implementation for this
	infra, infraCtx, err := c.infra()
	if err != nil {
		return err
	}
	defer maybeClose(infra)

	// Get all the foundation implementations (which are tied as singletons
	// to the infrastructure).
	foundations, foundationCtxs, err := c.foundations()
	if err != nil {
		return err
	}
	for _, f := range foundations {
		defer maybeClose(f)
	}

	// Delete the prior output directory
	log.Printf("[INFO] deleting prior compilation contents: %s", c.compileDir)
	if err := os.RemoveAll(c.compileDir); err != nil {
		return err
	}

	// Reset the metadata cache so we don't have that
	c.resetCompileMetadata()

	// Compile the infrastructure for our application
	log.Printf("[INFO] running infra compile...")
	c.ui.Message("Compiling infra...")
	infraResult, err := infra.Compile(infraCtx)
	if err != nil {
		return err
	}
	md.Infra = infraResult

	// Compile the foundation (not tied to any app). This compilation
	// of the foundation is used for `otto infra` to set everything up.
	log.Printf("[INFO] running foundation compilations")
	md.Foundations = make(map[string]*foundation.CompileResult, len(foundations))
	for i, f := range foundations {
		ctx := foundationCtxs[i]
		c.ui.Message(fmt.Sprintf(
			"Compiling foundation: %s", ctx.Tuple.Type))
		result, err := f.Compile(ctx)
		if err != nil {
			return err
		}

		md.Foundations[ctx.Tuple.Type] = result
	}

	// Walk through the dependencies and compile all of them.
	// We have to compile every dependency for dev building.
	var mdLock sync.Mutex
	md.AppDeps = make(map[string]*app.CompileResult)
	err = c.walk(func(app app.App, ctx *app.Context, root bool) error {
		if !root {
			c.ui.Header(fmt.Sprintf(
				"Compiling dependency '%s'...",
				ctx.Appfile.Application.Name))
		} else {
			c.ui.Header(fmt.Sprintf(
				"Compiling main application..."))
		}

		// If this is the root, we set the dev dep fragments.
		if root {
			// We grab the lock just in case although if we're the
			// root this should be serialized.
			mdLock.Lock()
			ctx.DevDepFragments = make([]string, 0, len(md.AppDeps))
			for _, result := range md.AppDeps {
				if result.DevDepFragmentPath != "" {
					ctx.DevDepFragments = append(
						ctx.DevDepFragments, result.DevDepFragmentPath)
				}
			}
			mdLock.Unlock()
		}

		// Compile the foundations for this app
		subdirs := []string{"app-dev", "app-dev-dep", "app-build", "app-deploy"}
		for i, f := range foundations {
			fCtx := foundationCtxs[i]
			fCtx.Dir = ctx.FoundationDirs[i]

			if _, err := f.Compile(fCtx); err != nil {
				return err
			}

			// Make sure the subdirs exist
			for _, dir := range subdirs {
				if err := os.MkdirAll(filepath.Join(fCtx.Dir, dir), 0755); err != nil {
					return err
				}
			}
		}

		// Compile!
		result, err := app.Compile(ctx)
		if err != nil {
			return err
		}

		// Compile the foundations for this app
		for i, f := range foundations {
			fCtx := foundationCtxs[i]
			fCtx.Dir = ctx.FoundationDirs[i]
			if result != nil {
				fCtx.AppConfig = &result.FoundationConfig
			}

			if _, err := f.Compile(fCtx); err != nil {
				return err
			}

			// Make sure the subdirs exist
			for _, dir := range subdirs {
				if err := os.MkdirAll(filepath.Join(fCtx.Dir, dir), 0755); err != nil {
					return err
				}
			}
		}

		// Store the compilation result in the metadata
		mdLock.Lock()
		defer mdLock.Unlock()

		if root {
			md.App = result
		} else {
			md.AppDeps[ctx.Appfile.ID] = result
		}

		return nil
	})
	if err != nil {
		return err
	}

	// We had no compilation errors! Let's save the metadata
	return c.saveCompileMetadata(&md)
}
Example #2
0
// Compile takes the Appfile and compiles all the resulting data.
func (c *Core) Compile() error {
	// Get the infra implementation for this
	infra, infraCtx, err := c.infra()
	if err != nil {
		return err
	}

	// Get all the foundation implementations (which are tied as singletons
	// to the infrastructure).
	foundations, foundationCtxs, err := c.foundations()
	if err != nil {
		return err
	}

	// Delete the prior output directory
	log.Printf("[INFO] deleting prior compilation contents: %s", c.compileDir)
	if err := os.RemoveAll(c.compileDir); err != nil {
		return err
	}

	// Compile the infrastructure for our application
	log.Printf("[INFO] running infra compile...")
	c.ui.Message("Compiling infra...")
	if _, err := infra.Compile(infraCtx); err != nil {
		return err
	}

	// Compile the foundation (not tied to any app). This compilation
	// of the foundation is used for `otto infra` to set everything up.
	log.Printf("[INFO] running foundation compilations")
	for i, f := range foundations {
		ctx := foundationCtxs[i]
		c.ui.Message(fmt.Sprintf(
			"Compiling foundation: %s", ctx.Tuple.Type))
		if _, err := f.Compile(ctx); err != nil {
			return err
		}
	}

	// Walk through the dependencies and compile all of them.
	// We have to compile every dependency for dev building.
	var resultLock sync.Mutex
	results := make([]*app.CompileResult, 0, len(c.appfileCompiled.Graph.Vertices()))
	err = c.walk(func(app app.App, ctx *app.Context, root bool) error {
		if !root {
			c.ui.Header(fmt.Sprintf(
				"Compiling dependency '%s'...",
				ctx.Appfile.Application.Name))
		} else {
			c.ui.Header(fmt.Sprintf(
				"Compiling main application..."))
		}

		// If this is the root, we set the dev dep fragments.
		if root {
			// We grab the lock just in case although if we're the
			// root this should be serialized.
			resultLock.Lock()
			ctx.DevDepFragments = make([]string, 0, len(results))
			for _, result := range results {
				if result.DevDepFragmentPath != "" {
					ctx.DevDepFragments = append(
						ctx.DevDepFragments, result.DevDepFragmentPath)
				}
			}
			resultLock.Unlock()
		}

		// Compile!
		result, err := app.Compile(ctx)
		if err != nil {
			return err
		}

		// Compile the foundations for this app
		subdirs := []string{"app-dev", "app-dev-dep", "app-build", "app-deploy"}
		for i, f := range foundations {
			fCtx := foundationCtxs[i]
			fCtx.Dir = ctx.FoundationDirs[i]
			if result != nil {
				fCtx.AppConfig = &result.FoundationConfig
			}

			if _, err := f.Compile(fCtx); err != nil {
				return err
			}

			// Make sure the subdirs exist
			for _, dir := range subdirs {
				if err := os.MkdirAll(filepath.Join(fCtx.Dir, dir), 0755); err != nil {
					return err
				}
			}
		}

		// Store the compilation result for later
		resultLock.Lock()
		defer resultLock.Unlock()
		results = append(results, result)

		return nil
	})

	return err
}