// 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) }
// 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 }