blob: 2507c4c83d52e452e36f65672b5640d050d36c98 [file] [log] [blame]
Colin Crossfeec25b2019-01-30 17:32:39 -08001// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
Colin Cross3d680512020-11-13 16:23:53 -080018 "crypto/sha256"
Colin Crossfeec25b2019-01-30 17:32:39 -080019 "fmt"
Colin Cross3d680512020-11-13 16:23:53 -080020 "path/filepath"
Colin Crossfeec25b2019-01-30 17:32:39 -080021 "sort"
22 "strings"
Colin Crosse16ce362020-11-12 08:29:30 -080023 "testing"
Colin Crossfeec25b2019-01-30 17:32:39 -080024
Colin Crosse16ce362020-11-12 08:29:30 -080025 "github.com/golang/protobuf/proto"
Colin Crossfeec25b2019-01-30 17:32:39 -080026 "github.com/google/blueprint"
27 "github.com/google/blueprint/proptools"
Dan Willemsen633c5022019-04-12 11:11:38 -070028
Colin Crosse16ce362020-11-12 08:29:30 -080029 "android/soong/cmd/sbox/sbox_proto"
Colin Crossef972742021-03-12 17:24:45 -080030 "android/soong/remoteexec"
Colin Crosse55bd422021-03-23 13:44:30 -070031 "android/soong/response"
Dan Willemsen633c5022019-04-12 11:11:38 -070032 "android/soong/shared"
Colin Crossfeec25b2019-01-30 17:32:39 -080033)
34
Colin Crosse16ce362020-11-12 08:29:30 -080035const sboxSandboxBaseDir = "__SBOX_SANDBOX_DIR__"
36const sboxOutSubDir = "out"
Colin Crossba9e4032020-11-24 16:32:22 -080037const sboxToolsSubDir = "tools"
Colin Crosse16ce362020-11-12 08:29:30 -080038const sboxOutDir = sboxSandboxBaseDir + "/" + sboxOutSubDir
Colin Cross3d680512020-11-13 16:23:53 -080039
Colin Cross758290d2019-02-01 16:42:32 -080040// RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
41// graph.
Colin Crossfeec25b2019-01-30 17:32:39 -080042type RuleBuilder struct {
Colin Crossf1a035e2020-11-16 17:32:30 -080043 pctx PackageContext
44 ctx BuilderContext
45
Colin Crosse16ce362020-11-12 08:29:30 -080046 commands []*RuleBuilderCommand
47 installs RuleBuilderInstalls
48 temporariesSet map[WritablePath]bool
49 restat bool
50 sbox bool
51 highmem bool
52 remoteable RemoteRuleSupports
Colin Crossef972742021-03-12 17:24:45 -080053 rbeParams *remoteexec.REParams
Colin Crossf1a035e2020-11-16 17:32:30 -080054 outDir WritablePath
Colin Crossba9e4032020-11-24 16:32:22 -080055 sboxTools bool
Colin Crossab020a72021-03-12 17:52:23 -080056 sboxInputs bool
Colin Crosse16ce362020-11-12 08:29:30 -080057 sboxManifestPath WritablePath
58 missingDeps []string
Colin Crossfeec25b2019-01-30 17:32:39 -080059}
60
Colin Cross758290d2019-02-01 16:42:32 -080061// NewRuleBuilder returns a newly created RuleBuilder.
Colin Crossf1a035e2020-11-16 17:32:30 -080062func NewRuleBuilder(pctx PackageContext, ctx BuilderContext) *RuleBuilder {
Colin Cross5cb5b092019-02-02 21:25:18 -080063 return &RuleBuilder{
Colin Crossf1a035e2020-11-16 17:32:30 -080064 pctx: pctx,
65 ctx: ctx,
Colin Cross69f59a32019-02-15 10:39:37 -080066 temporariesSet: make(map[WritablePath]bool),
Colin Cross5cb5b092019-02-02 21:25:18 -080067 }
Colin Cross758290d2019-02-01 16:42:32 -080068}
69
70// RuleBuilderInstall is a tuple of install from and to locations.
71type RuleBuilderInstall struct {
Colin Cross69f59a32019-02-15 10:39:37 -080072 From Path
73 To string
Colin Cross758290d2019-02-01 16:42:32 -080074}
75
Colin Crossdeabb942019-02-11 14:11:09 -080076type RuleBuilderInstalls []RuleBuilderInstall
77
78// String returns the RuleBuilderInstalls in the form used by $(call copy-many-files) in Make, a space separated
79// list of from:to tuples.
80func (installs RuleBuilderInstalls) String() string {
81 sb := strings.Builder{}
82 for i, install := range installs {
83 if i != 0 {
84 sb.WriteRune(' ')
85 }
Colin Cross69f59a32019-02-15 10:39:37 -080086 sb.WriteString(install.From.String())
Colin Crossdeabb942019-02-11 14:11:09 -080087 sb.WriteRune(':')
88 sb.WriteString(install.To)
89 }
90 return sb.String()
91}
92
Colin Cross0d2f40a2019-02-05 22:31:15 -080093// MissingDeps adds modules to the list of missing dependencies. If MissingDeps
94// is called with a non-empty input, any call to Build will result in a rule
95// that will print an error listing the missing dependencies and fail.
96// MissingDeps should only be called if Config.AllowMissingDependencies() is
97// true.
98func (r *RuleBuilder) MissingDeps(missingDeps []string) {
99 r.missingDeps = append(r.missingDeps, missingDeps...)
100}
101
Colin Cross758290d2019-02-01 16:42:32 -0800102// Restat marks the rule as a restat rule, which will be passed to ModuleContext.Rule in BuildParams.Restat.
Dan Willemsen633c5022019-04-12 11:11:38 -0700103//
104// Restat is not compatible with Sbox()
Colin Crossfeec25b2019-01-30 17:32:39 -0800105func (r *RuleBuilder) Restat() *RuleBuilder {
Dan Willemsen633c5022019-04-12 11:11:38 -0700106 if r.sbox {
107 panic("Restat() is not compatible with Sbox()")
108 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800109 r.restat = true
110 return r
111}
112
Colin Cross8b8bec32019-11-15 13:18:43 -0800113// HighMem marks the rule as a high memory rule, which will limit how many run in parallel with other high memory
114// rules.
115func (r *RuleBuilder) HighMem() *RuleBuilder {
116 r.highmem = true
117 return r
118}
119
120// Remoteable marks the rule as supporting remote execution.
121func (r *RuleBuilder) Remoteable(supports RemoteRuleSupports) *RuleBuilder {
122 r.remoteable = supports
123 return r
124}
125
Colin Crossef972742021-03-12 17:24:45 -0800126// Rewrapper marks the rule as running inside rewrapper using the given params in order to support
127// running on RBE. During RuleBuilder.Build the params will be combined with the inputs, outputs
128// and tools known to RuleBuilder to prepend an appropriate rewrapper command line to the rule's
129// command line.
130func (r *RuleBuilder) Rewrapper(params *remoteexec.REParams) *RuleBuilder {
131 if !r.sboxInputs {
132 panic(fmt.Errorf("RuleBuilder.Rewrapper must be called after RuleBuilder.SandboxInputs"))
133 }
134 r.rbeParams = params
135 return r
136}
137
Colin Crosse16ce362020-11-12 08:29:30 -0800138// Sbox marks the rule as needing to be wrapped by sbox. The outputDir should point to the output
139// directory that sbox will wipe. It should not be written to by any other rule. manifestPath should
140// point to a location where sbox's manifest will be written and must be outside outputDir. sbox
141// will ensure that all outputs have been written, and will discard any output files that were not
142// specified.
Dan Willemsen633c5022019-04-12 11:11:38 -0700143//
144// Sbox is not compatible with Restat()
Colin Crosse16ce362020-11-12 08:29:30 -0800145func (r *RuleBuilder) Sbox(outputDir WritablePath, manifestPath WritablePath) *RuleBuilder {
Dan Willemsen633c5022019-04-12 11:11:38 -0700146 if r.sbox {
147 panic("Sbox() may not be called more than once")
148 }
149 if len(r.commands) > 0 {
150 panic("Sbox() may not be called after Command()")
151 }
152 if r.restat {
153 panic("Sbox() is not compatible with Restat()")
154 }
155 r.sbox = true
Colin Crossf1a035e2020-11-16 17:32:30 -0800156 r.outDir = outputDir
Colin Crosse16ce362020-11-12 08:29:30 -0800157 r.sboxManifestPath = manifestPath
Dan Willemsen633c5022019-04-12 11:11:38 -0700158 return r
159}
160
Colin Crossba9e4032020-11-24 16:32:22 -0800161// SandboxTools enables tool sandboxing for the rule by copying any referenced tools into the
162// sandbox.
163func (r *RuleBuilder) SandboxTools() *RuleBuilder {
164 if !r.sbox {
165 panic("SandboxTools() must be called after Sbox()")
166 }
167 if len(r.commands) > 0 {
168 panic("SandboxTools() may not be called after Command()")
169 }
170 r.sboxTools = true
171 return r
172}
173
Colin Crossab020a72021-03-12 17:52:23 -0800174// SandboxInputs enables input sandboxing for the rule by copying any referenced inputs into the
175// sandbox. It also implies SandboxTools().
176//
177// Sandboxing inputs requires RuleBuilder to be aware of all references to input paths. Paths
178// that are passed to RuleBuilder outside of the methods that expect inputs, for example
179// FlagWithArg, must use RuleBuilderCommand.PathForInput to translate the path to one that matches
180// the sandbox layout.
181func (r *RuleBuilder) SandboxInputs() *RuleBuilder {
182 if !r.sbox {
183 panic("SandboxInputs() must be called after Sbox()")
184 }
185 if len(r.commands) > 0 {
186 panic("SandboxInputs() may not be called after Command()")
187 }
188 r.sboxTools = true
189 r.sboxInputs = true
190 return r
191}
192
Colin Cross758290d2019-02-01 16:42:32 -0800193// Install associates an output of the rule with an install location, which can be retrieved later using
194// RuleBuilder.Installs.
Colin Cross69f59a32019-02-15 10:39:37 -0800195func (r *RuleBuilder) Install(from Path, to string) {
Colin Crossfeec25b2019-01-30 17:32:39 -0800196 r.installs = append(r.installs, RuleBuilderInstall{from, to})
197}
198
Colin Cross758290d2019-02-01 16:42:32 -0800199// Command returns a new RuleBuilderCommand for the rule. The commands will be ordered in the rule by when they were
200// created by this method. That can be mutated through their methods in any order, as long as the mutations do not
201// race with any call to Build.
Colin Crossfeec25b2019-01-30 17:32:39 -0800202func (r *RuleBuilder) Command() *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -0700203 command := &RuleBuilderCommand{
Colin Crossf1a035e2020-11-16 17:32:30 -0800204 rule: r,
Dan Willemsen633c5022019-04-12 11:11:38 -0700205 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800206 r.commands = append(r.commands, command)
207 return command
208}
209
Colin Cross5cb5b092019-02-02 21:25:18 -0800210// Temporary marks an output of a command as an intermediate file that will be used as an input to another command
211// in the same rule, and should not be listed in Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -0800212func (r *RuleBuilder) Temporary(path WritablePath) {
Colin Cross5cb5b092019-02-02 21:25:18 -0800213 r.temporariesSet[path] = true
214}
215
216// DeleteTemporaryFiles adds a command to the rule that deletes any outputs that have been marked using Temporary
217// when the rule runs. DeleteTemporaryFiles should be called after all calls to Temporary.
218func (r *RuleBuilder) DeleteTemporaryFiles() {
Colin Cross69f59a32019-02-15 10:39:37 -0800219 var temporariesList WritablePaths
Colin Cross5cb5b092019-02-02 21:25:18 -0800220
221 for intermediate := range r.temporariesSet {
222 temporariesList = append(temporariesList, intermediate)
223 }
Colin Cross69f59a32019-02-15 10:39:37 -0800224
225 sort.Slice(temporariesList, func(i, j int) bool {
226 return temporariesList[i].String() < temporariesList[j].String()
227 })
Colin Cross5cb5b092019-02-02 21:25:18 -0800228
229 r.Command().Text("rm").Flag("-f").Outputs(temporariesList)
230}
231
Colin Crossda71eda2020-02-21 16:55:19 -0800232// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
Colin Cross3d680512020-11-13 16:23:53 -0800233// input paths, such as RuleBuilderCommand.Input, RuleBuilderCommand.Implicit, or
Colin Crossda71eda2020-02-21 16:55:19 -0800234// RuleBuilderCommand.FlagWithInput. Inputs to a command that are also outputs of another command
235// in the same RuleBuilder are filtered out. The list is sorted and duplicates removed.
Colin Cross69f59a32019-02-15 10:39:37 -0800236func (r *RuleBuilder) Inputs() Paths {
Colin Crossfeec25b2019-01-30 17:32:39 -0800237 outputs := r.outputSet()
Dan Willemsen633c5022019-04-12 11:11:38 -0700238 depFiles := r.depFileSet()
Colin Crossfeec25b2019-01-30 17:32:39 -0800239
Colin Cross69f59a32019-02-15 10:39:37 -0800240 inputs := make(map[string]Path)
Colin Crossfeec25b2019-01-30 17:32:39 -0800241 for _, c := range r.commands {
Ramy Medhat2f99eec2020-06-13 17:38:27 -0400242 for _, input := range append(c.inputs, c.implicits...) {
Dan Willemsen633c5022019-04-12 11:11:38 -0700243 inputStr := input.String()
244 if _, isOutput := outputs[inputStr]; !isOutput {
245 if _, isDepFile := depFiles[inputStr]; !isDepFile {
246 inputs[input.String()] = input
247 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800248 }
249 }
250 }
251
Colin Cross69f59a32019-02-15 10:39:37 -0800252 var inputList Paths
253 for _, input := range inputs {
Colin Crossfeec25b2019-01-30 17:32:39 -0800254 inputList = append(inputList, input)
255 }
Colin Cross69f59a32019-02-15 10:39:37 -0800256
257 sort.Slice(inputList, func(i, j int) bool {
258 return inputList[i].String() < inputList[j].String()
259 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800260
261 return inputList
262}
263
Colin Crossda71eda2020-02-21 16:55:19 -0800264// OrderOnlys returns the list of paths that were passed to the RuleBuilderCommand.OrderOnly or
265// RuleBuilderCommand.OrderOnlys. The list is sorted and duplicates removed.
266func (r *RuleBuilder) OrderOnlys() Paths {
267 orderOnlys := make(map[string]Path)
268 for _, c := range r.commands {
269 for _, orderOnly := range c.orderOnlys {
270 orderOnlys[orderOnly.String()] = orderOnly
271 }
272 }
273
274 var orderOnlyList Paths
275 for _, orderOnly := range orderOnlys {
276 orderOnlyList = append(orderOnlyList, orderOnly)
277 }
278
279 sort.Slice(orderOnlyList, func(i, j int) bool {
280 return orderOnlyList[i].String() < orderOnlyList[j].String()
281 })
282
283 return orderOnlyList
284}
285
Colin Crossae89abe2021-04-21 11:45:23 -0700286// Validations returns the list of paths that were passed to RuleBuilderCommand.Validation or
287// RuleBuilderCommand.Validations. The list is sorted and duplicates removed.
288func (r *RuleBuilder) Validations() Paths {
289 validations := make(map[string]Path)
290 for _, c := range r.commands {
291 for _, validation := range c.validations {
292 validations[validation.String()] = validation
293 }
294 }
295
296 var validationList Paths
297 for _, validation := range validations {
298 validationList = append(validationList, validation)
299 }
300
301 sort.Slice(validationList, func(i, j int) bool {
302 return validationList[i].String() < validationList[j].String()
303 })
304
305 return validationList
306}
307
Colin Cross69f59a32019-02-15 10:39:37 -0800308func (r *RuleBuilder) outputSet() map[string]WritablePath {
309 outputs := make(map[string]WritablePath)
Colin Crossfeec25b2019-01-30 17:32:39 -0800310 for _, c := range r.commands {
311 for _, output := range c.outputs {
Colin Cross69f59a32019-02-15 10:39:37 -0800312 outputs[output.String()] = output
Colin Crossfeec25b2019-01-30 17:32:39 -0800313 }
314 }
315 return outputs
316}
317
Colin Crossda71eda2020-02-21 16:55:19 -0800318// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
319// output paths, such as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or
320// RuleBuilderCommand.FlagWithInput. The list is sorted and duplicates removed.
Colin Cross69f59a32019-02-15 10:39:37 -0800321func (r *RuleBuilder) Outputs() WritablePaths {
Colin Crossfeec25b2019-01-30 17:32:39 -0800322 outputs := r.outputSet()
323
Colin Cross69f59a32019-02-15 10:39:37 -0800324 var outputList WritablePaths
325 for _, output := range outputs {
Colin Cross5cb5b092019-02-02 21:25:18 -0800326 if !r.temporariesSet[output] {
327 outputList = append(outputList, output)
328 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800329 }
Colin Cross69f59a32019-02-15 10:39:37 -0800330
331 sort.Slice(outputList, func(i, j int) bool {
332 return outputList[i].String() < outputList[j].String()
333 })
334
Colin Crossfeec25b2019-01-30 17:32:39 -0800335 return outputList
336}
337
Jingwen Chence679d22020-09-23 04:30:02 +0000338func (r *RuleBuilder) symlinkOutputSet() map[string]WritablePath {
339 symlinkOutputs := make(map[string]WritablePath)
340 for _, c := range r.commands {
341 for _, symlinkOutput := range c.symlinkOutputs {
342 symlinkOutputs[symlinkOutput.String()] = symlinkOutput
343 }
344 }
345 return symlinkOutputs
346}
347
348// SymlinkOutputs returns the list of paths that the executor (Ninja) would
349// verify, after build edge completion, that:
350//
351// 1) Created output symlinks match the list of paths in this list exactly (no more, no fewer)
352// 2) Created output files are *not* declared in this list.
353//
354// These symlink outputs are expected to be a subset of outputs or implicit
355// outputs, or they would fail validation at build param construction time
356// later, to support other non-rule-builder approaches for constructing
357// statements.
358func (r *RuleBuilder) SymlinkOutputs() WritablePaths {
359 symlinkOutputs := r.symlinkOutputSet()
360
361 var symlinkOutputList WritablePaths
362 for _, symlinkOutput := range symlinkOutputs {
363 symlinkOutputList = append(symlinkOutputList, symlinkOutput)
364 }
365
366 sort.Slice(symlinkOutputList, func(i, j int) bool {
367 return symlinkOutputList[i].String() < symlinkOutputList[j].String()
368 })
369
370 return symlinkOutputList
371}
372
Dan Willemsen633c5022019-04-12 11:11:38 -0700373func (r *RuleBuilder) depFileSet() map[string]WritablePath {
374 depFiles := make(map[string]WritablePath)
375 for _, c := range r.commands {
376 for _, depFile := range c.depFiles {
377 depFiles[depFile.String()] = depFile
378 }
379 }
380 return depFiles
381}
382
Colin Cross1d2cf042019-03-29 15:33:06 -0700383// DepFiles returns the list of paths that were passed to the RuleBuilderCommand methods that take depfile paths, such
384// as RuleBuilderCommand.DepFile or RuleBuilderCommand.FlagWithDepFile.
385func (r *RuleBuilder) DepFiles() WritablePaths {
386 var depFiles WritablePaths
387
388 for _, c := range r.commands {
389 for _, depFile := range c.depFiles {
390 depFiles = append(depFiles, depFile)
391 }
392 }
393
394 return depFiles
395}
396
Colin Cross758290d2019-02-01 16:42:32 -0800397// Installs returns the list of tuples passed to Install.
Colin Crossdeabb942019-02-11 14:11:09 -0800398func (r *RuleBuilder) Installs() RuleBuilderInstalls {
399 return append(RuleBuilderInstalls(nil), r.installs...)
Colin Crossfeec25b2019-01-30 17:32:39 -0800400}
401
Colin Cross69f59a32019-02-15 10:39:37 -0800402func (r *RuleBuilder) toolsSet() map[string]Path {
403 tools := make(map[string]Path)
Colin Cross5cb5b092019-02-02 21:25:18 -0800404 for _, c := range r.commands {
405 for _, tool := range c.tools {
Colin Cross69f59a32019-02-15 10:39:37 -0800406 tools[tool.String()] = tool
Colin Cross5cb5b092019-02-02 21:25:18 -0800407 }
408 }
409
410 return tools
411}
412
Colin Crossda71eda2020-02-21 16:55:19 -0800413// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method. The
414// list is sorted and duplicates removed.
Colin Cross69f59a32019-02-15 10:39:37 -0800415func (r *RuleBuilder) Tools() Paths {
Colin Cross5cb5b092019-02-02 21:25:18 -0800416 toolsSet := r.toolsSet()
417
Colin Cross69f59a32019-02-15 10:39:37 -0800418 var toolsList Paths
419 for _, tool := range toolsSet {
Colin Cross5cb5b092019-02-02 21:25:18 -0800420 toolsList = append(toolsList, tool)
Colin Crossfeec25b2019-01-30 17:32:39 -0800421 }
Colin Cross69f59a32019-02-15 10:39:37 -0800422
423 sort.Slice(toolsList, func(i, j int) bool {
424 return toolsList[i].String() < toolsList[j].String()
425 })
426
Colin Cross5cb5b092019-02-02 21:25:18 -0800427 return toolsList
Colin Crossfeec25b2019-01-30 17:32:39 -0800428}
429
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700430// RspFileInputs returns the list of paths that were passed to the RuleBuilderCommand.FlagWithRspFileInputList method.
431func (r *RuleBuilder) RspFileInputs() Paths {
432 var rspFileInputs Paths
433 for _, c := range r.commands {
Colin Crossce3a51d2021-03-19 16:22:12 -0700434 for _, rspFile := range c.rspFiles {
435 rspFileInputs = append(rspFileInputs, rspFile.paths...)
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700436 }
437 }
438
439 return rspFileInputs
440}
441
Colin Crossce3a51d2021-03-19 16:22:12 -0700442func (r *RuleBuilder) rspFiles() []rspFileAndPaths {
443 var rspFiles []rspFileAndPaths
Colin Cross70c47412021-03-12 17:48:14 -0800444 for _, c := range r.commands {
Colin Crossce3a51d2021-03-19 16:22:12 -0700445 rspFiles = append(rspFiles, c.rspFiles...)
Colin Cross70c47412021-03-12 17:48:14 -0800446 }
447
Colin Crossce3a51d2021-03-19 16:22:12 -0700448 return rspFiles
Colin Cross70c47412021-03-12 17:48:14 -0800449}
450
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700451// Commands returns a slice containing the built command line for each call to RuleBuilder.Command.
Colin Crossfeec25b2019-01-30 17:32:39 -0800452func (r *RuleBuilder) Commands() []string {
453 var commands []string
454 for _, c := range r.commands {
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700455 commands = append(commands, c.String())
456 }
457 return commands
458}
459
Colin Cross758290d2019-02-01 16:42:32 -0800460// BuilderContext is a subset of ModuleContext and SingletonContext.
Colin Cross786cd6d2019-02-01 16:41:11 -0800461type BuilderContext interface {
462 PathContext
463 Rule(PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule
464 Build(PackageContext, BuildParams)
465}
466
Colin Cross758290d2019-02-01 16:42:32 -0800467var _ BuilderContext = ModuleContext(nil)
468var _ BuilderContext = SingletonContext(nil)
469
Colin Crossf1a035e2020-11-16 17:32:30 -0800470func (r *RuleBuilder) depFileMergerCmd(depFiles WritablePaths) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -0700471 return r.Command().
Colin Crossf1a035e2020-11-16 17:32:30 -0800472 BuiltTool("dep_fixer").
Dan Willemsen633c5022019-04-12 11:11:38 -0700473 Inputs(depFiles.Paths())
Colin Cross1d2cf042019-03-29 15:33:06 -0700474}
475
Colin Cross758290d2019-02-01 16:42:32 -0800476// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
477// Outputs.
Colin Crossf1a035e2020-11-16 17:32:30 -0800478func (r *RuleBuilder) Build(name string, desc string) {
Colin Cross1d2cf042019-03-29 15:33:06 -0700479 name = ninjaNameEscape(name)
480
Colin Cross0d2f40a2019-02-05 22:31:15 -0800481 if len(r.missingDeps) > 0 {
Colin Crossf1a035e2020-11-16 17:32:30 -0800482 r.ctx.Build(pctx, BuildParams{
Colin Cross0d2f40a2019-02-05 22:31:15 -0800483 Rule: ErrorRule,
Colin Cross69f59a32019-02-15 10:39:37 -0800484 Outputs: r.Outputs(),
Colin Cross0d2f40a2019-02-05 22:31:15 -0800485 Description: desc,
486 Args: map[string]string{
487 "error": "missing dependencies: " + strings.Join(r.missingDeps, ", "),
488 },
489 })
490 return
491 }
492
Colin Cross1d2cf042019-03-29 15:33:06 -0700493 var depFile WritablePath
494 var depFormat blueprint.Deps
495 if depFiles := r.DepFiles(); len(depFiles) > 0 {
496 depFile = depFiles[0]
497 depFormat = blueprint.DepsGCC
498 if len(depFiles) > 1 {
499 // Add a command locally that merges all depfiles together into the first depfile.
Colin Crossf1a035e2020-11-16 17:32:30 -0800500 r.depFileMergerCmd(depFiles)
Dan Willemsen633c5022019-04-12 11:11:38 -0700501
502 if r.sbox {
Colin Crosse16ce362020-11-12 08:29:30 -0800503 // Check for Rel() errors, as all depfiles should be in the output dir. Errors
504 // will be reported to the ctx.
Dan Willemsen633c5022019-04-12 11:11:38 -0700505 for _, path := range depFiles[1:] {
Colin Crossf1a035e2020-11-16 17:32:30 -0800506 Rel(r.ctx, r.outDir.String(), path.String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700507 }
508 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700509 }
510 }
511
Dan Willemsen633c5022019-04-12 11:11:38 -0700512 tools := r.Tools()
Colin Crossb70a1a92021-03-12 17:51:32 -0800513 commands := r.Commands()
Dan Willemsen633c5022019-04-12 11:11:38 -0700514 outputs := r.Outputs()
Colin Cross3d680512020-11-13 16:23:53 -0800515 inputs := r.Inputs()
Colin Crossce3a51d2021-03-19 16:22:12 -0700516 rspFiles := r.rspFiles()
Dan Willemsen633c5022019-04-12 11:11:38 -0700517
518 if len(commands) == 0 {
519 return
520 }
521 if len(outputs) == 0 {
522 panic("No outputs specified from any Commands")
523 }
524
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700525 commandString := strings.Join(commands, " && ")
Dan Willemsen633c5022019-04-12 11:11:38 -0700526
527 if r.sbox {
Colin Crosse16ce362020-11-12 08:29:30 -0800528 // If running the command inside sbox, write the rule data out to an sbox
529 // manifest.textproto.
530 manifest := sbox_proto.Manifest{}
531 command := sbox_proto.Command{}
532 manifest.Commands = append(manifest.Commands, &command)
533 command.Command = proto.String(commandString)
Colin Cross151b9ff2020-11-12 08:29:30 -0800534
Colin Cross619b9ab2020-11-20 18:44:31 +0000535 if depFile != nil {
Colin Crosse16ce362020-11-12 08:29:30 -0800536 manifest.OutputDepfile = proto.String(depFile.String())
Colin Cross619b9ab2020-11-20 18:44:31 +0000537 }
538
Colin Crossba9e4032020-11-24 16:32:22 -0800539 // If sandboxing tools is enabled, add copy rules to the manifest to copy each tool
540 // into the sbox directory.
541 if r.sboxTools {
542 for _, tool := range tools {
543 command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
544 From: proto.String(tool.String()),
545 To: proto.String(sboxPathForToolRel(r.ctx, tool)),
546 })
547 }
548 for _, c := range r.commands {
549 for _, tool := range c.packagedTools {
550 command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
551 From: proto.String(tool.srcPath.String()),
552 To: proto.String(sboxPathForPackagedToolRel(tool)),
553 Executable: proto.Bool(tool.executable),
554 })
555 tools = append(tools, tool.srcPath)
556 }
557 }
558 }
559
Colin Crossab020a72021-03-12 17:52:23 -0800560 // If sandboxing inputs is enabled, add copy rules to the manifest to copy each input
561 // into the sbox directory.
562 if r.sboxInputs {
563 for _, input := range inputs {
564 command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
565 From: proto.String(input.String()),
566 To: proto.String(r.sboxPathForInputRel(input)),
567 })
568 }
569
Colin Crossce3a51d2021-03-19 16:22:12 -0700570 // If using rsp files copy them and their contents into the sbox directory with
571 // the appropriate path mappings.
572 for _, rspFile := range rspFiles {
Colin Crosse55bd422021-03-23 13:44:30 -0700573 command.RspFiles = append(command.RspFiles, &sbox_proto.RspFile{
Colin Crossce3a51d2021-03-19 16:22:12 -0700574 File: proto.String(rspFile.file.String()),
Colin Crosse55bd422021-03-23 13:44:30 -0700575 // These have to match the logic in sboxPathForInputRel
576 PathMappings: []*sbox_proto.PathMapping{
577 {
578 From: proto.String(r.outDir.String()),
579 To: proto.String(sboxOutSubDir),
580 },
581 {
582 From: proto.String(PathForOutput(r.ctx).String()),
583 To: proto.String(sboxOutSubDir),
584 },
585 },
Colin Crossab020a72021-03-12 17:52:23 -0800586 })
587 }
588
589 command.Chdir = proto.Bool(true)
590 }
591
Colin Crosse16ce362020-11-12 08:29:30 -0800592 // Add copy rules to the manifest to copy each output file from the sbox directory.
Colin Crossba9e4032020-11-24 16:32:22 -0800593 // to the output directory after running the commands.
Colin Crosse16ce362020-11-12 08:29:30 -0800594 sboxOutputs := make([]string, len(outputs))
595 for i, output := range outputs {
Colin Crossf1a035e2020-11-16 17:32:30 -0800596 rel := Rel(r.ctx, r.outDir.String(), output.String())
Colin Crosse16ce362020-11-12 08:29:30 -0800597 sboxOutputs[i] = filepath.Join(sboxOutDir, rel)
598 command.CopyAfter = append(command.CopyAfter, &sbox_proto.Copy{
599 From: proto.String(filepath.Join(sboxOutSubDir, rel)),
600 To: proto.String(output.String()),
601 })
602 }
Colin Cross619b9ab2020-11-20 18:44:31 +0000603
Colin Cross5334edd2021-03-11 17:18:21 -0800604 // Outputs that were marked Temporary will not be checked that they are in the output
605 // directory by the loop above, check them here.
606 for path := range r.temporariesSet {
607 Rel(r.ctx, r.outDir.String(), path.String())
608 }
609
Colin Crosse16ce362020-11-12 08:29:30 -0800610 // Add a hash of the list of input files to the manifest so that the textproto file
611 // changes when the list of input files changes and causes the sbox rule that
612 // depends on it to rerun.
613 command.InputHash = proto.String(hashSrcFiles(inputs))
Colin Cross619b9ab2020-11-20 18:44:31 +0000614
Colin Crosse16ce362020-11-12 08:29:30 -0800615 // Verify that the manifest textproto is not inside the sbox output directory, otherwise
616 // it will get deleted when the sbox rule clears its output directory.
Colin Crossf1a035e2020-11-16 17:32:30 -0800617 _, manifestInOutDir := MaybeRel(r.ctx, r.outDir.String(), r.sboxManifestPath.String())
Colin Crosse16ce362020-11-12 08:29:30 -0800618 if manifestInOutDir {
Colin Crossf1a035e2020-11-16 17:32:30 -0800619 ReportPathErrorf(r.ctx, "sbox rule %q manifestPath %q must not be in outputDir %q",
620 name, r.sboxManifestPath.String(), r.outDir.String())
Colin Crosse16ce362020-11-12 08:29:30 -0800621 }
622
623 // Create a rule to write the manifest as a the textproto.
Colin Cross1c217fd2021-03-12 17:24:18 -0800624 WriteFileRule(r.ctx, r.sboxManifestPath, proto.MarshalTextString(&manifest))
Colin Crosse16ce362020-11-12 08:29:30 -0800625
626 // Generate a new string to use as the command line of the sbox rule. This uses
627 // a RuleBuilderCommand as a convenience method of building the command line, then
628 // converts it to a string to replace commandString.
Colin Crossf1a035e2020-11-16 17:32:30 -0800629 sboxCmd := &RuleBuilderCommand{
630 rule: &RuleBuilder{
631 ctx: r.ctx,
632 },
633 }
634 sboxCmd.Text("rm -rf").Output(r.outDir)
Colin Crosse16ce362020-11-12 08:29:30 -0800635 sboxCmd.Text("&&")
Colin Crossf1a035e2020-11-16 17:32:30 -0800636 sboxCmd.BuiltTool("sbox").
637 Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(r.ctx).String())).
Colin Crosse16ce362020-11-12 08:29:30 -0800638 Flag("--manifest").Input(r.sboxManifestPath)
639
640 // Replace the command string, and add the sbox tool and manifest textproto to the
641 // dependencies of the final sbox rule.
Colin Crosscfec40c2019-07-08 17:07:18 -0700642 commandString = sboxCmd.buf.String()
Dan Willemsen633c5022019-04-12 11:11:38 -0700643 tools = append(tools, sboxCmd.tools...)
Colin Crosse16ce362020-11-12 08:29:30 -0800644 inputs = append(inputs, sboxCmd.inputs...)
Colin Crossef972742021-03-12 17:24:45 -0800645
646 if r.rbeParams != nil {
Colin Crosse55bd422021-03-23 13:44:30 -0700647 // RBE needs a list of input files to copy to the remote builder. For inputs already
648 // listed in an rsp file, pass the rsp file directly to rewrapper. For the rest,
649 // create a new rsp file to pass to rewrapper.
650 var remoteRspFiles Paths
651 var remoteInputs Paths
652
653 remoteInputs = append(remoteInputs, inputs...)
654 remoteInputs = append(remoteInputs, tools...)
655
Colin Crossce3a51d2021-03-19 16:22:12 -0700656 for _, rspFile := range rspFiles {
657 remoteInputs = append(remoteInputs, rspFile.file)
658 remoteRspFiles = append(remoteRspFiles, rspFile.file)
Colin Crossef972742021-03-12 17:24:45 -0800659 }
Colin Crosse55bd422021-03-23 13:44:30 -0700660
661 if len(remoteInputs) > 0 {
662 inputsListFile := r.sboxManifestPath.ReplaceExtension(r.ctx, "rbe_inputs.list")
663 writeRspFileRule(r.ctx, inputsListFile, remoteInputs)
664 remoteRspFiles = append(remoteRspFiles, inputsListFile)
665 // Add the new rsp file as an extra input to the rule.
666 inputs = append(inputs, inputsListFile)
667 }
Colin Crossef972742021-03-12 17:24:45 -0800668
669 r.rbeParams.OutputFiles = outputs.Strings()
Colin Crosse55bd422021-03-23 13:44:30 -0700670 r.rbeParams.RSPFiles = remoteRspFiles.Strings()
Colin Crossef972742021-03-12 17:24:45 -0800671 rewrapperCommand := r.rbeParams.NoVarTemplate(r.ctx.Config().RBEWrapper())
672 commandString = rewrapperCommand + " bash -c '" + strings.ReplaceAll(commandString, `'`, `'\''`) + "'"
673 }
Colin Cross3d680512020-11-13 16:23:53 -0800674 } else {
675 // If not using sbox the rule will run the command directly, put the hash of the
676 // list of input files in a comment at the end of the command line to ensure ninja
677 // reruns the rule when the list of input files changes.
678 commandString += " # hash of input list: " + hashSrcFiles(inputs)
Dan Willemsen633c5022019-04-12 11:11:38 -0700679 }
680
Colin Cross1d2cf042019-03-29 15:33:06 -0700681 // Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
Colin Cross70c47412021-03-12 17:48:14 -0800682 // ImplicitOutputs. RuleBuilder doesn't use "$out", so the distinction between Outputs and
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700683 // ImplicitOutputs doesn't matter.
Dan Willemsen633c5022019-04-12 11:11:38 -0700684 output := outputs[0]
685 implicitOutputs := outputs[1:]
Colin Cross1d2cf042019-03-29 15:33:06 -0700686
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700687 var rspFile, rspFileContent string
Colin Crossce3a51d2021-03-19 16:22:12 -0700688 var rspFileInputs Paths
689 if len(rspFiles) > 0 {
690 // The first rsp files uses Ninja's rsp file support for the rule
691 rspFile = rspFiles[0].file.String()
Colin Crosse55bd422021-03-23 13:44:30 -0700692 // Use "$in" for rspFileContent to avoid duplicating the list of files in the dependency
693 // list and in the contents of the rsp file. Inputs to the rule that are not in the
694 // rsp file will be listed in Implicits instead of Inputs so they don't show up in "$in".
695 rspFileContent = "$in"
Colin Crossce3a51d2021-03-19 16:22:12 -0700696 rspFileInputs = append(rspFileInputs, rspFiles[0].paths...)
697
698 for _, rspFile := range rspFiles[1:] {
699 // Any additional rsp files need an extra rule to write the file.
700 writeRspFileRule(r.ctx, rspFile.file, rspFile.paths)
701 // The main rule needs to depend on the inputs listed in the extra rsp file.
702 inputs = append(inputs, rspFile.paths...)
703 // The main rule needs to depend on the extra rsp file.
704 inputs = append(inputs, rspFile.file)
705 }
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700706 }
707
Colin Cross8b8bec32019-11-15 13:18:43 -0800708 var pool blueprint.Pool
Colin Crossf1a035e2020-11-16 17:32:30 -0800709 if r.ctx.Config().UseGoma() && r.remoteable.Goma {
Colin Cross8b8bec32019-11-15 13:18:43 -0800710 // When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool.
Colin Crossf1a035e2020-11-16 17:32:30 -0800711 } else if r.ctx.Config().UseRBE() && r.remoteable.RBE {
Ramy Medhat944839a2020-03-31 22:14:52 -0400712 // When USE_RBE=true is set and the rule is supported by RBE, use the remotePool.
713 pool = remotePool
Colin Cross8b8bec32019-11-15 13:18:43 -0800714 } else if r.highmem {
715 pool = highmemPool
Colin Crossf1a035e2020-11-16 17:32:30 -0800716 } else if r.ctx.Config().UseRemoteBuild() {
Colin Cross8b8bec32019-11-15 13:18:43 -0800717 pool = localPool
718 }
719
Colin Crossf1a035e2020-11-16 17:32:30 -0800720 r.ctx.Build(r.pctx, BuildParams{
721 Rule: r.ctx.Rule(pctx, name, blueprint.RuleParams{
Colin Crossb70a1a92021-03-12 17:51:32 -0800722 Command: proptools.NinjaEscape(commandString),
Colin Cross45029782021-03-16 16:49:52 -0700723 CommandDeps: proptools.NinjaEscapeList(tools.Strings()),
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700724 Restat: r.restat,
Colin Cross45029782021-03-16 16:49:52 -0700725 Rspfile: proptools.NinjaEscape(rspFile),
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700726 RspfileContent: rspFileContent,
Colin Cross8b8bec32019-11-15 13:18:43 -0800727 Pool: pool,
Dan Willemsen633c5022019-04-12 11:11:38 -0700728 }),
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700729 Inputs: rspFileInputs,
Colin Cross3d680512020-11-13 16:23:53 -0800730 Implicits: inputs,
Colin Crossda6401b2021-04-21 11:32:19 -0700731 OrderOnly: r.OrderOnlys(),
Colin Crossae89abe2021-04-21 11:45:23 -0700732 Validations: r.Validations(),
Dan Willemsen633c5022019-04-12 11:11:38 -0700733 Output: output,
734 ImplicitOutputs: implicitOutputs,
Jingwen Chence679d22020-09-23 04:30:02 +0000735 SymlinkOutputs: r.SymlinkOutputs(),
Dan Willemsen633c5022019-04-12 11:11:38 -0700736 Depfile: depFile,
737 Deps: depFormat,
738 Description: desc,
739 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800740}
741
Colin Cross758290d2019-02-01 16:42:32 -0800742// RuleBuilderCommand is a builder for a command in a command line. It can be mutated by its methods to add to the
743// command and track dependencies. The methods mutate the RuleBuilderCommand in place, as well as return the
744// RuleBuilderCommand, so they can be used chained or unchained. All methods that add text implicitly add a single
745// space as a separator from the previous method.
Colin Crossfeec25b2019-01-30 17:32:39 -0800746type RuleBuilderCommand struct {
Colin Crossf1a035e2020-11-16 17:32:30 -0800747 rule *RuleBuilder
748
Jingwen Chence679d22020-09-23 04:30:02 +0000749 buf strings.Builder
750 inputs Paths
751 implicits Paths
752 orderOnlys Paths
Colin Crossae89abe2021-04-21 11:45:23 -0700753 validations Paths
Jingwen Chence679d22020-09-23 04:30:02 +0000754 outputs WritablePaths
755 symlinkOutputs WritablePaths
756 depFiles WritablePaths
757 tools Paths
Colin Crossba9e4032020-11-24 16:32:22 -0800758 packagedTools []PackagingSpec
Colin Crossce3a51d2021-03-19 16:22:12 -0700759 rspFiles []rspFileAndPaths
760}
761
762type rspFileAndPaths struct {
763 file WritablePath
764 paths Paths
Dan Willemsen633c5022019-04-12 11:11:38 -0700765}
766
767func (c *RuleBuilderCommand) addInput(path Path) string {
Dan Willemsen633c5022019-04-12 11:11:38 -0700768 c.inputs = append(c.inputs, path)
Colin Crossab020a72021-03-12 17:52:23 -0800769 return c.PathForInput(path)
Dan Willemsen633c5022019-04-12 11:11:38 -0700770}
771
Colin Crossab020a72021-03-12 17:52:23 -0800772func (c *RuleBuilderCommand) addImplicit(path Path) {
Ramy Medhat2f99eec2020-06-13 17:38:27 -0400773 c.implicits = append(c.implicits, path)
Ramy Medhat2f99eec2020-06-13 17:38:27 -0400774}
775
Colin Crossda71eda2020-02-21 16:55:19 -0800776func (c *RuleBuilderCommand) addOrderOnly(path Path) {
777 c.orderOnlys = append(c.orderOnlys, path)
778}
779
Colin Crossab020a72021-03-12 17:52:23 -0800780// PathForInput takes an input path and returns the appropriate path to use on the command line. If
781// sbox was enabled via a call to RuleBuilder.Sbox() and the path was an output path it returns a
782// path with the placeholder prefix used for outputs in sbox. If sbox is not enabled it returns the
783// original path.
784func (c *RuleBuilderCommand) PathForInput(path Path) string {
785 if c.rule.sbox {
786 rel, inSandbox := c.rule._sboxPathForInputRel(path)
787 if inSandbox {
788 rel = filepath.Join(sboxSandboxBaseDir, rel)
789 }
790 return rel
791 }
792 return path.String()
793}
794
795// PathsForInputs takes a list of input paths and returns the appropriate paths to use on the
796// command line. If sbox was enabled via a call to RuleBuilder.Sbox() a path was an output path, it
797// returns the path with the placeholder prefix used for outputs in sbox. If sbox is not enabled it
798// returns the original paths.
799func (c *RuleBuilderCommand) PathsForInputs(paths Paths) []string {
800 ret := make([]string, len(paths))
801 for i, path := range paths {
802 ret[i] = c.PathForInput(path)
803 }
804 return ret
805}
806
Colin Crossf1a035e2020-11-16 17:32:30 -0800807// PathForOutput takes an output path and returns the appropriate path to use on the command
808// line. If sbox was enabled via a call to RuleBuilder.Sbox(), it returns a path with the
809// placeholder prefix used for outputs in sbox. If sbox is not enabled it returns the
810// original path.
811func (c *RuleBuilderCommand) PathForOutput(path WritablePath) string {
812 if c.rule.sbox {
813 // Errors will be handled in RuleBuilder.Build where we have a context to report them
814 rel, _, _ := maybeRelErr(c.rule.outDir.String(), path.String())
815 return filepath.Join(sboxOutDir, rel)
Dan Willemsen633c5022019-04-12 11:11:38 -0700816 }
817 return path.String()
Colin Crossfeec25b2019-01-30 17:32:39 -0800818}
819
Colin Crossba9e4032020-11-24 16:32:22 -0800820func sboxPathForToolRel(ctx BuilderContext, path Path) string {
821 // Errors will be handled in RuleBuilder.Build where we have a context to report them
822 relOut, isRelOut, _ := maybeRelErr(PathForOutput(ctx, "host", ctx.Config().PrebuiltOS()).String(), path.String())
823 if isRelOut {
824 // The tool is in the output directory, it will be copied to __SBOX_OUT_DIR__/tools/out
825 return filepath.Join(sboxToolsSubDir, "out", relOut)
826 }
827 // The tool is in the source directory, it will be copied to __SBOX_OUT_DIR__/tools/src
828 return filepath.Join(sboxToolsSubDir, "src", path.String())
829}
830
Colin Crossab020a72021-03-12 17:52:23 -0800831func (r *RuleBuilder) _sboxPathForInputRel(path Path) (rel string, inSandbox bool) {
832 // Errors will be handled in RuleBuilder.Build where we have a context to report them
833 rel, isRelSboxOut, _ := maybeRelErr(r.outDir.String(), path.String())
834 if isRelSboxOut {
835 return filepath.Join(sboxOutSubDir, rel), true
836 }
837 if r.sboxInputs {
838 // When sandboxing inputs all inputs have to be copied into the sandbox. Input files that
839 // are outputs of other rules could be an arbitrary absolute path if OUT_DIR is set, so they
840 // will be copied to relative paths under __SBOX_OUT_DIR__/out.
841 rel, isRelOut, _ := maybeRelErr(PathForOutput(r.ctx).String(), path.String())
842 if isRelOut {
843 return filepath.Join(sboxOutSubDir, rel), true
844 }
845 }
846 return path.String(), false
847}
848
849func (r *RuleBuilder) sboxPathForInputRel(path Path) string {
850 rel, _ := r._sboxPathForInputRel(path)
851 return rel
852}
853
854func (r *RuleBuilder) sboxPathsForInputsRel(paths Paths) []string {
855 ret := make([]string, len(paths))
856 for i, path := range paths {
857 ret[i] = r.sboxPathForInputRel(path)
858 }
859 return ret
860}
861
Colin Crossba9e4032020-11-24 16:32:22 -0800862func sboxPathForPackagedToolRel(spec PackagingSpec) string {
863 return filepath.Join(sboxToolsSubDir, "out", spec.relPathInPackage)
864}
865
Colin Crossd11cf622021-03-23 22:30:35 -0700866// PathForPackagedTool takes a PackageSpec for a tool and returns the corresponding path for the
867// tool after copying it into the sandbox. This can be used on the RuleBuilder command line to
868// reference the tool.
869func (c *RuleBuilderCommand) PathForPackagedTool(spec PackagingSpec) string {
870 if !c.rule.sboxTools {
871 panic("PathForPackagedTool() requires SandboxTools()")
872 }
873
874 return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
875}
876
Colin Crossba9e4032020-11-24 16:32:22 -0800877// PathForTool takes a path to a tool, which may be an output file or a source file, and returns
878// the corresponding path for the tool in the sbox sandbox if sbox is enabled, or the original path
879// if it is not. This can be used on the RuleBuilder command line to reference the tool.
880func (c *RuleBuilderCommand) PathForTool(path Path) string {
881 if c.rule.sbox && c.rule.sboxTools {
882 return filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path))
883 }
884 return path.String()
885}
886
Colin Crossd11cf622021-03-23 22:30:35 -0700887// PathsForTools takes a list of paths to tools, which may be output files or source files, and
888// returns the corresponding paths for the tools in the sbox sandbox if sbox is enabled, or the
889// original paths if it is not. This can be used on the RuleBuilder command line to reference the tool.
890func (c *RuleBuilderCommand) PathsForTools(paths Paths) []string {
891 if c.rule.sbox && c.rule.sboxTools {
892 var ret []string
893 for _, path := range paths {
894 ret = append(ret, filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path)))
895 }
896 return ret
897 }
898 return paths.Strings()
899}
900
Colin Crossba9e4032020-11-24 16:32:22 -0800901// PackagedTool adds the specified tool path to the command line. It can only be used with tool
902// sandboxing enabled by SandboxTools(), and will copy the tool into the sandbox.
903func (c *RuleBuilderCommand) PackagedTool(spec PackagingSpec) *RuleBuilderCommand {
904 if !c.rule.sboxTools {
905 panic("PackagedTool() requires SandboxTools()")
906 }
907
908 c.packagedTools = append(c.packagedTools, spec)
909 c.Text(sboxPathForPackagedToolRel(spec))
910 return c
911}
912
913// ImplicitPackagedTool copies the specified tool into the sandbox without modifying the command
914// line. It can only be used with tool sandboxing enabled by SandboxTools().
915func (c *RuleBuilderCommand) ImplicitPackagedTool(spec PackagingSpec) *RuleBuilderCommand {
916 if !c.rule.sboxTools {
917 panic("ImplicitPackagedTool() requires SandboxTools()")
918 }
919
920 c.packagedTools = append(c.packagedTools, spec)
921 return c
922}
923
924// ImplicitPackagedTools copies the specified tools into the sandbox without modifying the command
925// line. It can only be used with tool sandboxing enabled by SandboxTools().
926func (c *RuleBuilderCommand) ImplicitPackagedTools(specs []PackagingSpec) *RuleBuilderCommand {
927 if !c.rule.sboxTools {
928 panic("ImplicitPackagedTools() requires SandboxTools()")
929 }
930
931 c.packagedTools = append(c.packagedTools, specs...)
932 return c
933}
934
Colin Cross758290d2019-02-01 16:42:32 -0800935// Text adds the specified raw text to the command line. The text should not contain input or output paths or the
936// rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800937func (c *RuleBuilderCommand) Text(text string) *RuleBuilderCommand {
Colin Crosscfec40c2019-07-08 17:07:18 -0700938 if c.buf.Len() > 0 {
939 c.buf.WriteByte(' ')
Colin Crossfeec25b2019-01-30 17:32:39 -0800940 }
Colin Crosscfec40c2019-07-08 17:07:18 -0700941 c.buf.WriteString(text)
Colin Crossfeec25b2019-01-30 17:32:39 -0800942 return c
943}
944
Colin Cross758290d2019-02-01 16:42:32 -0800945// Textf adds the specified formatted text to the command line. The text should not contain input or output paths or
946// the rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800947func (c *RuleBuilderCommand) Textf(format string, a ...interface{}) *RuleBuilderCommand {
948 return c.Text(fmt.Sprintf(format, a...))
949}
950
Colin Cross758290d2019-02-01 16:42:32 -0800951// Flag adds the specified raw text to the command line. The text should not contain input or output paths or the
952// rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800953func (c *RuleBuilderCommand) Flag(flag string) *RuleBuilderCommand {
954 return c.Text(flag)
955}
956
Colin Crossab054432019-07-15 16:13:59 -0700957// OptionalFlag adds the specified raw text to the command line if it is not nil. The text should not contain input or
958// output paths or the rule will not have them listed in its dependencies or outputs.
959func (c *RuleBuilderCommand) OptionalFlag(flag *string) *RuleBuilderCommand {
960 if flag != nil {
961 c.Text(*flag)
962 }
963
964 return c
965}
966
Colin Cross92b7d582019-03-29 15:32:51 -0700967// Flags adds the specified raw text to the command line. The text should not contain input or output paths or the
968// rule will not have them listed in its dependencies or outputs.
969func (c *RuleBuilderCommand) Flags(flags []string) *RuleBuilderCommand {
970 for _, flag := range flags {
971 c.Text(flag)
972 }
973 return c
974}
975
Colin Cross758290d2019-02-01 16:42:32 -0800976// FlagWithArg adds the specified flag and argument text to the command line, with no separator between them. The flag
977// and argument should not contain input or output paths or the rule will not have them listed in its dependencies or
978// outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800979func (c *RuleBuilderCommand) FlagWithArg(flag, arg string) *RuleBuilderCommand {
980 return c.Text(flag + arg)
981}
982
Colin Crossc7ed0042019-02-11 14:11:09 -0800983// FlagForEachArg adds the specified flag joined with each argument to the command line. The result is identical to
984// calling FlagWithArg for argument.
985func (c *RuleBuilderCommand) FlagForEachArg(flag string, args []string) *RuleBuilderCommand {
986 for _, arg := range args {
987 c.FlagWithArg(flag, arg)
988 }
989 return c
990}
991
Roland Levillain2da5d9a2019-02-27 16:56:41 +0000992// FlagWithList adds the specified flag and list of arguments to the command line, with the arguments joined by sep
Colin Cross758290d2019-02-01 16:42:32 -0800993// and no separator between the flag and arguments. The flag and arguments should not contain input or output paths or
994// the rule will not have them listed in its dependencies or outputs.
Colin Crossfeec25b2019-01-30 17:32:39 -0800995func (c *RuleBuilderCommand) FlagWithList(flag string, list []string, sep string) *RuleBuilderCommand {
996 return c.Text(flag + strings.Join(list, sep))
997}
998
Colin Cross758290d2019-02-01 16:42:32 -0800999// Tool adds the specified tool path to the command line. The path will be also added to the dependencies returned by
1000// RuleBuilder.Tools.
Colin Cross69f59a32019-02-15 10:39:37 -08001001func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -08001002 c.tools = append(c.tools, path)
Colin Crossba9e4032020-11-24 16:32:22 -08001003 return c.Text(c.PathForTool(path))
1004}
1005
1006// Tool adds the specified tool path to the dependencies returned by RuleBuilder.Tools.
1007func (c *RuleBuilderCommand) ImplicitTool(path Path) *RuleBuilderCommand {
1008 c.tools = append(c.tools, path)
1009 return c
1010}
1011
1012// Tool adds the specified tool path to the dependencies returned by RuleBuilder.Tools.
1013func (c *RuleBuilderCommand) ImplicitTools(paths Paths) *RuleBuilderCommand {
1014 c.tools = append(c.tools, paths...)
1015 return c
Colin Crossfeec25b2019-01-30 17:32:39 -08001016}
1017
Colin Crossee94d6a2019-07-08 17:08:34 -07001018// BuiltTool adds the specified tool path that was built using a host Soong module to the command line. The path will
1019// be also added to the dependencies returned by RuleBuilder.Tools.
1020//
1021// It is equivalent to:
1022// cmd.Tool(ctx.Config().HostToolPath(ctx, tool))
Colin Crossf1a035e2020-11-16 17:32:30 -08001023func (c *RuleBuilderCommand) BuiltTool(tool string) *RuleBuilderCommand {
1024 return c.Tool(c.rule.ctx.Config().HostToolPath(c.rule.ctx, tool))
Colin Crossee94d6a2019-07-08 17:08:34 -07001025}
1026
1027// PrebuiltBuildTool adds the specified tool path from prebuils/build-tools. The path will be also added to the
1028// dependencies returned by RuleBuilder.Tools.
1029//
1030// It is equivalent to:
1031// cmd.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
1032func (c *RuleBuilderCommand) PrebuiltBuildTool(ctx PathContext, tool string) *RuleBuilderCommand {
1033 return c.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
1034}
1035
Colin Cross758290d2019-02-01 16:42:32 -08001036// Input adds the specified input path to the command line. The path will also be added to the dependencies returned by
1037// RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001038func (c *RuleBuilderCommand) Input(path Path) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -07001039 return c.Text(c.addInput(path))
Colin Crossfeec25b2019-01-30 17:32:39 -08001040}
1041
Colin Cross758290d2019-02-01 16:42:32 -08001042// Inputs adds the specified input paths to the command line, separated by spaces. The paths will also be added to the
1043// dependencies returned by RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001044func (c *RuleBuilderCommand) Inputs(paths Paths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -08001045 for _, path := range paths {
1046 c.Input(path)
1047 }
1048 return c
1049}
1050
1051// Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the
1052// command line.
Colin Cross69f59a32019-02-15 10:39:37 -08001053func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand {
Ramy Medhat2f99eec2020-06-13 17:38:27 -04001054 c.addImplicit(path)
Colin Crossfeec25b2019-01-30 17:32:39 -08001055 return c
1056}
1057
Colin Cross758290d2019-02-01 16:42:32 -08001058// Implicits adds the specified input paths to the dependencies returned by RuleBuilder.Inputs without modifying the
1059// command line.
Colin Cross69f59a32019-02-15 10:39:37 -08001060func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -07001061 for _, path := range paths {
Ramy Medhat2f99eec2020-06-13 17:38:27 -04001062 c.addImplicit(path)
Dan Willemsen633c5022019-04-12 11:11:38 -07001063 }
Colin Crossfeec25b2019-01-30 17:32:39 -08001064 return c
1065}
1066
Ramy Medhat2f99eec2020-06-13 17:38:27 -04001067// GetImplicits returns the command's implicit inputs.
1068func (c *RuleBuilderCommand) GetImplicits() Paths {
1069 return c.implicits
1070}
1071
Colin Crossda71eda2020-02-21 16:55:19 -08001072// OrderOnly adds the specified input path to the dependencies returned by RuleBuilder.OrderOnlys
1073// without modifying the command line.
1074func (c *RuleBuilderCommand) OrderOnly(path Path) *RuleBuilderCommand {
1075 c.addOrderOnly(path)
1076 return c
1077}
1078
1079// OrderOnlys adds the specified input paths to the dependencies returned by RuleBuilder.OrderOnlys
1080// without modifying the command line.
1081func (c *RuleBuilderCommand) OrderOnlys(paths Paths) *RuleBuilderCommand {
1082 for _, path := range paths {
1083 c.addOrderOnly(path)
1084 }
1085 return c
1086}
1087
Colin Crossae89abe2021-04-21 11:45:23 -07001088// Validation adds the specified input path to the validation dependencies by
1089// RuleBuilder.Validations without modifying the command line.
1090func (c *RuleBuilderCommand) Validation(path Path) *RuleBuilderCommand {
1091 c.validations = append(c.validations, path)
1092 return c
1093}
1094
1095// Validations adds the specified input paths to the validation dependencies by
1096// RuleBuilder.Validations without modifying the command line.
1097func (c *RuleBuilderCommand) Validations(paths Paths) *RuleBuilderCommand {
1098 c.validations = append(c.validations, paths...)
1099 return c
1100}
1101
Colin Cross758290d2019-02-01 16:42:32 -08001102// Output adds the specified output path to the command line. The path will also be added to the outputs returned by
1103// RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001104func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -08001105 c.outputs = append(c.outputs, path)
Colin Crossf1a035e2020-11-16 17:32:30 -08001106 return c.Text(c.PathForOutput(path))
Colin Crossfeec25b2019-01-30 17:32:39 -08001107}
1108
Colin Cross758290d2019-02-01 16:42:32 -08001109// Outputs adds the specified output paths to the command line, separated by spaces. The paths will also be added to
1110// the outputs returned by RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001111func (c *RuleBuilderCommand) Outputs(paths WritablePaths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -08001112 for _, path := range paths {
1113 c.Output(path)
1114 }
1115 return c
1116}
1117
Dan Willemsen1945a4b2019-06-04 17:10:41 -07001118// OutputDir adds the output directory to the command line. This is only available when used with RuleBuilder.Sbox,
1119// and will be the temporary output directory managed by sbox, not the final one.
1120func (c *RuleBuilderCommand) OutputDir() *RuleBuilderCommand {
Colin Crossf1a035e2020-11-16 17:32:30 -08001121 if !c.rule.sbox {
Dan Willemsen1945a4b2019-06-04 17:10:41 -07001122 panic("OutputDir only valid with Sbox")
1123 }
Colin Cross3d680512020-11-13 16:23:53 -08001124 return c.Text(sboxOutDir)
Dan Willemsen1945a4b2019-06-04 17:10:41 -07001125}
1126
Colin Cross1d2cf042019-03-29 15:33:06 -07001127// DepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles and adds it to the command
1128// line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles are added to
1129// commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
1130func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
1131 c.depFiles = append(c.depFiles, path)
Colin Crossf1a035e2020-11-16 17:32:30 -08001132 return c.Text(c.PathForOutput(path))
Colin Cross1d2cf042019-03-29 15:33:06 -07001133}
1134
Colin Cross758290d2019-02-01 16:42:32 -08001135// ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
1136// the command line.
Colin Cross69f59a32019-02-15 10:39:37 -08001137func (c *RuleBuilderCommand) ImplicitOutput(path WritablePath) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -08001138 c.outputs = append(c.outputs, path)
1139 return c
1140}
1141
Colin Cross758290d2019-02-01 16:42:32 -08001142// ImplicitOutputs adds the specified output paths to the dependencies returned by RuleBuilder.Outputs without modifying
1143// the command line.
Colin Cross69f59a32019-02-15 10:39:37 -08001144func (c *RuleBuilderCommand) ImplicitOutputs(paths WritablePaths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -08001145 c.outputs = append(c.outputs, paths...)
1146 return c
1147}
1148
Jingwen Chence679d22020-09-23 04:30:02 +00001149// ImplicitSymlinkOutput declares the specified path as an implicit output that
1150// will be a symlink instead of a regular file. Does not modify the command
1151// line.
1152func (c *RuleBuilderCommand) ImplicitSymlinkOutput(path WritablePath) *RuleBuilderCommand {
1153 c.symlinkOutputs = append(c.symlinkOutputs, path)
1154 return c.ImplicitOutput(path)
1155}
1156
1157// ImplicitSymlinkOutputs declares the specified paths as implicit outputs that
1158// will be a symlinks instead of regular files. Does not modify the command
1159// line.
1160func (c *RuleBuilderCommand) ImplicitSymlinkOutputs(paths WritablePaths) *RuleBuilderCommand {
1161 for _, path := range paths {
1162 c.ImplicitSymlinkOutput(path)
1163 }
1164 return c
1165}
1166
1167// SymlinkOutput declares the specified path as an output that will be a symlink
1168// instead of a regular file. Modifies the command line.
1169func (c *RuleBuilderCommand) SymlinkOutput(path WritablePath) *RuleBuilderCommand {
1170 c.symlinkOutputs = append(c.symlinkOutputs, path)
1171 return c.Output(path)
1172}
1173
1174// SymlinkOutputsl declares the specified paths as outputs that will be symlinks
1175// instead of regular files. Modifies the command line.
1176func (c *RuleBuilderCommand) SymlinkOutputs(paths WritablePaths) *RuleBuilderCommand {
1177 for _, path := range paths {
1178 c.SymlinkOutput(path)
1179 }
1180 return c
1181}
1182
Colin Cross1d2cf042019-03-29 15:33:06 -07001183// ImplicitDepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles without modifying
1184// the command line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles
1185// are added to commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the
1186// depfiles together.
1187func (c *RuleBuilderCommand) ImplicitDepFile(path WritablePath) *RuleBuilderCommand {
1188 c.depFiles = append(c.depFiles, path)
1189 return c
1190}
1191
Colin Cross758290d2019-02-01 16:42:32 -08001192// FlagWithInput adds the specified flag and input path to the command line, with no separator between them. The path
1193// will also be added to the dependencies returned by RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001194func (c *RuleBuilderCommand) FlagWithInput(flag string, path Path) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -07001195 return c.Text(flag + c.addInput(path))
Colin Crossfeec25b2019-01-30 17:32:39 -08001196}
1197
Colin Cross758290d2019-02-01 16:42:32 -08001198// FlagWithInputList adds the specified flag and input paths to the command line, with the inputs joined by sep
1199// and no separator between the flag and inputs. The input paths will also be added to the dependencies returned by
1200// RuleBuilder.Inputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001201func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths Paths, sep string) *RuleBuilderCommand {
Dan Willemsen633c5022019-04-12 11:11:38 -07001202 strs := make([]string, len(paths))
1203 for i, path := range paths {
1204 strs[i] = c.addInput(path)
1205 }
1206 return c.FlagWithList(flag, strs, sep)
Colin Crossfeec25b2019-01-30 17:32:39 -08001207}
1208
Colin Cross758290d2019-02-01 16:42:32 -08001209// FlagForEachInput adds the specified flag joined with each input path to the command line. The input paths will also
1210// be added to the dependencies returned by RuleBuilder.Inputs. The result is identical to calling FlagWithInput for
1211// each input path.
Colin Cross69f59a32019-02-15 10:39:37 -08001212func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths Paths) *RuleBuilderCommand {
Colin Cross758290d2019-02-01 16:42:32 -08001213 for _, path := range paths {
1214 c.FlagWithInput(flag, path)
1215 }
1216 return c
1217}
1218
1219// FlagWithOutput adds the specified flag and output path to the command line, with no separator between them. The path
1220// will also be added to the outputs returned by RuleBuilder.Outputs.
Colin Cross69f59a32019-02-15 10:39:37 -08001221func (c *RuleBuilderCommand) FlagWithOutput(flag string, path WritablePath) *RuleBuilderCommand {
Colin Crossfeec25b2019-01-30 17:32:39 -08001222 c.outputs = append(c.outputs, path)
Colin Crossf1a035e2020-11-16 17:32:30 -08001223 return c.Text(flag + c.PathForOutput(path))
Colin Crossfeec25b2019-01-30 17:32:39 -08001224}
1225
Colin Cross1d2cf042019-03-29 15:33:06 -07001226// FlagWithDepFile adds the specified flag and depfile path to the command line, with no separator between them. The path
1227// will also be added to the outputs returned by RuleBuilder.Outputs.
1228func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *RuleBuilderCommand {
1229 c.depFiles = append(c.depFiles, path)
Colin Crossf1a035e2020-11-16 17:32:30 -08001230 return c.Text(flag + c.PathForOutput(path))
Colin Cross1d2cf042019-03-29 15:33:06 -07001231}
1232
Colin Crossce3a51d2021-03-19 16:22:12 -07001233// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with
1234// no separator between them. The paths will be written to the rspfile. If sbox is enabled, the
1235// rspfile must be outside the sbox directory. The first use of FlagWithRspFileInputList in any
1236// RuleBuilderCommand of a RuleBuilder will use Ninja's rsp file support for the rule, additional
1237// uses will result in an auxiliary rules to write the rspFile contents.
Colin Cross70c47412021-03-12 17:48:14 -08001238func (c *RuleBuilderCommand) FlagWithRspFileInputList(flag string, rspFile WritablePath, paths Paths) *RuleBuilderCommand {
Colin Cross0cb0d7b2019-07-11 10:59:15 -07001239 // Use an empty slice if paths is nil, the non-nil slice is used as an indicator that the rsp file must be
1240 // generated.
1241 if paths == nil {
1242 paths = Paths{}
1243 }
1244
Colin Crossce3a51d2021-03-19 16:22:12 -07001245 c.rspFiles = append(c.rspFiles, rspFileAndPaths{rspFile, paths})
Colin Cross0cb0d7b2019-07-11 10:59:15 -07001246
Colin Cross70c47412021-03-12 17:48:14 -08001247 if c.rule.sbox {
1248 if _, isRel, _ := maybeRelErr(c.rule.outDir.String(), rspFile.String()); isRel {
1249 panic(fmt.Errorf("FlagWithRspFileInputList rspfile %q must not be inside out dir %q",
1250 rspFile.String(), c.rule.outDir.String()))
1251 }
1252 }
1253
Colin Crossab020a72021-03-12 17:52:23 -08001254 c.FlagWithArg(flag, c.PathForInput(rspFile))
Colin Cross0cb0d7b2019-07-11 10:59:15 -07001255 return c
1256}
1257
Colin Cross758290d2019-02-01 16:42:32 -08001258// String returns the command line.
1259func (c *RuleBuilderCommand) String() string {
Colin Crosscfec40c2019-07-08 17:07:18 -07001260 return c.buf.String()
Colin Cross758290d2019-02-01 16:42:32 -08001261}
Colin Cross1d2cf042019-03-29 15:33:06 -07001262
Colin Crosse16ce362020-11-12 08:29:30 -08001263// RuleBuilderSboxProtoForTests takes the BuildParams for the manifest passed to RuleBuilder.Sbox()
1264// and returns sbox testproto generated by the RuleBuilder.
1265func RuleBuilderSboxProtoForTests(t *testing.T, params TestingBuildParams) *sbox_proto.Manifest {
1266 t.Helper()
1267 content := ContentFromFileRuleForTests(t, params)
1268 manifest := sbox_proto.Manifest{}
1269 err := proto.UnmarshalText(content, &manifest)
1270 if err != nil {
1271 t.Fatalf("failed to unmarshal manifest: %s", err.Error())
1272 }
1273 return &manifest
1274}
1275
Colin Cross1d2cf042019-03-29 15:33:06 -07001276func ninjaNameEscape(s string) string {
1277 b := []byte(s)
1278 escaped := false
1279 for i, c := range b {
1280 valid := (c >= 'a' && c <= 'z') ||
1281 (c >= 'A' && c <= 'Z') ||
1282 (c >= '0' && c <= '9') ||
1283 (c == '_') ||
1284 (c == '-') ||
1285 (c == '.')
1286 if !valid {
1287 b[i] = '_'
1288 escaped = true
1289 }
1290 }
1291 if escaped {
1292 s = string(b)
1293 }
1294 return s
1295}
Colin Cross3d680512020-11-13 16:23:53 -08001296
1297// hashSrcFiles returns a hash of the list of source files. It is used to ensure the command line
1298// or the sbox textproto manifest change even if the input files are not listed on the command line.
1299func hashSrcFiles(srcFiles Paths) string {
1300 h := sha256.New()
1301 srcFileList := strings.Join(srcFiles.Strings(), "\n")
1302 h.Write([]byte(srcFileList))
1303 return fmt.Sprintf("%x", h.Sum(nil))
1304}
Colin Crossf1a035e2020-11-16 17:32:30 -08001305
1306// BuilderContextForTesting returns a BuilderContext for the given config that can be used for tests
1307// that need to call methods that take a BuilderContext.
1308func BuilderContextForTesting(config Config) BuilderContext {
1309 pathCtx := PathContextForTesting(config)
1310 return builderContextForTests{
1311 PathContext: pathCtx,
1312 }
1313}
1314
1315type builderContextForTests struct {
1316 PathContext
1317}
1318
1319func (builderContextForTests) Rule(PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule {
1320 return nil
1321}
1322func (builderContextForTests) Build(PackageContext, BuildParams) {}
Colin Crossef972742021-03-12 17:24:45 -08001323
Colin Crosse55bd422021-03-23 13:44:30 -07001324func writeRspFileRule(ctx BuilderContext, rspFile WritablePath, paths Paths) {
1325 buf := &strings.Builder{}
1326 err := response.WriteRspFile(buf, paths.Strings())
1327 if err != nil {
1328 // There should never be I/O errors writing to a bytes.Buffer.
1329 panic(err)
Colin Crossef972742021-03-12 17:24:45 -08001330 }
Colin Crosse55bd422021-03-23 13:44:30 -07001331 WriteFileRule(ctx, rspFile, buf.String())
Colin Crossef972742021-03-12 17:24:45 -08001332}