Skip to content

Commit

Permalink
Adds plz export command
Browse files Browse the repository at this point in the history
  • Loading branch information
peterebden committed Mar 23, 2017
1 parent f6fe6a7 commit 6accdaf
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/BUILD_
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ go_binary(
'//src/clean',
'//src/cli',
'//src/core',
'//src/export',
'//src/gc',
'//src/help',
'//src/metrics',
Expand Down
4 changes: 4 additions & 0 deletions src/core/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ func RecursiveCopyFile(from string, to string, mode os.FileMode, link, fallback
if fi.IsDir() {
return RecursiveCopyFile(name+"/", dest+"/", mode, link, fallback)
} else {
// 0 indicates inheriting the existing mode bits.
if mode == 0 {
mode = info.Mode()
}
return copyOrLinkFile(name, dest, mode, link, fallback)
}
} else {
Expand Down
10 changes: 10 additions & 0 deletions src/export/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
go_library(
name = 'export',
srcs = ['export.go'],
deps = [
'//src/core',
'//src/gc',
'//third_party/go:logging',
],
visibility = ['PUBLIC'],
)
75 changes: 75 additions & 0 deletions src/export/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Package export handles exporting parts of the repo to other directories.
// This is useful if, for example, one wanted to separate out part of
// their repo with all dependencies.
package export

import (
"path"
"strings"

"gopkg.in/op/go-logging.v1"

"core"
"gc"
)

var log = logging.MustGetLogger("export")

// ToDir exports a set of targets to the given directory.
// It dies on any errors.
func ToDir(state *core.BuildState, dir string, targets []core.BuildLabel) {
done := map[*core.BuildTarget]bool{}
for _, target := range targets {
export(state.Graph, dir, state.Graph.TargetOrDie(target), done)
}
// Now write all the build files
packages := map[*core.Package]bool{}
for target := range done {
packages[state.Graph.PackageOrDie(target.Label.PackageName)] = true
}
for pkg := range packages {
dest := path.Join(dir, pkg.Filename)
if err := core.RecursiveCopyFile(pkg.Filename, dest, 0, false, false); err != nil {
log.Fatalf("Failed to copy BUILD file: %s\n", pkg.Filename)
}
// Now rewrite the unused targets out of it
victims := []string{}
for name, target := range pkg.Targets {
if !done[target] {
victims = append(victims, name)
}
}
if err := gc.RewriteFile(state, dest, victims); err != nil {
log.Fatalf("Failed to rewrite BUILD file: %s\n", err)
}
}
}

// export implements the logic of ToDir, but prevents repeating targets.
func export(graph *core.BuildGraph, dir string, target *core.BuildTarget, done map[*core.BuildTarget]bool) {
if done[target] {
return
}
for _, src := range target.AllSources() {
if src.Label() == nil { // We'll handle these dependencies later
for _, p := range src.FullPaths(graph) {
if !strings.HasPrefix(p, "/") { // Don't copy system file deps.
if err := core.RecursiveCopyFile(p, path.Join(dir, p), 0, false, false); err != nil {
log.Fatalf("Error copying file: %s\n", err)
}
}
}
}
}
done[target] = true
for _, dep := range target.Dependencies() {
if parent := dep.Parent(graph); parent != nil && parent != target.Parent(graph) && parent != target {
export(graph, dir, parent, done)
} else {
export(graph, dir, dep, done)
}
}
for _, subinclude := range graph.PackageOrDie(target.Label.PackageName).Subincludes {
export(graph, dir, graph.TargetOrDie(subinclude), done)
}
}
13 changes: 8 additions & 5 deletions src/gc/gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,11 @@ func publicDependencies(graph *core.BuildGraph, target *core.BuildTarget) []*cor
return ret
}

// rewriteFile rewrites a BUILD file to exclude a set of targets.
func rewriteFile(state *core.BuildState, filename string, targets []string) error {
// RewriteFile rewrites a BUILD file to exclude a set of targets.
func RewriteFile(state *core.BuildState, filename string, targets []string) error {
for i, t := range targets {
targets[i] = fmt.Sprintf(`"%s"`, t)
}
data := string(MustAsset("rewrite.py"))
// Template in the variables we want.
data = strings.Replace(data, "__FILENAME__", filename, 1)
Expand All @@ -214,12 +217,12 @@ func rewriteFile(state *core.BuildState, filename string, targets []string) erro
func removeTargets(state *core.BuildState, labels core.BuildLabels) error {
byPackage := map[string][]string{}
for _, l := range labels {
byPackage[l.PackageName] = append(byPackage[l.PackageName], `"`+l.Name+`"`)
byPackage[l.PackageName] = append(byPackage[l.PackageName], l.Name)
}
for pkgName, victims := range byPackage {
filename := state.Graph.PackageOrDie(pkgName).Filename
log.Notice("Rewriting %s to remove %s...\n", filename, strings.Replace(strings.Join(victims, ", "), `"`, "", -1))
if err := rewriteFile(state, filename, victims); err != nil {
log.Notice("Rewriting %s to remove %s...\n", filename, strings.Join(victims, ", "))
if err := RewriteFile(state, filename, victims); err != nil {
return err
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/gc/rewrite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestRewriteFile(t *testing.T) {
wd, _ := os.Getwd()
err := core.CopyFile("src/gc/test_data/before.build", path.Join(wd, "test.build"), 0644)
assert.NoError(t, err)
assert.NoError(t, rewriteFile(state, "test.build", []string{`"prometheus"`, `"cover"`}))
assert.NoError(t, RewriteFile(state, "test.build", []string{"prometheus", "cover"}))
rewritten, err := ioutil.ReadFile("test.build")
assert.NoError(t, err)
after, err := ioutil.ReadFile("src/gc/test_data/after.build")
Expand Down
3 changes: 3 additions & 0 deletions src/gc/stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ import "core"
// GarbageCollect is a stub used at initial bootstrap time to avoid requiring us to run go-bindata yet again.
func GarbageCollect(state *core.BuildState, filter, targets []core.BuildLabel, keepLabels []string, conservative, targetsOnly, srcsOnly, noPrompt, dryRun, git bool) {
}

// RewriteFile is also a stub used at boostrap time that does nothing.
func RewriteFile(state *core.BuildState, filename string, targets []string) error { return nil }
15 changes: 15 additions & 0 deletions src/please.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"clean"
"cli"
"core"
"export"
"gc"
"help"
"metrics"
Expand Down Expand Up @@ -167,6 +168,13 @@ var opts struct {
} `positional-args:"true"`
} `command:"gc" description:"Analyzes the repo to determine unneeded targets."`

Export struct {
Output string `short:"o" long:"output" required:"true" description:"Directory to export into"`
Args struct {
Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to export."`
} `positional-args:"true"`
} `command:"export" description:"Exports a set of targets and files from the repo."`

Help struct {
Args struct {
Topic string `positional-arg-name:"topic" description:"Topic to display help on"`
Expand Down Expand Up @@ -346,6 +354,13 @@ var buildFunctions = map[string]func() bool{
}
return success
},
"export": func() bool {
success, state := runBuild(opts.Export.Args.Targets, false, false)
if success {
export.ToDir(state, opts.Export.Output, state.ExpandOriginalTargets())
}
return success
},
"help": func() bool {
return help.Help(opts.Help.Args.Topic)
},
Expand Down

0 comments on commit 6accdaf

Please sign in to comment.