// CreateMakefile creates a Makefile to build a tree. The cwd should // be the root of the tree you want to make (due to some probably // unnecessary assumptions that CreateMaker makes). func CreateMakefile(execOpt ToolchainExecOpt, cacheOpt BuildCacheOpt) (*makex.Makefile, error) { localRepo, err := OpenRepo(".") if err != nil { return nil, err } buildStore, err := buildstore.LocalRepo(localRepo.RootDir) if err != nil { return nil, err } treeConfig, err := config.ReadCached(buildStore.Commit(localRepo.CommitID)) if err != nil { return nil, err } if len(treeConfig.SourceUnits) == 0 { log.Println("No source unit files found. Did you mean to run `src config`? (This is not an error; it just means that src didn't find anything to build or analyze here.)") } toolchainExecOptArgs, err := flagutil.MarshalArgs(&execOpt) if err != nil { return nil, err } // TODO(sqs): buildDataDir is hardcoded. buildDataDir := filepath.Join(buildstore.BuildDataDirName, localRepo.CommitID) mf, err := plan.CreateMakefile(buildDataDir, buildStore, localRepo.VCSType, treeConfig, plan.Options{ ToolchainExecOpt: strings.Join(toolchainExecOptArgs, " "), NoCache: cacheOpt.NoCacheWrite, }) if err != nil { return nil, err } return mf, nil }
func TestCreateMakefile(t *testing.T) { buildDataDir := "testdata" c := &config.Tree{ SourceUnits: []*unit.SourceUnit{ { Name: "n", Type: "t", Files: []string{"f"}, Ops: map[string]*srclib.ToolRef{ "graph": {Toolchain: "tc", Subcmd: "t"}, "depresolve": {Toolchain: "tc", Subcmd: "t"}, }, }, }, } mf, err := plan.CreateMakefile(buildDataDir, nil, "", c, plan.Options{NoCache: true}) if err != nil { t.Fatal(err) } want := ` all: testdata/n/t.graph.json testdata/n/t.depresolve.json testdata/n/t.graph.json: testdata/n/t.unit.json f src tool "tc" "t" < $< | src internal normalize-graph-data --unit-type "t" --dir . 1> $@ testdata/n/t.depresolve.json: testdata/n/t.unit.json src tool "tc" "t" < $^ 1> $@ .DELETE_ON_ERROR: ` gotBytes, err := makex.Marshal(mf) if err != nil { t.Fatal(err) } want = strings.TrimSpace(want) got := string(bytes.TrimSpace(gotBytes)) if got != want { t.Errorf("got makefile:\n==========\n%s\n==========\n\nwant makefile:\n==========\n%s\n==========", got, want) } }
// Import imports build data into a RepoStore or MultiRepoStore. func Import(buildDataFS vfs.FileSystem, stor interface{}, opt ImportOpt) error { // Traverse the build data directory for this repo and commit to // create the makefile that lists the targets (which are the data // files we will import). treeConfig, err := config.ReadCached(buildDataFS) if err != nil { return err } mf, err := plan.CreateMakefile(".", nil, "", treeConfig, plan.Options{NoCache: true}) if err != nil { return err } var ( mu sync.Mutex hasIndexableData bool ) par := parallel.NewRun(10) for _, rule_ := range mf.Rules { rule := rule_ if opt.Unit != "" || opt.UnitType != "" { type ruleForSourceUnit interface { SourceUnit() *unit.SourceUnit } if rule, ok := rule.(ruleForSourceUnit); ok { u := rule.SourceUnit() if (opt.Unit != "" && u.Name != opt.Unit) || (opt.UnitType != "" && u.Type != opt.UnitType) { continue } } else { // Skip all non-source-unit rules if --unit or // --unit-type are specified. continue } } par.Do(func() error { switch rule := rule.(type) { case *grapher.GraphUnitRule: var data graph.Output if err := readJSONFileFS(buildDataFS, rule.Target(), &data); err != nil { if os.IsNotExist(err) { log.Printf("Warning: no build data for unit %s %s.", rule.Unit.Type, rule.Unit.Name) return nil } return err } if opt.DryRun || GlobalOpt.Verbose { log.Printf("# Importing graph data (%d defs, %d refs, %d docs, %d anns) for unit %s %s", len(data.Defs), len(data.Refs), len(data.Docs), len(data.Anns), rule.Unit.Type, rule.Unit.Name) if opt.DryRun { return nil } } // HACK: Transfer docs to [def].Docs. docsByPath := make(map[string]*graph.Doc, len(data.Docs)) for _, doc := range data.Docs { docsByPath[doc.Path] = doc } for _, def := range data.Defs { if doc, present := docsByPath[def.Path]; present { def.Docs = append(def.Docs, graph.DefDoc{Format: doc.Format, Data: doc.Data}) } } switch imp := stor.(type) { case store.RepoImporter: if err := imp.Import(opt.CommitID, rule.Unit, data); err != nil { return err } case store.MultiRepoImporter: if err := imp.Import(opt.Repo, opt.CommitID, rule.Unit, data); err != nil { return err } default: return fmt.Errorf("store (type %T) does not implement importing", stor) } mu.Lock() hasIndexableData = true mu.Unlock() } return nil }) } if err := par.Wait(); err != nil { return err } if hasIndexableData && !opt.NoIndex { if GlobalOpt.Verbose { log.Printf("# Building indexes") } switch s := stor.(type) { case store.RepoIndexer: if err := s.Index(opt.CommitID); err != nil { return err } case store.MultiRepoIndexer: if err := s.Index(opt.Repo, opt.CommitID); err != nil { return err } } } return nil }