blob: 0d1070da26f57ae912a8609597a36b098babaa00 [file] [log] [blame]
Colin Crossfeec25b2019-01-30 17:32:39 -08001// Copyright 2019 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 Cross758290d2019-02-01 16:42:32 -080018 "fmt"
Colin Crossfeec25b2019-01-30 17:32:39 -080019 "path/filepath"
20 "reflect"
Colin Cross758290d2019-02-01 16:42:32 -080021 "strings"
Colin Crossfeec25b2019-01-30 17:32:39 -080022 "testing"
Dan Willemsen633c5022019-04-12 11:11:38 -070023
24 "github.com/google/blueprint"
25
26 "android/soong/shared"
Colin Crossfeec25b2019-01-30 17:32:39 -080027)
28
Colin Cross69f59a32019-02-15 10:39:37 -080029func pathContext() PathContext {
Colin Cross98be1bb2019-12-13 20:41:13 -080030 return PathContextForTesting(TestConfig("out", nil, "", map[string][]byte{
31 "ld": nil,
32 "a.o": nil,
33 "b.o": nil,
34 "cp": nil,
35 "a": nil,
36 "b": nil,
37 "ls": nil,
Jingwen Chence679d22020-09-23 04:30:02 +000038 "ln": nil,
Colin Cross98be1bb2019-12-13 20:41:13 -080039 "turbine": nil,
40 "java": nil,
41 "javac": nil,
42 }))
Colin Cross69f59a32019-02-15 10:39:37 -080043}
44
Colin Cross758290d2019-02-01 16:42:32 -080045func ExampleRuleBuilder() {
46 rule := NewRuleBuilder()
47
Colin Cross69f59a32019-02-15 10:39:37 -080048 ctx := pathContext()
49
50 rule.Command().
51 Tool(PathForSource(ctx, "ld")).
52 Inputs(PathsForTesting("a.o", "b.o")).
53 FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -080054 rule.Command().Text("echo success")
55
56 // To add the command to the build graph:
57 // rule.Build(pctx, ctx, "link", "link")
58
59 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
60 fmt.Printf("tools: %q\n", rule.Tools())
61 fmt.Printf("inputs: %q\n", rule.Inputs())
62 fmt.Printf("outputs: %q\n", rule.Outputs())
63
64 // Output:
Colin Cross69f59a32019-02-15 10:39:37 -080065 // commands: "ld a.o b.o -o out/linked && echo success"
Colin Cross758290d2019-02-01 16:42:32 -080066 // tools: ["ld"]
67 // inputs: ["a.o" "b.o"]
Colin Cross69f59a32019-02-15 10:39:37 -080068 // outputs: ["out/linked"]
Colin Cross758290d2019-02-01 16:42:32 -080069}
70
Jingwen Chence679d22020-09-23 04:30:02 +000071func ExampleRuleBuilder_SymlinkOutputs() {
72 rule := NewRuleBuilder()
73
74 ctx := pathContext()
75
76 rule.Command().
77 Tool(PathForSource(ctx, "ln")).
78 FlagWithInput("-s ", PathForTesting("a.o")).
79 SymlinkOutput(PathForOutput(ctx, "a"))
80 rule.Command().Text("cp out/a out/b").
81 ImplicitSymlinkOutput(PathForOutput(ctx, "b"))
82
83 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
84 fmt.Printf("tools: %q\n", rule.Tools())
85 fmt.Printf("inputs: %q\n", rule.Inputs())
86 fmt.Printf("outputs: %q\n", rule.Outputs())
87 fmt.Printf("symlink_outputs: %q\n", rule.SymlinkOutputs())
88
89 // Output:
90 // commands: "ln -s a.o out/a && cp out/a out/b"
91 // tools: ["ln"]
92 // inputs: ["a.o"]
93 // outputs: ["out/a" "out/b"]
94 // symlink_outputs: ["out/a" "out/b"]
95}
96
Colin Cross5cb5b092019-02-02 21:25:18 -080097func ExampleRuleBuilder_Temporary() {
98 rule := NewRuleBuilder()
99
Colin Cross69f59a32019-02-15 10:39:37 -0800100 ctx := pathContext()
101
102 rule.Command().
103 Tool(PathForSource(ctx, "cp")).
104 Input(PathForSource(ctx, "a")).
105 Output(PathForOutput(ctx, "b"))
106 rule.Command().
107 Tool(PathForSource(ctx, "cp")).
108 Input(PathForOutput(ctx, "b")).
109 Output(PathForOutput(ctx, "c"))
110 rule.Temporary(PathForOutput(ctx, "b"))
Colin Cross5cb5b092019-02-02 21:25:18 -0800111
112 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
113 fmt.Printf("tools: %q\n", rule.Tools())
114 fmt.Printf("inputs: %q\n", rule.Inputs())
115 fmt.Printf("outputs: %q\n", rule.Outputs())
116
117 // Output:
Colin Cross69f59a32019-02-15 10:39:37 -0800118 // commands: "cp a out/b && cp out/b out/c"
Colin Cross5cb5b092019-02-02 21:25:18 -0800119 // tools: ["cp"]
120 // inputs: ["a"]
Colin Cross69f59a32019-02-15 10:39:37 -0800121 // outputs: ["out/c"]
Colin Cross5cb5b092019-02-02 21:25:18 -0800122}
123
124func ExampleRuleBuilder_DeleteTemporaryFiles() {
125 rule := NewRuleBuilder()
126
Colin Cross69f59a32019-02-15 10:39:37 -0800127 ctx := pathContext()
128
129 rule.Command().
130 Tool(PathForSource(ctx, "cp")).
131 Input(PathForSource(ctx, "a")).
132 Output(PathForOutput(ctx, "b"))
133 rule.Command().
134 Tool(PathForSource(ctx, "cp")).
135 Input(PathForOutput(ctx, "b")).
136 Output(PathForOutput(ctx, "c"))
137 rule.Temporary(PathForOutput(ctx, "b"))
Colin Cross5cb5b092019-02-02 21:25:18 -0800138 rule.DeleteTemporaryFiles()
139
140 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
141 fmt.Printf("tools: %q\n", rule.Tools())
142 fmt.Printf("inputs: %q\n", rule.Inputs())
143 fmt.Printf("outputs: %q\n", rule.Outputs())
144
145 // Output:
Colin Cross69f59a32019-02-15 10:39:37 -0800146 // commands: "cp a out/b && cp out/b out/c && rm -f out/b"
Colin Cross5cb5b092019-02-02 21:25:18 -0800147 // tools: ["cp"]
148 // inputs: ["a"]
Colin Cross69f59a32019-02-15 10:39:37 -0800149 // outputs: ["out/c"]
Colin Cross5cb5b092019-02-02 21:25:18 -0800150}
151
Colin Crossdeabb942019-02-11 14:11:09 -0800152func ExampleRuleBuilder_Installs() {
153 rule := NewRuleBuilder()
154
Colin Cross69f59a32019-02-15 10:39:37 -0800155 ctx := pathContext()
156
157 out := PathForOutput(ctx, "linked")
158
159 rule.Command().
160 Tool(PathForSource(ctx, "ld")).
161 Inputs(PathsForTesting("a.o", "b.o")).
162 FlagWithOutput("-o ", out)
163 rule.Install(out, "/bin/linked")
164 rule.Install(out, "/sbin/linked")
Colin Crossdeabb942019-02-11 14:11:09 -0800165
166 fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String())
167
168 // Output:
Colin Cross69f59a32019-02-15 10:39:37 -0800169 // rule.Installs().String() = "out/linked:/bin/linked out/linked:/sbin/linked"
Colin Crossdeabb942019-02-11 14:11:09 -0800170}
171
Colin Cross758290d2019-02-01 16:42:32 -0800172func ExampleRuleBuilderCommand() {
173 rule := NewRuleBuilder()
174
Colin Cross69f59a32019-02-15 10:39:37 -0800175 ctx := pathContext()
176
Colin Cross758290d2019-02-01 16:42:32 -0800177 // chained
Colin Cross69f59a32019-02-15 10:39:37 -0800178 rule.Command().
179 Tool(PathForSource(ctx, "ld")).
180 Inputs(PathsForTesting("a.o", "b.o")).
181 FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800182
183 // unchained
184 cmd := rule.Command()
Colin Cross69f59a32019-02-15 10:39:37 -0800185 cmd.Tool(PathForSource(ctx, "ld"))
186 cmd.Inputs(PathsForTesting("a.o", "b.o"))
187 cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800188
189 // mixed:
Colin Cross69f59a32019-02-15 10:39:37 -0800190 cmd = rule.Command().Tool(PathForSource(ctx, "ld"))
191 cmd.Inputs(PathsForTesting("a.o", "b.o"))
192 cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800193}
194
195func ExampleRuleBuilderCommand_Flag() {
Colin Cross69f59a32019-02-15 10:39:37 -0800196 ctx := pathContext()
Colin Cross758290d2019-02-01 16:42:32 -0800197 fmt.Println(NewRuleBuilder().Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800198 Tool(PathForSource(ctx, "ls")).Flag("-l"))
Colin Cross758290d2019-02-01 16:42:32 -0800199 // Output:
200 // ls -l
201}
202
Colin Cross92b7d582019-03-29 15:32:51 -0700203func ExampleRuleBuilderCommand_Flags() {
204 ctx := pathContext()
205 fmt.Println(NewRuleBuilder().Command().
206 Tool(PathForSource(ctx, "ls")).Flags([]string{"-l", "-a"}))
207 // Output:
208 // ls -l -a
209}
210
Colin Cross758290d2019-02-01 16:42:32 -0800211func ExampleRuleBuilderCommand_FlagWithArg() {
Colin Cross69f59a32019-02-15 10:39:37 -0800212 ctx := pathContext()
Colin Cross758290d2019-02-01 16:42:32 -0800213 fmt.Println(NewRuleBuilder().Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800214 Tool(PathForSource(ctx, "ls")).
Colin Cross758290d2019-02-01 16:42:32 -0800215 FlagWithArg("--sort=", "time"))
216 // Output:
217 // ls --sort=time
218}
219
Colin Crossc7ed0042019-02-11 14:11:09 -0800220func ExampleRuleBuilderCommand_FlagForEachArg() {
Colin Cross69f59a32019-02-15 10:39:37 -0800221 ctx := pathContext()
Colin Crossc7ed0042019-02-11 14:11:09 -0800222 fmt.Println(NewRuleBuilder().Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800223 Tool(PathForSource(ctx, "ls")).
Colin Crossc7ed0042019-02-11 14:11:09 -0800224 FlagForEachArg("--sort=", []string{"time", "size"}))
225 // Output:
226 // ls --sort=time --sort=size
227}
228
Colin Cross758290d2019-02-01 16:42:32 -0800229func ExampleRuleBuilderCommand_FlagForEachInput() {
Colin Cross69f59a32019-02-15 10:39:37 -0800230 ctx := pathContext()
Colin Cross758290d2019-02-01 16:42:32 -0800231 fmt.Println(NewRuleBuilder().Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800232 Tool(PathForSource(ctx, "turbine")).
233 FlagForEachInput("--classpath ", PathsForTesting("a.jar", "b.jar")))
Colin Cross758290d2019-02-01 16:42:32 -0800234 // Output:
235 // turbine --classpath a.jar --classpath b.jar
236}
237
238func ExampleRuleBuilderCommand_FlagWithInputList() {
Colin Cross69f59a32019-02-15 10:39:37 -0800239 ctx := pathContext()
Colin Cross758290d2019-02-01 16:42:32 -0800240 fmt.Println(NewRuleBuilder().Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800241 Tool(PathForSource(ctx, "java")).
242 FlagWithInputList("-classpath=", PathsForTesting("a.jar", "b.jar"), ":"))
Colin Cross758290d2019-02-01 16:42:32 -0800243 // Output:
244 // java -classpath=a.jar:b.jar
245}
246
247func ExampleRuleBuilderCommand_FlagWithInput() {
Colin Cross69f59a32019-02-15 10:39:37 -0800248 ctx := pathContext()
Colin Cross758290d2019-02-01 16:42:32 -0800249 fmt.Println(NewRuleBuilder().Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800250 Tool(PathForSource(ctx, "java")).
251 FlagWithInput("-classpath=", PathForSource(ctx, "a")))
Colin Cross758290d2019-02-01 16:42:32 -0800252 // Output:
253 // java -classpath=a
254}
255
256func ExampleRuleBuilderCommand_FlagWithList() {
Colin Cross69f59a32019-02-15 10:39:37 -0800257 ctx := pathContext()
Colin Cross758290d2019-02-01 16:42:32 -0800258 fmt.Println(NewRuleBuilder().Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800259 Tool(PathForSource(ctx, "ls")).
Colin Cross758290d2019-02-01 16:42:32 -0800260 FlagWithList("--sort=", []string{"time", "size"}, ","))
261 // Output:
262 // ls --sort=time,size
263}
264
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700265func ExampleRuleBuilderCommand_FlagWithRspFileInputList() {
266 ctx := pathContext()
267 fmt.Println(NewRuleBuilder().Command().
268 Tool(PathForSource(ctx, "javac")).
269 FlagWithRspFileInputList("@", PathsForTesting("a.java", "b.java")).
270 NinjaEscapedString())
271 // Output:
272 // javac @$out.rsp
273}
274
275func ExampleRuleBuilderCommand_String() {
276 fmt.Println(NewRuleBuilder().Command().
277 Text("FOO=foo").
278 Text("echo $FOO").
279 String())
280 // Output:
281 // FOO=foo echo $FOO
282}
283
284func ExampleRuleBuilderCommand_NinjaEscapedString() {
285 fmt.Println(NewRuleBuilder().Command().
286 Text("FOO=foo").
287 Text("echo $FOO").
288 NinjaEscapedString())
289 // Output:
290 // FOO=foo echo $$FOO
291}
292
Colin Crossfeec25b2019-01-30 17:32:39 -0800293func TestRuleBuilder(t *testing.T) {
Colin Cross69f59a32019-02-15 10:39:37 -0800294 fs := map[string][]byte{
Colin Crossda71eda2020-02-21 16:55:19 -0800295 "dep_fixer": nil,
296 "input": nil,
297 "Implicit": nil,
298 "Input": nil,
299 "OrderOnly": nil,
300 "OrderOnlys": nil,
301 "Tool": nil,
302 "input2": nil,
303 "tool2": nil,
304 "input3": nil,
Colin Cross69f59a32019-02-15 10:39:37 -0800305 }
306
Colin Cross98be1bb2019-12-13 20:41:13 -0800307 ctx := PathContextForTesting(TestConfig("out", nil, "", fs))
Colin Cross69f59a32019-02-15 10:39:37 -0800308
Dan Willemsen633c5022019-04-12 11:11:38 -0700309 addCommands := func(rule *RuleBuilder) {
310 cmd := rule.Command().
311 DepFile(PathForOutput(ctx, "DepFile")).
312 Flag("Flag").
313 FlagWithArg("FlagWithArg=", "arg").
314 FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")).
315 FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
316 FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")).
317 Implicit(PathForSource(ctx, "Implicit")).
318 ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")).
319 ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
320 Input(PathForSource(ctx, "Input")).
321 Output(PathForOutput(ctx, "Output")).
Colin Crossda71eda2020-02-21 16:55:19 -0800322 OrderOnly(PathForSource(ctx, "OrderOnly")).
Jingwen Chence679d22020-09-23 04:30:02 +0000323 SymlinkOutput(PathForOutput(ctx, "SymlinkOutput")).
324 ImplicitSymlinkOutput(PathForOutput(ctx, "ImplicitSymlinkOutput")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700325 Text("Text").
326 Tool(PathForSource(ctx, "Tool"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800327
Dan Willemsen633c5022019-04-12 11:11:38 -0700328 rule.Command().
329 Text("command2").
330 DepFile(PathForOutput(ctx, "depfile2")).
331 Input(PathForSource(ctx, "input2")).
332 Output(PathForOutput(ctx, "output2")).
Colin Crossda71eda2020-02-21 16:55:19 -0800333 OrderOnlys(PathsForSource(ctx, []string{"OrderOnlys"})).
Dan Willemsen633c5022019-04-12 11:11:38 -0700334 Tool(PathForSource(ctx, "tool2"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800335
Dan Willemsen633c5022019-04-12 11:11:38 -0700336 // Test updates to the first command after the second command has been started
337 cmd.Text("after command2")
338 // Test updating a command when the previous update did not replace the cmd variable
339 cmd.Text("old cmd")
Colin Crossfeec25b2019-01-30 17:32:39 -0800340
Dan Willemsen633c5022019-04-12 11:11:38 -0700341 // Test a command that uses the output of a previous command as an input
342 rule.Command().
343 Text("command3").
344 Input(PathForSource(ctx, "input3")).
345 Input(PathForOutput(ctx, "output2")).
346 Output(PathForOutput(ctx, "output3"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800347 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700348
Colin Cross69f59a32019-02-15 10:39:37 -0800349 wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"})
Jingwen Chence679d22020-09-23 04:30:02 +0000350 wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "ImplicitSymlinkOutput", "Output", "SymlinkOutput", "output", "output2", "output3"})
Colin Cross1d2cf042019-03-29 15:33:06 -0700351 wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
Colin Cross69f59a32019-02-15 10:39:37 -0800352 wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
Colin Crossda71eda2020-02-21 16:55:19 -0800353 wantOrderOnlys := PathsForSource(ctx, []string{"OrderOnly", "OrderOnlys"})
Jingwen Chence679d22020-09-23 04:30:02 +0000354 wantSymlinkOutputs := PathsForOutput(ctx, []string{"ImplicitSymlinkOutput", "SymlinkOutput"})
Colin Crossfeec25b2019-01-30 17:32:39 -0800355
Dan Willemsen633c5022019-04-12 11:11:38 -0700356 t.Run("normal", func(t *testing.T) {
357 rule := NewRuleBuilder()
358 addCommands(rule)
Colin Cross1d2cf042019-03-29 15:33:06 -0700359
Dan Willemsen633c5022019-04-12 11:11:38 -0700360 wantCommands := []string{
Jingwen Chence679d22020-09-23 04:30:02 +0000361 "out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output out/SymlinkOutput Text Tool after command2 old cmd",
Dan Willemsen633c5022019-04-12 11:11:38 -0700362 "command2 out/depfile2 input2 out/output2 tool2",
363 "command3 input3 out/output2 out/output3",
364 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700365
Dan Willemsen633c5022019-04-12 11:11:38 -0700366 wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2"
367
368 if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
369 t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g)
370 }
371
372 if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
373 t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g)
374 }
375 if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
376 t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g)
377 }
Jingwen Chence679d22020-09-23 04:30:02 +0000378 if g, w := rule.SymlinkOutputs(), wantSymlinkOutputs; !reflect.DeepEqual(w, g) {
379 t.Errorf("\nwant rule.SymlinkOutputs() = %#v\n got %#v", w, g)
380 }
Dan Willemsen633c5022019-04-12 11:11:38 -0700381 if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
382 t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g)
383 }
384 if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
385 t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
386 }
Colin Crossda71eda2020-02-21 16:55:19 -0800387 if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
388 t.Errorf("\nwant rule.OrderOnlys() = %#v\n got %#v", w, g)
389 }
Dan Willemsen633c5022019-04-12 11:11:38 -0700390
391 if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
392 t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
393 }
394 })
395
396 t.Run("sbox", func(t *testing.T) {
397 rule := NewRuleBuilder().Sbox(PathForOutput(ctx))
398 addCommands(rule)
399
400 wantCommands := []string{
Jingwen Chence679d22020-09-23 04:30:02 +0000401 "__SBOX_OUT_DIR__/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_OUT_DIR__/depfile FlagWithInput=input FlagWithOutput=__SBOX_OUT_DIR__/output Input __SBOX_OUT_DIR__/Output __SBOX_OUT_DIR__/SymlinkOutput Text Tool after command2 old cmd",
Dan Willemsen633c5022019-04-12 11:11:38 -0700402 "command2 __SBOX_OUT_DIR__/depfile2 input2 __SBOX_OUT_DIR__/output2 tool2",
403 "command3 input3 __SBOX_OUT_DIR__/output2 __SBOX_OUT_DIR__/output3",
404 }
405
406 wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_OUT_DIR__/DepFile __SBOX_OUT_DIR__/depfile __SBOX_OUT_DIR__/ImplicitDepFile __SBOX_OUT_DIR__/depfile2"
407
408 if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
409 t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g)
410 }
411
412 if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
413 t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g)
414 }
415 if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
416 t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g)
417 }
418 if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
419 t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g)
420 }
421 if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
422 t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
423 }
Colin Crossda71eda2020-02-21 16:55:19 -0800424 if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
425 t.Errorf("\nwant rule.OrderOnlys() = %#v\n got %#v", w, g)
426 }
Dan Willemsen633c5022019-04-12 11:11:38 -0700427
428 if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
429 t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
430 }
431 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800432}
433
434func testRuleBuilderFactory() Module {
435 module := &testRuleBuilderModule{}
436 module.AddProperties(&module.properties)
437 InitAndroidModule(module)
438 return module
439}
440
441type testRuleBuilderModule struct {
442 ModuleBase
443 properties struct {
444 Src string
Dan Willemsen633c5022019-04-12 11:11:38 -0700445
446 Restat bool
447 Sbox bool
Colin Crossfeec25b2019-01-30 17:32:39 -0800448 }
449}
450
451func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Crossfeec25b2019-01-30 17:32:39 -0800452 in := PathForSource(ctx, t.properties.Src)
453 out := PathForModuleOut(ctx, ctx.ModuleName())
Dan Willemsen633c5022019-04-12 11:11:38 -0700454 outDep := PathForModuleOut(ctx, ctx.ModuleName()+".d")
455 outDir := PathForModuleOut(ctx)
Colin Crossfeec25b2019-01-30 17:32:39 -0800456
Dan Willemsen633c5022019-04-12 11:11:38 -0700457 testRuleBuilder_Build(ctx, in, out, outDep, outDir, t.properties.Restat, t.properties.Sbox)
Colin Cross786cd6d2019-02-01 16:41:11 -0800458}
459
460type testRuleBuilderSingleton struct{}
461
462func testRuleBuilderSingletonFactory() Singleton {
463 return &testRuleBuilderSingleton{}
464}
465
466func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
467 in := PathForSource(ctx, "bar")
468 out := PathForOutput(ctx, "baz")
Dan Willemsen633c5022019-04-12 11:11:38 -0700469 outDep := PathForOutput(ctx, "baz.d")
470 outDir := PathForOutput(ctx)
471 testRuleBuilder_Build(ctx, in, out, outDep, outDir, true, false)
Colin Cross786cd6d2019-02-01 16:41:11 -0800472}
473
Dan Willemsen633c5022019-04-12 11:11:38 -0700474func testRuleBuilder_Build(ctx BuilderContext, in Path, out, outDep, outDir WritablePath, restat, sbox bool) {
Colin Cross758290d2019-02-01 16:42:32 -0800475 rule := NewRuleBuilder()
Colin Cross786cd6d2019-02-01 16:41:11 -0800476
Dan Willemsen633c5022019-04-12 11:11:38 -0700477 if sbox {
478 rule.Sbox(outDir)
479 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800480
Dan Willemsen633c5022019-04-12 11:11:38 -0700481 rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out).ImplicitDepFile(outDep)
482
483 if restat {
484 rule.Restat()
485 }
Colin Crossbaa676f2019-02-25 14:56:01 -0800486
Colin Crossfeec25b2019-01-30 17:32:39 -0800487 rule.Build(pctx, ctx, "rule", "desc")
488}
489
490func TestRuleBuilder_Build(t *testing.T) {
Colin Cross98be1bb2019-12-13 20:41:13 -0800491 fs := map[string][]byte{
492 "bar": nil,
493 "cp": nil,
494 }
495
Colin Crossfeec25b2019-01-30 17:32:39 -0800496 bp := `
497 rule_builder_test {
498 name: "foo",
499 src: "bar",
Dan Willemsen633c5022019-04-12 11:11:38 -0700500 restat: true,
501 }
502 rule_builder_test {
503 name: "foo_sbox",
504 src: "bar",
505 sbox: true,
Colin Crossfeec25b2019-01-30 17:32:39 -0800506 }
507 `
508
Colin Cross98be1bb2019-12-13 20:41:13 -0800509 config := TestConfig(buildDir, nil, bp, fs)
Colin Crossfeec25b2019-01-30 17:32:39 -0800510 ctx := NewTestContext()
Colin Cross4b49b762019-11-22 15:25:03 -0800511 ctx.RegisterModuleType("rule_builder_test", testRuleBuilderFactory)
512 ctx.RegisterSingletonType("rule_builder_test", testRuleBuilderSingletonFactory)
Colin Cross98be1bb2019-12-13 20:41:13 -0800513 ctx.Register(config)
Colin Crossfeec25b2019-01-30 17:32:39 -0800514
515 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
516 FailIfErrored(t, errs)
517 _, errs = ctx.PrepareBuildActions(config)
518 FailIfErrored(t, errs)
519
Dan Willemsen633c5022019-04-12 11:11:38 -0700520 check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraCmdDeps []string) {
Dan Willemsenc89b6f12019-08-29 14:47:40 -0700521 t.Helper()
Dan Willemsen633c5022019-04-12 11:11:38 -0700522 if params.RuleParams.Command != wantCommand {
523 t.Errorf("\nwant RuleParams.Command = %q\n got %q", wantCommand, params.RuleParams.Command)
524 }
525
526 wantDeps := append([]string{"cp"}, extraCmdDeps...)
527 if !reflect.DeepEqual(params.RuleParams.CommandDeps, wantDeps) {
528 t.Errorf("\nwant RuleParams.CommandDeps = %q\n got %q", wantDeps, params.RuleParams.CommandDeps)
529 }
530
531 if params.RuleParams.Restat != wantRestat {
532 t.Errorf("want RuleParams.Restat = %v, got %v", wantRestat, params.RuleParams.Restat)
Colin Cross4c83e5c2019-02-25 14:54:28 -0800533 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800534
Colin Cross4c83e5c2019-02-25 14:54:28 -0800535 if len(params.Implicits) != 1 || params.Implicits[0].String() != "bar" {
536 t.Errorf("want Implicits = [%q], got %q", "bar", params.Implicits.Strings())
537 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800538
Colin Cross1d2cf042019-03-29 15:33:06 -0700539 if params.Output.String() != wantOutput {
540 t.Errorf("want Output = %q, got %q", wantOutput, params.Output)
Colin Cross4c83e5c2019-02-25 14:54:28 -0800541 }
Colin Crossbaa676f2019-02-25 14:56:01 -0800542
Dan Willemsen633c5022019-04-12 11:11:38 -0700543 if len(params.ImplicitOutputs) != 0 {
544 t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings())
545 }
546
547 if params.Depfile.String() != wantDepfile {
548 t.Errorf("want Depfile = %q, got %q", wantDepfile, params.Depfile)
549 }
550
551 if params.Deps != blueprint.DepsGCC {
552 t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
Colin Crossbaa676f2019-02-25 14:56:01 -0800553 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800554 }
555
Colin Cross4c83e5c2019-02-25 14:54:28 -0800556 t.Run("module", func(t *testing.T) {
Dan Willemsen633c5022019-04-12 11:11:38 -0700557 outFile := filepath.Join(buildDir, ".intermediates", "foo", "foo")
Colin Cross4c83e5c2019-02-25 14:54:28 -0800558 check(t, ctx.ModuleForTests("foo", "").Rule("rule"),
Dan Willemsen633c5022019-04-12 11:11:38 -0700559 "cp bar "+outFile,
560 outFile, outFile+".d", true, nil)
561 })
562 t.Run("sbox", func(t *testing.T) {
563 outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox")
564 outFile := filepath.Join(outDir, "foo_sbox")
Dan Willemsenc89b6f12019-08-29 14:47:40 -0700565 depFile := filepath.Join(outDir, "foo_sbox.d")
Dan Willemsen633c5022019-04-12 11:11:38 -0700566 sbox := filepath.Join(buildDir, "host", config.PrebuiltOS(), "bin/sbox")
567 sandboxPath := shared.TempDirForOutDir(buildDir)
568
Dan Willemsenc89b6f12019-08-29 14:47:40 -0700569 cmd := sbox + ` -c 'cp bar __SBOX_OUT_DIR__/foo_sbox' --sandbox-path ` + sandboxPath + " --output-root " + outDir + " --depfile-out " + depFile + " __SBOX_OUT_DIR__/foo_sbox"
Dan Willemsen633c5022019-04-12 11:11:38 -0700570
571 check(t, ctx.ModuleForTests("foo_sbox", "").Rule("rule"),
Dan Willemsenc89b6f12019-08-29 14:47:40 -0700572 cmd, outFile, depFile, false, []string{sbox})
Colin Cross4c83e5c2019-02-25 14:54:28 -0800573 })
574 t.Run("singleton", func(t *testing.T) {
Dan Willemsen633c5022019-04-12 11:11:38 -0700575 outFile := filepath.Join(buildDir, "baz")
Colin Cross4c83e5c2019-02-25 14:54:28 -0800576 check(t, ctx.SingletonForTests("rule_builder_test").Rule("rule"),
Dan Willemsen633c5022019-04-12 11:11:38 -0700577 "cp bar "+outFile, outFile, outFile+".d", true, nil)
Colin Cross4c83e5c2019-02-25 14:54:28 -0800578 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800579}
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700580
581func Test_ninjaEscapeExceptForSpans(t *testing.T) {
582 type args struct {
583 s string
584 spans [][2]int
585 }
586 tests := []struct {
587 name string
588 args args
589 want string
590 }{
591 {
592 name: "empty",
593 args: args{
594 s: "",
595 },
596 want: "",
597 },
598 {
599 name: "unescape none",
600 args: args{
601 s: "$abc",
602 },
603 want: "$$abc",
604 },
605 {
606 name: "unescape all",
607 args: args{
608 s: "$abc",
609 spans: [][2]int{{0, 4}},
610 },
611 want: "$abc",
612 },
613 {
614 name: "unescape first",
615 args: args{
616 s: "$abc$",
617 spans: [][2]int{{0, 1}},
618 },
619 want: "$abc$$",
620 },
621 {
622 name: "unescape last",
623 args: args{
624 s: "$abc$",
625 spans: [][2]int{{4, 5}},
626 },
627 want: "$$abc$",
628 },
629 {
630 name: "unescape middle",
631 args: args{
632 s: "$a$b$c$",
633 spans: [][2]int{{2, 5}},
634 },
635 want: "$$a$b$c$$",
636 },
637 {
638 name: "unescape multiple",
639 args: args{
640 s: "$a$b$c$",
641 spans: [][2]int{{2, 3}, {4, 5}},
642 },
643 want: "$$a$b$c$$",
644 },
645 }
646 for _, tt := range tests {
647 t.Run(tt.name, func(t *testing.T) {
648 if got := ninjaEscapeExceptForSpans(tt.args.s, tt.args.spans); got != tt.want {
649 t.Errorf("ninjaEscapeExceptForSpans() = %v, want %v", got, tt.want)
650 }
651 })
652 }
653}