Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/please.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ var opts struct {
Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to query" required:"true"`
} `positional-args:"true" required:"true"`
} `command:"revdeps" alias:"reverseDeps" description:"Queries all the reverse dependencies of a target."`
RuntimeDeps struct {
Args struct {
Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to query" required:"true"`
} `positional-args:"true" required:"true"`
} `command:"runtimedeps" description:"Queries all the run-time dependencies of a target."`
SomePath struct {
Except []core.BuildLabel `long:"except" description:"Targets to exclude from path calculation"`
Hidden bool `long:"hidden" description:"Show hidden targets as well"`
Expand Down Expand Up @@ -792,6 +797,11 @@ var buildFunctions = map[string]func() int{
query.ReverseDeps(state, state.ExpandLabels(labels), opts.Query.ReverseDeps.Level, opts.Query.ReverseDeps.Hidden)
})
},
"query.runtimedeps": func() int {
return runQuery(true, opts.Query.RuntimeDeps.Args.Targets, func(state *core.BuildState) {
query.RuntimeDeps(os.Stdout, state, state.ExpandOriginalLabels())
})
},
"query.somepath": func() int {
a := plz.ReadStdinLabels([]core.BuildLabel{opts.Query.SomePath.Args.Target1})
b := plz.ReadStdinLabels([]core.BuildLabel{opts.Query.SomePath.Args.Target2})
Expand Down
28 changes: 28 additions & 0 deletions src/query/runtime_deps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package query

import (
"fmt"
"io"

"github.com/thought-machine/please/src/core"
)

// RuntimeDeps prints all transitive run-time dependencies of a set of targets.
func RuntimeDeps(out io.Writer, state *core.BuildState, labels []core.BuildLabel) {
done := map[core.BuildLabel]bool{}
for _, label := range labels {
runtimeDeps(out, state, state.Graph.TargetOrDie(label), done)
}
}

// runtimeDeps prints all transitive run-time dependencies of a target, except for those that have
// already been printed (which are given by the keys of "done").
func runtimeDeps(out io.Writer, state *core.BuildState, target *core.BuildTarget, done map[core.BuildLabel]bool) {
for l := range target.IterAllRuntimeDependencies(state.Graph) {
if done[l] {
continue
}
done[l] = true
fmt.Fprintf(out, "%s\n", l.String())
}
}
118 changes: 118 additions & 0 deletions src/query/runtime_deps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package query

import (
"bytes"
"strings"
"testing"

"github.com/stretchr/testify/assert"

"github.com/thought-machine/please/src/core"
)

func TestRuntimeDeps(t *testing.T) {
var addTarget func(string, bool, bool, []*core.BuildTarget, []*core.BuildTarget, []*core.BuildTarget) *core.BuildTarget

for _, test := range []struct {
Description string
GraphFunc func() *core.BuildTarget
Expected []string
}{
{
Description: "Explicit run-time deps",
GraphFunc: func() *core.BuildTarget {
run1 := addTarget("runtime_dep_1", false, false, nil, nil, nil)
run2 := addTarget("runtime_dep_2", false, false, nil, nil, []*core.BuildTarget{run1})
root := addTarget("root", false, false, nil, nil, []*core.BuildTarget{run2})
return root
},
Expected: []string{
"//test:runtime_dep_1",
"//test:runtime_dep_2",
},
},
{
Description: "Run-time deps from srcs but not deps",
GraphFunc: func() *core.BuildTarget {
run1 := addTarget("runtime_dep_1", false, false, nil, nil, nil)
run2 := addTarget("runtime_dep_2", false, false, nil, nil, []*core.BuildTarget{run1})
src := addTarget("src", false, false, nil, nil, []*core.BuildTarget{run2})
run3 := addTarget("runtime_dep_3", false, false, nil, nil, nil)
run4 := addTarget("runtime_dep_4", false, false, nil, nil, []*core.BuildTarget{run3})
dep := addTarget("dep", false, false, nil, nil, []*core.BuildTarget{run4})
root := addTarget("root", true, false, []*core.BuildTarget{src}, []*core.BuildTarget{dep}, nil)
return root
},
Expected: []string{
"//test:runtime_dep_1",
"//test:runtime_dep_2",
},
},
{
Description: "Run-time deps from deps but not srcs",
GraphFunc: func() *core.BuildTarget {
run1 := addTarget("runtime_dep_1", false, false, nil, nil, nil)
run2 := addTarget("runtime_dep_2", false, false, nil, nil, []*core.BuildTarget{run1})
src := addTarget("src", false, false, nil, nil, []*core.BuildTarget{run2})
run3 := addTarget("runtime_dep_3", false, false, nil, nil, nil)
run4 := addTarget("runtime_dep_4", false, false, nil, nil, []*core.BuildTarget{run3})
dep := addTarget("dep", false, false, nil, nil, []*core.BuildTarget{run4})
root := addTarget("root", false, true, []*core.BuildTarget{src}, []*core.BuildTarget{dep}, nil)
return root
},
Expected: []string{
"//test:runtime_dep_3",
"//test:runtime_dep_4",
},
},
{
Description: "Run-time deps from both srcs and deps",
GraphFunc: func() *core.BuildTarget {
run1 := addTarget("runtime_dep_1", false, false, nil, nil, nil)
run2 := addTarget("runtime_dep_2", false, false, nil, nil, []*core.BuildTarget{run1})
src := addTarget("src", false, false, nil, nil, []*core.BuildTarget{run2})
run3 := addTarget("runtime_dep_3", false, false, nil, nil, nil)
run4 := addTarget("runtime_dep_4", false, false, nil, nil, []*core.BuildTarget{run3})
dep := addTarget("dep", false, false, nil, nil, []*core.BuildTarget{run4})
root := addTarget("root", true, true, []*core.BuildTarget{src}, []*core.BuildTarget{dep}, nil)
return root
},
Expected: []string{
"//test:runtime_dep_1",
"//test:runtime_dep_2",
"//test:runtime_dep_3",
"//test:runtime_dep_4",
},
},
} {
t.Run(test.Description, func(t *testing.T) {
state := core.NewDefaultBuildState()
testPkg := core.NewPackage("test")

addTarget = func(name string, fromSrcs, fromDeps bool, srcs, deps, runtimeDeps []*core.BuildTarget) *core.BuildTarget {
t := addNewTarget(state.Graph, testPkg, name, nil)
t.RuntimeDependenciesFromSources = fromSrcs
t.RuntimeDependenciesFromDependencies = fromDeps
for _, src := range srcs {
t.AddSource(src.Label)
}
for _, dep := range deps {
t.AddDependency(dep.Label)
}
if runtimeDeps != nil {
t.IsBinary = true
for _, runtimeDep := range runtimeDeps {
t.AddMaybeExportedDependency(runtimeDep.Label, false, false, false, true)
}
}
return t
}

root := test.GraphFunc()

var buf bytes.Buffer
RuntimeDeps(&buf, state, []core.BuildLabel{root.Label})
assert.ElementsMatch(t, test.Expected, strings.Split(strings.TrimSuffix(buf.String(), "\n"), "\n"))
})
}
}
Loading