Skip to content

Commit

Permalink
Merge pull request #108 from thought-machine/plz-whatoutputs
Browse files Browse the repository at this point in the history
Add a new subcommand - plz query whatoutputs
  • Loading branch information
dimpavloff authored Jul 4, 2016
2 parents 43ca08d + 6a407f0 commit 578521e
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/please.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ var opts struct {
Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to render graph for"`
} `positional-args:"true"`
} `command:"graph" description:"Prints a JSON representation of the build graph."`
WhatOutputs struct {
EchoFiles bool `long:"echo_files" description:"Echo the file for which the printed output is responsible."`
Args struct {
Files []string `positional-arg-name:"files" description:"Files to query targets responsible for"`
} `positional-args:"true"`
} `command:"whatoutputs" description:"Prints out target(s) responsible for outputting provided file(s)"`
} `command:"query" description:"Queries information about the build graph"`
}

Expand Down Expand Up @@ -347,6 +353,15 @@ var buildFunctions = map[string]func() bool{
query.QueryGraph(state.Graph, state.ExpandOriginalTargets())
})
},
"whatoutputs": func() bool {
files := opts.Query.WhatOutputs.Args.Files
return runQuery(true, core.WholeGraph, func(state *core.BuildState) {
if len(files) == 1 && files[0] == "-" {
files = utils.ReadAllStdin()
}
query.WhatOutputs(state.Graph, files, opts.Query.WhatOutputs.EchoFiles)
})
},
}

// Used above as a convenience wrapper for query functions.
Expand Down
10 changes: 10 additions & 0 deletions src/query/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,13 @@ go_test(
'//third_party/go:testify',
],
)

go_test(
name = 'whatoutputs_test',
srcs = ['whatoutputs_test.go'],
deps = [
':query',
'//src/core',
'//third_party/go:testify',
],
)
38 changes: 38 additions & 0 deletions src/query/whatoutputs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package query

import (
"core"
"fmt"
"path"
)

// WhatOuputs prints the target responsible for producing each of the provided files
// The targets are printed in the same order as the provided files, separated by a newline
// Use print_files to additionally echo the files themselves (i.e. print <file> <target>)
func WhatOutputs(graph *core.BuildGraph, files []string, print_files bool) {
packageMap := filesToLabelMap(graph)
for _, f := range files {
if print_files {
fmt.Printf("%s ", f)
}
if build_label, present := packageMap[f]; present {
fmt.Printf("%s\n", build_label)
} else {
// # TODO(dimitar): is this a good way to handle unknown files?
fmt.Println("Error: the file is not a product of any current target")
}
}
}

func filesToLabelMap(graph *core.BuildGraph) map[string]*core.BuildLabel {
packageMap := make(map[string]*core.BuildLabel)
for _, pkg := range graph.PackageMap() {
for _, target := range pkg.Outputs {
for _, output := range target.Outputs() {
artifact_path := path.Join(target.OutDir(), output)
packageMap[artifact_path] = &target.Label
}
}
}
return packageMap
}
64 changes: 64 additions & 0 deletions src/query/whatoutputs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package query

import (
"fmt"
"path"
"testing"

"github.com/stretchr/testify/assert"

"core"
)

func makeTarget(g *core.BuildGraph, packageName string, label_name string, outputs []string) *core.BuildTarget {
l := core.ParseBuildLabel(fmt.Sprintf("//%s:%s", packageName, label_name), "")
t := core.NewBuildTarget(l)

p := g.Package(packageName)
if p == nil {
p = core.NewPackage(packageName)
g.AddPackage(p)
}
for _, out := range outputs {
t.AddOutput(out)
p.MustRegisterOutput(out, t)
}
p.Targets[label_name] = t
g.AddTarget(t)
return t
}

func TestConstructsMapFromGraph(t *testing.T) {
core.State = &core.BuildState{}
graph := core.NewGraph()
m := filesToLabelMap(graph)
assert.Equal(t, 0, len(m))

label := core.ParseBuildLabel("//package1:target1", "")
makeTarget(graph, "package1", "target1", []string{"out1", "out2"})
m = filesToLabelMap(graph)
assert.Equal(t, 2, len(m))
for _, l := range m {
assert.Equal(t, label.String(), l.String())
}
}

func TestMapKeysContainFullPathFromProjectRoot(t *testing.T) {
core.State = &core.BuildState{}
graph := core.NewGraph()
makeTarget(graph, "package1", "target1", []string{"out1", "out2"})
makeTarget(graph, "package1", "target2", []string{"out3"})
makeTarget(graph, "package2", "target1", []string{"out4"})
m := filesToLabelMap(graph)
label1 := core.ParseBuildLabel("//package1:target1", "")
label2 := core.ParseBuildLabel("//package1:target2", "")
label3 := core.ParseBuildLabel("//package2:target1", "")

p1 := graph.PackageOrDie("package1")
p2 := graph.PackageOrDie("package2")

assert.Equal(t, m[path.Join(p1.Targets["target1"].OutDir(), "out1")].String(), label1.String())
assert.Equal(t, m[path.Join(p1.Targets["target1"].OutDir(), "out2")].String(), label1.String())
assert.Equal(t, m[path.Join(p1.Targets["target2"].OutDir(), "out3")].String(), label2.String())
assert.Equal(t, m[path.Join(p2.Targets["target1"].OutDir(), "out4")].String(), label3.String())
}

0 comments on commit 578521e

Please sign in to comment.