Skip to content

Commit

Permalink
Retrieve named_outputs keys with get_named_outs (#2808)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
izissise authored Jun 15, 2023
1 parent 9018510 commit 22137cc
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 1 deletion.
2 changes: 1 addition & 1 deletion docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ genrule(
plugins = {
"python": "v1.3.0",
"java": "v0.3.0",
"go": "v1.6.0",
"go": "v1.7.0",
"cc": "v0.3.2",
"shell": "v0.1.2",
"go-proto": "v0.2.0",
Expand Down
2 changes: 2 additions & 0 deletions rules/builtins.build_defs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ def add_out(target:str, name:str, out:str=''):
pass
def get_outs(target:str):
pass
def get_named_outs(target:str) -> dict:
pass
def add_licence(target:str, licence:str):
pass
def get_licences(target:str):
Expand Down
23 changes: 23 additions & 0 deletions src/core/build_target.go
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,29 @@ func (target *BuildTarget) DeclaredOutputNames() []string {
return ret
}

// DeclaredNamedSources returns the named sources from this target's original declaration.
func (target *BuildTarget) DeclaredNamedSources() map[string][]string {
ret := make(map[string][]string, len(target.NamedSources))
for k, v := range target.NamedSources {
ret[k] = make([]string, len(v))
for i, bi := range v {
ret[k][i] = bi.String()
}
}
return ret
}

// DeclaredSourceNames is a convenience function to return the names of the declared
// sources in a consistent order.
func (target *BuildTarget) DeclaredSourceNames() []string {
ret := make([]string, 0, len(target.NamedSources))
for name := range target.NamedSources {
ret = append(ret, name)
}
sort.Strings(ret)
return ret
}

func (target *BuildTarget) filegroupOutputs(srcs []BuildInput) []string {
ret := make([]string, 0, len(srcs))
// Filegroups just re-output their inputs.
Expand Down
29 changes: 29 additions & 0 deletions src/parse/asp/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func registerBuiltins(s *scope) {
setNativeCode(s, "add_data", addData)
setNativeCode(s, "add_out", addOut)
setNativeCode(s, "get_outs", getOuts)
setNativeCode(s, "get_named_outs", getNamedOuts)
setNativeCode(s, "add_licence", addLicence)
setNativeCode(s, "get_licences", getLicences)
setNativeCode(s, "get_command", getCommand)
Expand Down Expand Up @@ -1020,6 +1021,34 @@ func getOuts(s *scope, args []pyObject) pyObject {
return ret
}

// getNamedOuts gets the named outputs of a target
func getNamedOuts(s *scope, args []pyObject) pyObject {
var target *core.BuildTarget
if name := args[0].String(); core.LooksLikeABuildLabel(name) {
label := core.ParseBuildLabel(name, s.pkg.Name)
target = s.state.Graph.TargetOrDie(label)
} else {
target = getTargetPost(s, name)
}

var outs map[string][]string
if target.IsFilegroup {
outs = target.DeclaredNamedSources()
} else {
outs = target.DeclaredNamedOutputs()
}

ret := make(pyDict, len(outs))
for k, v := range outs {
list := make(pyList, len(v))
for i, out := range v {
list[i] = pyString(out)
}
ret[k] = list
}
return ret
}

// addLicence adds a licence to a target.
func addLicence(s *scope, args []pyObject) pyObject {
target := getTargetPost(s, string(args[0].(pyString)))
Expand Down
90 changes: 90 additions & 0 deletions test/get_outs/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
nonamedouts = genrule(
name = "nonamedouts",
outs = ["x"],
cmd = """
echo 'x' > "$OUTS"
""",
)

gr_getouts = genrule(
name = "genrule_getouts",
outs = {
"wibble": ["wibble_file1"],
"wobble": ["wobble_file1"],
},
cmd = """
echo 'wibblewibblewibble' > "$OUTS_WIBBLE"
echo 'wobblewobblewobble' > "$OUTS_WOBBLE"
""",
)

fg_getouts = filegroup(
name = "filegroup_getouts",
srcs = {
"wibble": [text_file(name = 'wibble_file2', content = 'wibblewibblewibble')],
"wobble": [text_file(name = 'wobble_file2', content = 'wobblewobblewobble')],
},
)

def assert_dict(l1, l2):
if l1 != l2:
fail(f"{l1} != {l2}")

assert_dict({}, get_named_outs(nonamedouts))

assert_dict({
"wibble": ["wibble_file1"],
"wobble": ["wobble_file1"],
}, get_named_outs(gr_getouts))

assert_dict({
"wibble": ["//test/get_outs:wibble_file2"],
"wobble": ["//test/get_outs:wobble_file2"],
}, get_named_outs(fg_getouts))

gr_subtargets = { k: [f'{gr_getouts}|{k}'] for k, _ in get_named_outs(gr_getouts).items() }
fg_subtargets = { k: [f'{fg_getouts}|{k}'] for k, _ in get_named_outs(fg_getouts).items() }

gentest(
name = "get_outs_gr_wibble_test",
data = gr_subtargets.wibble,
labels = ["get_outs"],
no_test_output = True,
test_cmd = """
$TOOL "$DATA" "wibblewibblewibble"
""",
test_tools = ["//test/build_defs:content_checker"],
)

gentest(
name = "get_outs_gr_wobble_test",
data = gr_subtargets.wobble,
labels = ["get_outs"],
no_test_output = True,
test_cmd = """
$TOOL "$DATA" "wobblewobblewobble"
""",
test_tools = ["//test/build_defs:content_checker"],
)

gentest(
name = "get_outs_fg_wibble_test",
data = fg_subtargets.wibble,
labels = ["get_outs"],
no_test_output = True,
test_cmd = """
$TOOL "$DATA" "wibblewibblewibble"
""",
test_tools = ["//test/build_defs:content_checker"],
)

gentest(
name = "get_outs_fg_wobble_test",
data = fg_subtargets.wobble,
labels = ["get_outs"],
no_test_output = True,
test_cmd = """
$TOOL "$DATA" "wobblewobblewobble"
""",
test_tools = ["//test/build_defs:content_checker"],
)

0 comments on commit 22137cc

Please sign in to comment.