Move primary builder command line computation. am: 77ef79b7c4

Original change: https://android-review.googlesource.com/c/platform/build/blueprint/+/1673050

Change-Id: I81958eb1b4ce674920d019cc497fa52a93acb4f1
diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go
index e122bb2..c9cb0e0 100644
--- a/bootstrap/bootstrap.go
+++ b/bootstrap/bootstrap.go
@@ -17,8 +17,6 @@
 import (
 	"fmt"
 	"go/build"
-	"io/ioutil"
-	"os"
 	"path/filepath"
 	"runtime"
 	"strings"
@@ -134,24 +132,18 @@
 				`BUILDER="$$PWD/$$(basename "$builder")" && ` +
 				`cd / && ` +
 				`env -i "$$BUILDER" ` +
-				`    $extra ` +
 				`    --top "$$TOP" ` +
-				`    --out "$$SOONG_OUTDIR" ` +
-				`    --delve_listen "$$SOONG_DELVE" ` +
-				`    --delve_path "$$SOONG_DELVE_PATH" ` +
-				`    -b "$buildDir" ` +
+				`    --out "$buildDir" ` +
 				`    -n "$ninjaBuildDir" ` +
 				`    -d "$out.d" ` +
-				`    -globFile "$globFile" ` +
-				`    -o "$out" ` +
-				`    "$in" `,
+				`    $extra`,
 			CommandDeps: []string{"$builder"},
 			Description: "$builder $out",
 			Deps:        blueprint.DepsGCC,
 			Depfile:     "$out.d",
 			Restat:      true,
 		},
-		"builder", "extra", "generator", "globFile")
+		"builder", "extra")
 
 	// Work around a Ninja issue.  See https://github.com/martine/ninja/pull/634
 	phony = pctx.StaticRule("phony",
@@ -708,73 +700,48 @@
 			}
 		})
 
-	var extraSharedFlagArray []string
-	if s.config.runGoTests {
-		extraSharedFlagArray = append(extraSharedFlagArray, "-t")
-	}
-	if s.config.moduleListFile != "" {
-		extraSharedFlagArray = append(extraSharedFlagArray, "-l", s.config.moduleListFile)
-	}
-	if s.config.emptyNinjaFile {
-		extraSharedFlagArray = append(extraSharedFlagArray, "--empty-ninja-file")
-	}
-	extraSharedFlagString := strings.Join(extraSharedFlagArray, " ")
+	var primaryBuilderCmdlinePrefix []string
+	var primaryBuilderName string
 
-	var primaryBuilderName, primaryBuilderExtraFlags string
-	switch len(primaryBuilders) {
-	case 0:
+	if len(primaryBuilders) == 0 {
 		// If there's no primary builder module then that means we'll use minibp
 		// as the primary builder.  We can trigger its primary builder mode with
 		// the -p flag.
 		primaryBuilderName = "minibp"
-		primaryBuilderExtraFlags = "-p " + extraSharedFlagString
-
-	case 1:
-		primaryBuilderName = ctx.ModuleName(primaryBuilders[0])
-		primaryBuilderExtraFlags = extraSharedFlagString
-
-	default:
+		primaryBuilderCmdlinePrefix = append(primaryBuilderCmdlinePrefix, "-p")
+	} else if len(primaryBuilders) > 1 {
 		ctx.Errorf("multiple primary builder modules present:")
 		for _, primaryBuilder := range primaryBuilders {
 			ctx.ModuleErrorf(primaryBuilder, "<-- module %s",
 				ctx.ModuleName(primaryBuilder))
 		}
 		return
+	} else {
+		primaryBuilderName = ctx.ModuleName(primaryBuilders[0])
 	}
 
 	primaryBuilderFile := filepath.Join("$BinDir", primaryBuilderName)
-
-	// Get the filename of the top-level Blueprints file to pass to minibp.
-	topLevelBlueprints := filepath.Join("$srcDir",
-		filepath.Base(s.config.topLevelBlueprintsFile))
 	ctx.SetNinjaBuildDir(pctx, "${ninjaBuildDir}")
 
-	buildDir := ctx.Config().(BootstrapConfig).BuildDir()
-
 	if s.config.stage == StagePrimary {
-		mainNinjaFile := filepath.Join("$buildDir", "build.ninja")
-		primaryBuilderNinjaGlobFile := absolutePath(filepath.Join(buildDir, bootstrapSubDir, "build-globs.ninja"))
+		ctx.AddSubninja(s.config.globFile)
 
-		if _, err := os.Stat(primaryBuilderNinjaGlobFile); os.IsNotExist(err) {
-			err = ioutil.WriteFile(primaryBuilderNinjaGlobFile, nil, 0666)
-			if err != nil {
-				ctx.Errorf("Failed to create empty ninja file: %s", err)
-			}
+		for _, i := range s.config.primaryBuilderInvocations {
+			flags := make([]string, 0)
+			flags = append(flags, primaryBuilderCmdlinePrefix...)
+			flags = append(flags, i.Args...)
+
+			// Build the main build.ninja
+			ctx.Build(pctx, blueprint.BuildParams{
+				Rule:    generateBuildNinja,
+				Outputs: i.Outputs,
+				Inputs:  i.Inputs,
+				Args: map[string]string{
+					"builder": primaryBuilderFile,
+					"extra":   strings.Join(flags, " "),
+				},
+			})
 		}
-
-		ctx.AddSubninja(primaryBuilderNinjaGlobFile)
-
-		// Build the main build.ninja
-		ctx.Build(pctx, blueprint.BuildParams{
-			Rule:    generateBuildNinja,
-			Outputs: []string{mainNinjaFile},
-			Inputs:  []string{topLevelBlueprints},
-			Args: map[string]string{
-				"builder":  primaryBuilderFile,
-				"extra":    primaryBuilderExtraFlags,
-				"globFile": primaryBuilderNinjaGlobFile,
-			},
-		})
 	}
 
 	if s.config.stage == StageMain {
@@ -798,7 +765,7 @@
 		bigbpDocs := ctx.Rule(pctx, "bigbpDocs",
 			blueprint.RuleParams{
 				Command: fmt.Sprintf("%s %s -b $buildDir --docs $out %s", primaryBuilderFile,
-					primaryBuilderExtraFlags, topLevelBlueprints),
+					primaryBuilderExtraFlags, s.config.topLevelBlueprintsFile),
 				CommandDeps: []string{primaryBuilderFile},
 				Description: fmt.Sprintf("%s docs $out", primaryBuilderName),
 			})
diff --git a/bootstrap/command.go b/bootstrap/command.go
index cd13c4f..548a2ea 100644
--- a/bootstrap/command.go
+++ b/bootstrap/command.go
@@ -38,6 +38,8 @@
 	DocFile                  string
 	Cpuprofile               string
 	Memprofile               string
+	DelveListen              string
+	DelvePath                string
 	TraceFile                string
 	RunGoTests               bool
 	UseValidations           bool
@@ -104,6 +106,46 @@
 	RunBlueprint(cmdline, ctx, config, extraNinjaFileDeps...)
 }
 
+func primaryBuilderExtraFlags(args Args, globFile, mainNinjaFile string) []string {
+	result := make([]string, 0)
+
+	if args.RunGoTests {
+		result = append(result, "-t")
+	}
+
+	result = append(result, "-l", args.ModuleListFile)
+	result = append(result, "-globFile", globFile)
+	result = append(result, "-o", mainNinjaFile)
+
+	if args.EmptyNinjaFile {
+		result = append(result, "--empty-ninja-file")
+	}
+
+	if args.DelveListen != "" {
+		result = append(result, "--delve_listen", args.DelveListen)
+	}
+
+	if args.DelvePath != "" {
+		result = append(result, "--delve_path", args.DelvePath)
+	}
+
+	result = append(result, args.TopFile)
+	return result
+}
+
+func writeEmptyGlobFile(path string) {
+	err := os.MkdirAll(filepath.Dir(path), 0777)
+	if err != nil {
+		fatalf("Failed to create parent directories of empty ninja glob file '%s': %s", path, err)
+	}
+
+	if _, err := os.Stat(path); os.IsNotExist(err) {
+		err = ioutil.WriteFile(path, nil, 0666)
+		if err != nil {
+			fatalf("Failed to create empty ninja glob file '%s': %s", path, err)
+		}
+	}
+}
 func RunBlueprint(args Args, ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) {
 	runtime.GOMAXPROCS(runtime.NumCPU())
 
@@ -153,14 +195,25 @@
 		stage = StagePrimary
 	}
 
+	primaryBuilderNinjaGlobFile := absolutePath(filepath.Join(args.BuildDir, bootstrapSubDir, "build-globs.ninja"))
+	mainNinjaFile := filepath.Join("$buildDir", "build.ninja")
+
+	writeEmptyGlobFile(primaryBuilderNinjaGlobFile)
+
 	bootstrapConfig := &Config{
 		stage: stage,
 
 		topLevelBlueprintsFile: args.TopFile,
-		emptyNinjaFile:         args.EmptyNinjaFile,
+		globFile:               primaryBuilderNinjaGlobFile,
 		runGoTests:             args.RunGoTests,
 		useValidations:         args.UseValidations,
-		moduleListFile:         args.ModuleListFile,
+		primaryBuilderInvocations: []PrimaryBuilderInvocation{
+			{
+				Inputs:  []string{args.TopFile},
+				Outputs: []string{mainNinjaFile},
+				Args:    primaryBuilderExtraFlags(args, primaryBuilderNinjaGlobFile, mainNinjaFile),
+			},
+		},
 	}
 
 	ctx.RegisterBottomUpMutator("bootstrap_plugin_deps", pluginDeps)
@@ -171,7 +224,7 @@
 
 	ctx.RegisterSingletonType("glob", globSingletonFactory(ctx))
 
-	deps, errs := ctx.ParseFileList(filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), filesToParse, config)
+	deps, errs := ctx.ParseFileList(filepath.Dir(args.TopFile), filesToParse, config)
 	if len(errs) > 0 {
 		fatalErrors(errs)
 	}
diff --git a/bootstrap/config.go b/bootstrap/config.go
index 6be0111..a29ba76 100644
--- a/bootstrap/config.go
+++ b/bootstrap/config.go
@@ -123,13 +123,20 @@
 	StageMain
 )
 
+type PrimaryBuilderInvocation struct {
+	Inputs  []string
+	Outputs []string
+	Args    []string
+}
+
 type Config struct {
 	stage Stage
 
 	topLevelBlueprintsFile string
+	globFile               string
 
-	emptyNinjaFile bool
 	runGoTests     bool
 	useValidations bool
-	moduleListFile string
+
+	primaryBuilderInvocations []PrimaryBuilderInvocation
 }