Pass pctx and ctx to NewRuleBuilder

Enable the RuleBuilder and RuleBuilderCommand methods to access
the BuilderContext by passing it to NewRuleBuilder instead of
RuleBuilder.Build.

Test: genrule_test.go
Test: rule_builder_test.go
Test: m checkbuild
Change-Id: I63e6597e19167393876dc2259d6f521363b7dabc
This commit is contained in:
Colin Cross
2020-11-16 17:32:30 -08:00
parent 33e1763094
commit f1a035e6be
39 changed files with 348 additions and 314 deletions

View File

@@ -37,6 +37,9 @@ const sboxOutDir = sboxSandboxBaseDir + "/" + sboxOutSubDir
// RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
// graph.
type RuleBuilder struct {
pctx PackageContext
ctx BuilderContext
commands []*RuleBuilderCommand
installs RuleBuilderInstalls
temporariesSet map[WritablePath]bool
@@ -44,14 +47,16 @@ type RuleBuilder struct {
sbox bool
highmem bool
remoteable RemoteRuleSupports
sboxOutDir WritablePath
outDir WritablePath
sboxManifestPath WritablePath
missingDeps []string
}
// NewRuleBuilder returns a newly created RuleBuilder.
func NewRuleBuilder() *RuleBuilder {
func NewRuleBuilder(pctx PackageContext, ctx BuilderContext) *RuleBuilder {
return &RuleBuilder{
pctx: pctx,
ctx: ctx,
temporariesSet: make(map[WritablePath]bool),
}
}
@@ -130,7 +135,7 @@ func (r *RuleBuilder) Sbox(outputDir WritablePath, manifestPath WritablePath) *R
panic("Sbox() is not compatible with Restat()")
}
r.sbox = true
r.sboxOutDir = outputDir
r.outDir = outputDir
r.sboxManifestPath = manifestPath
return r
}
@@ -146,8 +151,7 @@ func (r *RuleBuilder) Install(from Path, to string) {
// race with any call to Build.
func (r *RuleBuilder) Command() *RuleBuilderCommand {
command := &RuleBuilderCommand{
sbox: r.sbox,
outDir: r.sboxOutDir,
rule: r,
}
r.commands = append(r.commands, command)
return command
@@ -395,19 +399,19 @@ type BuilderContext interface {
var _ BuilderContext = ModuleContext(nil)
var _ BuilderContext = SingletonContext(nil)
func (r *RuleBuilder) depFileMergerCmd(ctx PathContext, depFiles WritablePaths) *RuleBuilderCommand {
func (r *RuleBuilder) depFileMergerCmd(depFiles WritablePaths) *RuleBuilderCommand {
return r.Command().
BuiltTool(ctx, "dep_fixer").
BuiltTool("dep_fixer").
Inputs(depFiles.Paths())
}
// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
// Outputs.
func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string, desc string) {
func (r *RuleBuilder) Build(name string, desc string) {
name = ninjaNameEscape(name)
if len(r.missingDeps) > 0 {
ctx.Build(pctx, BuildParams{
r.ctx.Build(pctx, BuildParams{
Rule: ErrorRule,
Outputs: r.Outputs(),
OrderOnly: r.OrderOnlys(),
@@ -426,13 +430,13 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
depFormat = blueprint.DepsGCC
if len(depFiles) > 1 {
// Add a command locally that merges all depfiles together into the first depfile.
r.depFileMergerCmd(ctx, depFiles)
r.depFileMergerCmd(depFiles)
if r.sbox {
// Check for Rel() errors, as all depfiles should be in the output dir. Errors
// will be reported to the ctx.
for _, path := range depFiles[1:] {
Rel(ctx, r.sboxOutDir.String(), path.String())
Rel(r.ctx, r.outDir.String(), path.String())
}
}
}
@@ -468,7 +472,7 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
// to the output directory.
sboxOutputs := make([]string, len(outputs))
for i, output := range outputs {
rel := Rel(ctx, r.sboxOutDir.String(), output.String())
rel := Rel(r.ctx, r.outDir.String(), output.String())
sboxOutputs[i] = filepath.Join(sboxOutDir, rel)
command.CopyAfter = append(command.CopyAfter, &sbox_proto.Copy{
From: proto.String(filepath.Join(sboxOutSubDir, rel)),
@@ -483,23 +487,27 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
// Verify that the manifest textproto is not inside the sbox output directory, otherwise
// it will get deleted when the sbox rule clears its output directory.
_, manifestInOutDir := MaybeRel(ctx, r.sboxOutDir.String(), r.sboxManifestPath.String())
_, manifestInOutDir := MaybeRel(r.ctx, r.outDir.String(), r.sboxManifestPath.String())
if manifestInOutDir {
ReportPathErrorf(ctx, "sbox rule %q manifestPath %q must not be in outputDir %q",
name, r.sboxManifestPath.String(), r.sboxOutDir.String())
ReportPathErrorf(r.ctx, "sbox rule %q manifestPath %q must not be in outputDir %q",
name, r.sboxManifestPath.String(), r.outDir.String())
}
// Create a rule to write the manifest as a the textproto.
WriteFileRule(ctx, r.sboxManifestPath, proto.MarshalTextString(&manifest))
WriteFileRule(r.ctx, r.sboxManifestPath, proto.MarshalTextString(&manifest))
// Generate a new string to use as the command line of the sbox rule. This uses
// a RuleBuilderCommand as a convenience method of building the command line, then
// converts it to a string to replace commandString.
sboxCmd := &RuleBuilderCommand{}
sboxCmd.Text("rm -rf").Output(r.sboxOutDir)
sboxCmd := &RuleBuilderCommand{
rule: &RuleBuilder{
ctx: r.ctx,
},
}
sboxCmd.Text("rm -rf").Output(r.outDir)
sboxCmd.Text("&&")
sboxCmd.BuiltTool(ctx, "sbox").
Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(ctx).String())).
sboxCmd.BuiltTool("sbox").
Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(r.ctx).String())).
Flag("--manifest").Input(r.sboxManifestPath)
// Replace the command string, and add the sbox tool and manifest textproto to the
@@ -528,19 +536,19 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
}
var pool blueprint.Pool
if ctx.Config().UseGoma() && r.remoteable.Goma {
if r.ctx.Config().UseGoma() && r.remoteable.Goma {
// When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool.
} else if ctx.Config().UseRBE() && r.remoteable.RBE {
} else if r.ctx.Config().UseRBE() && r.remoteable.RBE {
// When USE_RBE=true is set and the rule is supported by RBE, use the remotePool.
pool = remotePool
} else if r.highmem {
pool = highmemPool
} else if ctx.Config().UseRemoteBuild() {
} else if r.ctx.Config().UseRemoteBuild() {
pool = localPool
}
ctx.Build(pctx, BuildParams{
Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
r.ctx.Build(r.pctx, BuildParams{
Rule: r.ctx.Rule(pctx, name, blueprint.RuleParams{
Command: commandString,
CommandDeps: tools.Strings(),
Restat: r.restat,
@@ -564,6 +572,8 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
// RuleBuilderCommand, so they can be used chained or unchained. All methods that add text implicitly add a single
// space as a separator from the previous method.
type RuleBuilderCommand struct {
rule *RuleBuilder
buf strings.Builder
inputs Paths
implicits Paths
@@ -576,16 +586,11 @@ type RuleBuilderCommand struct {
// spans [start,end) of the command that should not be ninja escaped
unescapedSpans [][2]int
sbox bool
// outDir is the directory that will contain the output files of the rules. sbox will copy
// the output files from the sandbox directory to this directory when it finishes.
outDir WritablePath
}
func (c *RuleBuilderCommand) addInput(path Path) string {
if c.sbox {
if rel, isRel, _ := maybeRelErr(c.outDir.String(), path.String()); isRel {
if c.rule.sbox {
if rel, isRel, _ := maybeRelErr(c.rule.outDir.String(), path.String()); isRel {
return filepath.Join(sboxOutDir, rel)
}
}
@@ -594,8 +599,8 @@ func (c *RuleBuilderCommand) addInput(path Path) string {
}
func (c *RuleBuilderCommand) addImplicit(path Path) string {
if c.sbox {
if rel, isRel, _ := maybeRelErr(c.outDir.String(), path.String()); isRel {
if c.rule.sbox {
if rel, isRel, _ := maybeRelErr(c.rule.outDir.String(), path.String()); isRel {
return filepath.Join(sboxOutDir, rel)
}
}
@@ -607,22 +612,19 @@ func (c *RuleBuilderCommand) addOrderOnly(path Path) {
c.orderOnlys = append(c.orderOnlys, path)
}
func (c *RuleBuilderCommand) outputStr(path WritablePath) string {
if c.sbox {
return SboxPathForOutput(path, c.outDir)
// PathForOutput takes an output path and returns the appropriate path to use on the command
// line. If sbox was enabled via a call to RuleBuilder.Sbox(), it returns a path with the
// placeholder prefix used for outputs in sbox. If sbox is not enabled it returns the
// original path.
func (c *RuleBuilderCommand) PathForOutput(path WritablePath) string {
if c.rule.sbox {
// Errors will be handled in RuleBuilder.Build where we have a context to report them
rel, _, _ := maybeRelErr(c.rule.outDir.String(), path.String())
return filepath.Join(sboxOutDir, rel)
}
return path.String()
}
// SboxPathForOutput takes an output path and the out directory passed to RuleBuilder.Sbox(),
// and returns the corresponding path for the output in the sbox sandbox. This can be used
// on the RuleBuilder command line to reference the output.
func SboxPathForOutput(path WritablePath, outDir WritablePath) string {
// Errors will be handled in RuleBuilder.Build where we have a context to report them
rel, _, _ := maybeRelErr(outDir.String(), path.String())
return filepath.Join(sboxOutDir, rel)
}
// Text adds the specified raw text to the command line. The text should not contain input or output paths or the
// rule will not have them listed in its dependencies or outputs.
func (c *RuleBuilderCommand) Text(text string) *RuleBuilderCommand {
@@ -699,8 +701,8 @@ func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand {
//
// It is equivalent to:
// cmd.Tool(ctx.Config().HostToolPath(ctx, tool))
func (c *RuleBuilderCommand) BuiltTool(ctx PathContext, tool string) *RuleBuilderCommand {
return c.Tool(ctx.Config().HostToolPath(ctx, tool))
func (c *RuleBuilderCommand) BuiltTool(tool string) *RuleBuilderCommand {
return c.Tool(c.rule.ctx.Config().HostToolPath(c.rule.ctx, tool))
}
// PrebuiltBuildTool adds the specified tool path from prebuils/build-tools. The path will be also added to the
@@ -768,7 +770,7 @@ func (c *RuleBuilderCommand) OrderOnlys(paths Paths) *RuleBuilderCommand {
// RuleBuilder.Outputs.
func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
c.outputs = append(c.outputs, path)
return c.Text(c.outputStr(path))
return c.Text(c.PathForOutput(path))
}
// Outputs adds the specified output paths to the command line, separated by spaces. The paths will also be added to
@@ -783,7 +785,7 @@ func (c *RuleBuilderCommand) Outputs(paths WritablePaths) *RuleBuilderCommand {
// OutputDir adds the output directory to the command line. This is only available when used with RuleBuilder.Sbox,
// and will be the temporary output directory managed by sbox, not the final one.
func (c *RuleBuilderCommand) OutputDir() *RuleBuilderCommand {
if !c.sbox {
if !c.rule.sbox {
panic("OutputDir only valid with Sbox")
}
return c.Text(sboxOutDir)
@@ -794,7 +796,7 @@ func (c *RuleBuilderCommand) OutputDir() *RuleBuilderCommand {
// commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
c.depFiles = append(c.depFiles, path)
return c.Text(c.outputStr(path))
return c.Text(c.PathForOutput(path))
}
// ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
@@ -885,14 +887,14 @@ func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths Paths) *RuleBui
// will also be added to the outputs returned by RuleBuilder.Outputs.
func (c *RuleBuilderCommand) FlagWithOutput(flag string, path WritablePath) *RuleBuilderCommand {
c.outputs = append(c.outputs, path)
return c.Text(flag + c.outputStr(path))
return c.Text(flag + c.PathForOutput(path))
}
// FlagWithDepFile adds the specified flag and depfile path to the command line, with no separator between them. The path
// will also be added to the outputs returned by RuleBuilder.Outputs.
func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *RuleBuilderCommand {
c.depFiles = append(c.depFiles, path)
return c.Text(flag + c.outputStr(path))
return c.Text(flag + c.PathForOutput(path))
}
// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with no separator
@@ -987,3 +989,21 @@ func hashSrcFiles(srcFiles Paths) string {
h.Write([]byte(srcFileList))
return fmt.Sprintf("%x", h.Sum(nil))
}
// BuilderContextForTesting returns a BuilderContext for the given config that can be used for tests
// that need to call methods that take a BuilderContext.
func BuilderContextForTesting(config Config) BuilderContext {
pathCtx := PathContextForTesting(config)
return builderContextForTests{
PathContext: pathCtx,
}
}
type builderContextForTests struct {
PathContext
}
func (builderContextForTests) Rule(PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule {
return nil
}
func (builderContextForTests) Build(PackageContext, BuildParams) {}