Skip to content

Commit 22137cc

Browse files
authored
Retrieve named_outputs keys with get_named_outs (#2808)
* Retrieve named_outputs keys with get_named_outs When working with named outputs it is convenient to be able to get the keys from the target after it was created. With this addition, one can do the following: ``` target = genrule( name = "target", outs = { "a": ["a"], "b": ["b"] }, ... ) target = get_named_outs(target) target2 = genrule( name = "target2", srcs = target.a, ... ) ``` This makes easy to re-export a target outs in a filegroup: ``` target = genrule( name = "target", outs = { "a": ["a"], "b": ["b"] }, ... ) fg = filegroup( name = "fg", srcs = get_named_outs(target) | { "c": [":another_rule"] } ) ``` * Output similar to get_outs
1 parent 9018510 commit 22137cc

File tree

5 files changed

+145
-1
lines changed

5 files changed

+145
-1
lines changed

docs/BUILD

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ genrule(
5959
plugins = {
6060
"python": "v1.3.0",
6161
"java": "v0.3.0",
62-
"go": "v1.6.0",
62+
"go": "v1.7.0",
6363
"cc": "v0.3.2",
6464
"shell": "v0.1.2",
6565
"go-proto": "v0.2.0",

rules/builtins.build_defs

+2
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ def add_out(target:str, name:str, out:str=''):
235235
pass
236236
def get_outs(target:str):
237237
pass
238+
def get_named_outs(target:str) -> dict:
239+
pass
238240
def add_licence(target:str, licence:str):
239241
pass
240242
def get_licences(target:str):

src/core/build_target.go

+23
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,29 @@ func (target *BuildTarget) DeclaredOutputNames() []string {
718718
return ret
719719
}
720720

721+
// DeclaredNamedSources returns the named sources from this target's original declaration.
722+
func (target *BuildTarget) DeclaredNamedSources() map[string][]string {
723+
ret := make(map[string][]string, len(target.NamedSources))
724+
for k, v := range target.NamedSources {
725+
ret[k] = make([]string, len(v))
726+
for i, bi := range v {
727+
ret[k][i] = bi.String()
728+
}
729+
}
730+
return ret
731+
}
732+
733+
// DeclaredSourceNames is a convenience function to return the names of the declared
734+
// sources in a consistent order.
735+
func (target *BuildTarget) DeclaredSourceNames() []string {
736+
ret := make([]string, 0, len(target.NamedSources))
737+
for name := range target.NamedSources {
738+
ret = append(ret, name)
739+
}
740+
sort.Strings(ret)
741+
return ret
742+
}
743+
721744
func (target *BuildTarget) filegroupOutputs(srcs []BuildInput) []string {
722745
ret := make([]string, 0, len(srcs))
723746
// Filegroups just re-output their inputs.

src/parse/asp/builtins.go

+29
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ func registerBuiltins(s *scope) {
5757
setNativeCode(s, "add_data", addData)
5858
setNativeCode(s, "add_out", addOut)
5959
setNativeCode(s, "get_outs", getOuts)
60+
setNativeCode(s, "get_named_outs", getNamedOuts)
6061
setNativeCode(s, "add_licence", addLicence)
6162
setNativeCode(s, "get_licences", getLicences)
6263
setNativeCode(s, "get_command", getCommand)
@@ -1020,6 +1021,34 @@ func getOuts(s *scope, args []pyObject) pyObject {
10201021
return ret
10211022
}
10221023

1024+
// getNamedOuts gets the named outputs of a target
1025+
func getNamedOuts(s *scope, args []pyObject) pyObject {
1026+
var target *core.BuildTarget
1027+
if name := args[0].String(); core.LooksLikeABuildLabel(name) {
1028+
label := core.ParseBuildLabel(name, s.pkg.Name)
1029+
target = s.state.Graph.TargetOrDie(label)
1030+
} else {
1031+
target = getTargetPost(s, name)
1032+
}
1033+
1034+
var outs map[string][]string
1035+
if target.IsFilegroup {
1036+
outs = target.DeclaredNamedSources()
1037+
} else {
1038+
outs = target.DeclaredNamedOutputs()
1039+
}
1040+
1041+
ret := make(pyDict, len(outs))
1042+
for k, v := range outs {
1043+
list := make(pyList, len(v))
1044+
for i, out := range v {
1045+
list[i] = pyString(out)
1046+
}
1047+
ret[k] = list
1048+
}
1049+
return ret
1050+
}
1051+
10231052
// addLicence adds a licence to a target.
10241053
func addLicence(s *scope, args []pyObject) pyObject {
10251054
target := getTargetPost(s, string(args[0].(pyString)))

test/get_outs/BUILD

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
nonamedouts = genrule(
2+
name = "nonamedouts",
3+
outs = ["x"],
4+
cmd = """
5+
echo 'x' > "$OUTS"
6+
""",
7+
)
8+
9+
gr_getouts = genrule(
10+
name = "genrule_getouts",
11+
outs = {
12+
"wibble": ["wibble_file1"],
13+
"wobble": ["wobble_file1"],
14+
},
15+
cmd = """
16+
echo 'wibblewibblewibble' > "$OUTS_WIBBLE"
17+
echo 'wobblewobblewobble' > "$OUTS_WOBBLE"
18+
""",
19+
)
20+
21+
fg_getouts = filegroup(
22+
name = "filegroup_getouts",
23+
srcs = {
24+
"wibble": [text_file(name = 'wibble_file2', content = 'wibblewibblewibble')],
25+
"wobble": [text_file(name = 'wobble_file2', content = 'wobblewobblewobble')],
26+
},
27+
)
28+
29+
def assert_dict(l1, l2):
30+
if l1 != l2:
31+
fail(f"{l1} != {l2}")
32+
33+
assert_dict({}, get_named_outs(nonamedouts))
34+
35+
assert_dict({
36+
"wibble": ["wibble_file1"],
37+
"wobble": ["wobble_file1"],
38+
}, get_named_outs(gr_getouts))
39+
40+
assert_dict({
41+
"wibble": ["//test/get_outs:wibble_file2"],
42+
"wobble": ["//test/get_outs:wobble_file2"],
43+
}, get_named_outs(fg_getouts))
44+
45+
gr_subtargets = { k: [f'{gr_getouts}|{k}'] for k, _ in get_named_outs(gr_getouts).items() }
46+
fg_subtargets = { k: [f'{fg_getouts}|{k}'] for k, _ in get_named_outs(fg_getouts).items() }
47+
48+
gentest(
49+
name = "get_outs_gr_wibble_test",
50+
data = gr_subtargets.wibble,
51+
labels = ["get_outs"],
52+
no_test_output = True,
53+
test_cmd = """
54+
$TOOL "$DATA" "wibblewibblewibble"
55+
""",
56+
test_tools = ["//test/build_defs:content_checker"],
57+
)
58+
59+
gentest(
60+
name = "get_outs_gr_wobble_test",
61+
data = gr_subtargets.wobble,
62+
labels = ["get_outs"],
63+
no_test_output = True,
64+
test_cmd = """
65+
$TOOL "$DATA" "wobblewobblewobble"
66+
""",
67+
test_tools = ["//test/build_defs:content_checker"],
68+
)
69+
70+
gentest(
71+
name = "get_outs_fg_wibble_test",
72+
data = fg_subtargets.wibble,
73+
labels = ["get_outs"],
74+
no_test_output = True,
75+
test_cmd = """
76+
$TOOL "$DATA" "wibblewibblewibble"
77+
""",
78+
test_tools = ["//test/build_defs:content_checker"],
79+
)
80+
81+
gentest(
82+
name = "get_outs_fg_wobble_test",
83+
data = fg_subtargets.wobble,
84+
labels = ["get_outs"],
85+
no_test_output = True,
86+
test_cmd = """
87+
$TOOL "$DATA" "wobblewobblewobble"
88+
""",
89+
test_tools = ["//test/build_defs:content_checker"],
90+
)

0 commit comments

Comments
 (0)