func writeDocs(ctx *blueprint.Context, srcDir, filename string) error { // Find the module that's marked as the "primary builder", which means it's // creating the binary that we'll use to generate the non-bootstrap // build.ninja file. var primaryBuilders []*goBinary var minibp *goBinary ctx.VisitAllModulesIf(isBootstrapBinaryModule, func(module blueprint.Module) { binaryModule := module.(*goBinary) if binaryModule.properties.PrimaryBuilder { primaryBuilders = append(primaryBuilders, binaryModule) } if ctx.ModuleName(binaryModule) == "minibp" { minibp = binaryModule } }) if minibp == nil { panic("missing minibp") } var primaryBuilder *goBinary switch len(primaryBuilders) { case 0: // If there's no primary builder module then that means we'll use minibp // as the primary builder. primaryBuilder = minibp case 1: primaryBuilder = primaryBuilders[0] default: return fmt.Errorf("multiple primary builder modules present") } pkgFiles := make(map[string][]string) ctx.VisitDepsDepthFirst(primaryBuilder, func(module blueprint.Module) { switch m := module.(type) { case (*goPackage): pkgFiles[m.properties.PkgPath] = pathtools.PrefixPaths(m.properties.Srcs, filepath.Join(srcDir, ctx.ModuleDir(m))) default: panic(fmt.Errorf("unknown dependency type %T", module)) } }) return bpdoc.Write(filename, pkgFiles, ctx.ModuleTypePropertyStructs()) }
// removeAbandonedFiles removes any files that appear in the Ninja log that are // not currently build targets. func removeAbandonedFiles(ctx *blueprint.Context, config *Config, srcDir, manifestFile string) error { buildDir := "." switch config.stage { case StageBootstrap: buildDir = miniBootstrapDir case StagePrimary: buildDir = bootstrapDir } targetRules, err := ctx.AllTargets() if err != nil { return fmt.Errorf("error determining target list: %s", err) } replacer := strings.NewReplacer( "@@SrcDir@@", srcDir, "@@BuildDir@@", BuildDir, "@@BootstrapManifest@@", manifestFile) targets := make(map[string]bool) for target := range targetRules { replacedTarget := replacer.Replace(target) targets[filepath.Clean(replacedTarget)] = true } filePaths, err := parseNinjaLog(buildDir) if err != nil { return err } for _, filePath := range filePaths { isTarget := targets[filePath] if !isTarget { err = removeFileAndEmptyDirs(filePath) if err != nil { return err } } } return nil }
func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) { if !flag.Parsed() { flag.Parse() } runtime.GOMAXPROCS(runtime.NumCPU()) if cpuprofile != "" { f, err := os.Create(cpuprofile) if err != nil { fatalf("error opening cpuprofile: %s", err) } pprof.StartCPUProfile(f) defer f.Close() defer pprof.StopCPUProfile() } if flag.NArg() != 1 { fatalf("no Blueprints file specified") } stage := StageMain if c, ok := config.(ConfigInterface); ok { if c.GeneratingBootstrapper() { stage = StageBootstrap } if c.GeneratingPrimaryBuilder() { stage = StagePrimary } } bootstrapConfig := &Config{ stage: stage, topLevelBlueprintsFile: flag.Arg(0), runGoTests: runGoTests, } ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig)) ctx.RegisterModuleType("bootstrap_core_go_binary", newGoBinaryModuleFactory(bootstrapConfig, StageBootstrap)) ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig, StagePrimary)) ctx.RegisterTopDownMutator("bootstrap_stage", propagateStageBootstrap) ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig)) deps, errs := ctx.ParseBlueprintsFiles(bootstrapConfig.topLevelBlueprintsFile) if len(errs) > 0 { fatalErrors(errs) } // Add extra ninja file dependencies deps = append(deps, extraNinjaFileDeps...) errs = ctx.ResolveDependencies(config) if len(errs) > 0 { fatalErrors(errs) } if docFile != "" { err := writeDocs(ctx, filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), docFile) if err != nil { fatalErrors([]error{err}) } return } extraDeps, errs := ctx.PrepareBuildActions(config) if len(errs) > 0 { fatalErrors(errs) } deps = append(deps, extraDeps...) buf := bytes.NewBuffer(nil) err := ctx.WriteBuildFile(buf) if err != nil { fatalf("error generating Ninja file contents: %s", err) } const outFilePermissions = 0666 if timestampFile != "" { err := ioutil.WriteFile(timestampFile, []byte{}, outFilePermissions) if err != nil { fatalf("error writing %s: %s", timestampFile, err) } if timestampDepFile != "" { err := deptools.WriteDepFile(timestampDepFile, timestampFile, deps) if err != nil { fatalf("error writing depfile: %s", err) } } } err = ioutil.WriteFile(outFile, buf.Bytes(), outFilePermissions) if err != nil { fatalf("error writing %s: %s", outFile, err) } if depFile != "" { err := deptools.WriteDepFile(depFile, outFile, deps) if err != nil { fatalf("error writing depfile: %s", err) } err = deptools.WriteDepFile(depFile+".timestamp", outFile+".timestamp", deps) if err != nil { fatalf("error writing depfile: %s", err) } } srcDir := filepath.Dir(bootstrapConfig.topLevelBlueprintsFile) err = removeAbandonedFiles(ctx, bootstrapConfig, srcDir, manifestFile) if err != nil { fatalf("error removing abandoned files: %s", err) } }
func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) { if !flag.Parsed() { flag.Parse() } runtime.GOMAXPROCS(runtime.NumCPU()) if cpuprofile != "" { f, err := os.Create(cpuprofile) if err != nil { fatalf("error opening cpuprofile: %s", err) } pprof.StartCPUProfile(f) defer f.Close() defer pprof.StopCPUProfile() } if flag.NArg() != 1 { fatalf("no Blueprints file specified") } generatingBootstrapper := false if c, ok := config.(ConfigInterface); ok { generatingBootstrapper = c.GeneratingBootstrapper() } bootstrapConfig := &Config{ generatingBootstrapper: generatingBootstrapper, topLevelBlueprintsFile: flag.Arg(0), runGoTests: runGoTests, } ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig)) ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig)) ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig)) deps, errs := ctx.ParseBlueprintsFiles(bootstrapConfig.topLevelBlueprintsFile) if len(errs) > 0 { fatalErrors(errs) } // Add extra ninja file dependencies deps = append(deps, extraNinjaFileDeps...) errs = ctx.ResolveDependencies(config) if len(errs) > 0 { fatalErrors(errs) } if docFile != "" { err := writeDocs(ctx, filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), docFile) if err != nil { fatalErrors([]error{err}) } return } extraDeps, errs := ctx.PrepareBuildActions(config) if len(errs) > 0 { fatalErrors(errs) } deps = append(deps, extraDeps...) buf := bytes.NewBuffer(nil) err := ctx.WriteBuildFile(buf) if err != nil { fatalf("error generating Ninja file contents: %s", err) } const outFilePermissions = 0666 err = ioutil.WriteFile(outFile, buf.Bytes(), outFilePermissions) if err != nil { fatalf("error writing %s: %s", outFile, err) } if checkFile != "" { checkData, err := ioutil.ReadFile(checkFile) if err != nil { fatalf("error reading %s: %s", checkFile, err) } matches := buf.Len() == len(checkData) if matches { for i, value := range buf.Bytes() { if value != checkData[i] { matches = false break } } } if matches { // The new file content matches the check-file content, so we set // the new file's mtime and atime to match that of the check-file. checkFileInfo, err := os.Stat(checkFile) if err != nil { fatalf("error stat'ing %s: %s", checkFile, err) } time := checkFileInfo.ModTime() err = os.Chtimes(outFile, time, time) if err != nil { fatalf("error setting timestamps for %s: %s", outFile, err) } } } if depFile != "" { err := deptools.WriteDepFile(depFile, outFile, deps) if err != nil { fatalf("error writing depfile: %s", err) } } srcDir := filepath.Dir(bootstrapConfig.topLevelBlueprintsFile) err = removeAbandonedFiles(ctx, bootstrapConfig, srcDir, manifestFile) if err != nil { fatalf("error removing abandoned files: %s", err) } }