func (c *Core) appContext(f *appfile.File) (*app.Context, error) { // Whether or not this is the root Appfile root := f.ID == c.appfile.ID // We need the configuration for the active infrastructure // so that we can build the tuple below config := f.ActiveInfrastructure() if config == nil { return nil, fmt.Errorf( "infrastructure not found in appfile: %s", f.Project.Infrastructure) } // The tuple we're looking for is the application type, the // infrastructure type, and the infrastructure flavor. Build that // tuple. tuple := app.Tuple{ App: f.Application.Type, Infra: config.Type, InfraFlavor: config.Flavor, } // The output directory for data. This is either the main app so // it goes directly into "app" or it is a dependency and goes into // a dep folder. outputDir := filepath.Join(c.compileDir, "app") if !root { outputDir = filepath.Join( c.compileDir, fmt.Sprintf("dep-%s", f.ID)) } // The cache directory for this app cacheDir := filepath.Join(c.dataDir, "cache", f.ID) if err := os.MkdirAll(cacheDir, 0755); err != nil { return nil, fmt.Errorf( "error making cache directory '%s': %s", cacheDir, err) } // The directory for global data globalDir := filepath.Join(c.dataDir, "global-data") if err := os.MkdirAll(globalDir, 0755); err != nil { return nil, fmt.Errorf( "error making global data directory '%s': %s", globalDir, err) } // Build the contexts for the foundations. We use this // to also compile the list of foundation dirs. foundationDirs := make([]string, len(config.Foundations)) for i, f := range config.Foundations { foundationDirs[i] = filepath.Join( outputDir, fmt.Sprintf("foundation-%s", f.Name)) } // Get the dev IP address ipDB := &localaddr.CachedDB{ DB: &localaddr.DB{Path: filepath.Join(c.dataDir, "ip.db")}, CachePath: filepath.Join(c.localDir, "dev_ip"), } ip, err := ipDB.IP() if err != nil { return nil, fmt.Errorf( "Error retrieving dev IP address: %s", err) } // Get the metadata var compileResult *app.CompileResult md, err := c.compileMetadata() if err != nil { return nil, fmt.Errorf( "Error loading compilation metadata: %s", err) } if md != nil { if root { compileResult = md.App } else { compileResult = md.AppDeps[f.ID] } } // Get the customizations. If we don't have any at all, we fast-path // this by doing nothing. If we do, we have to make a deep copy in // order to prune out the irrelevant ones. if f.Customization != nil && len(f.Customization.Raw) > 0 { // Perform a deep copy of the Appfile so we can modify it fRaw, err := copystructure.Copy(f) if err != nil { return nil, err } f = fRaw.(*appfile.File) // Get the app-only customizations and set it on the Appfile cs := f.Customization.Filter("app") f.Customization = &appfile.CustomizationSet{Raw: cs} } return &app.Context{ CompileResult: compileResult, Dir: outputDir, CacheDir: cacheDir, LocalDir: c.localDir, GlobalDir: globalDir, Tuple: tuple, Application: f.Application, DevIPAddress: ip.String(), Shared: context.Shared{ Appfile: f, FoundationDirs: foundationDirs, InstallDir: filepath.Join(c.dataDir, "binaries"), Directory: c.dir, Ui: c.ui, }, }, nil }