Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add --notrim flag to plz export #3340

Merged
merged 1 commit into from
Jan 28, 2025
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
123 changes: 91 additions & 32 deletions src/export/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package export

import (
iofs "io/fs"
"os"
"path/filepath"

Expand All @@ -16,23 +17,52 @@ import (

var log = logging.Log

type export struct {
state *core.BuildState
targetDir string
noTrim bool

exportedTargets map[core.BuildLabel]bool
exportedPackages map[string]bool
}

// 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{}
func ToDir(state *core.BuildState, dir string, noTrim bool, targets []core.BuildLabel) {
e := &export{
state: state,
noTrim: noTrim,
targetDir: dir,
exportedPackages: map[string]bool{},
exportedTargets: map[core.BuildLabel]bool{},
}

e.exportPlzConf()
for _, target := range state.Config.Parse.PreloadSubincludes {
for _, includeLabel := range append(state.Graph.TransitiveSubincludes(target), target) {
export(state.Graph, dir, state.Graph.TargetOrDie(includeLabel), done)
e.export(state.Graph.TargetOrDie(includeLabel))
}
}
for _, target := range targets {
export(state.Graph, dir, state.Graph.TargetOrDie(target), done)
e.export(state.Graph.TargetOrDie(target))
}
// Now write all the build files
packages := map[*core.Package]bool{}
for target := range done {
packages[state.Graph.PackageOrDie(target.Label)] = true
for target := range e.exportedTargets {
packages[state.Graph.PackageOrDie(target)] = true
}

// Write any preloaded build defs as well; preloaded subincludes should be fine though.
for _, preload := range state.Config.Parse.PreloadBuildDefs {
if err := fs.RecursiveCopy(preload, filepath.Join(dir, preload), 0); err != nil {
log.Fatalf("Failed to copy preloaded build def %s: %s", preload, err)
}
}

if noTrim {
return // We have already exported the whole directory
}

for pkg := range packages {
if pkg.Name == parse.InternalPackageName {
continue // This isn't a real package to be copied
Expand All @@ -41,37 +71,29 @@ func ToDir(state *core.BuildState, dir string, targets []core.BuildLabel) {
continue // Don't copy subrepo BUILD files... they don't exist in our source tree
}
dest := filepath.Join(dir, pkg.Filename)
if err := fs.RecursiveCopy(pkg.Filename, dest, 0); err != nil {
if err := fs.CopyFile(pkg.Filename, dest, 0); err != nil {
log.Fatalf("Failed to copy BUILD file %s: %s\n", pkg.Filename, err)
}
// Now rewrite the unused targets out of it
victims := []string{}
var victims []string
for _, target := range pkg.AllTargets() {
if !done[target] && !target.HasParent() {
if !e.exportedTargets[target.Label] && !target.HasParent() {
victims = append(victims, target.Label.Name)
}
}
if err := gc.RewriteFile(state, dest, victims); err != nil {
log.Fatalf("Failed to rewrite BUILD file: %s\n", err)
}
}
// Write any preloaded build defs as well; preloaded subincludes should be fine though.
for _, preload := range state.Config.Parse.PreloadBuildDefs {
if err := fs.RecursiveCopy(preload, filepath.Join(dir, preload), 0); err != nil {
log.Fatalf("Failed to copy preloaded build def %s: %s", preload, err)
}
}

exportPlzConf(dir)
}

func exportPlzConf(destDir string) {
func (e *export) exportPlzConf() {
profiles, err := filepath.Glob(".plzconfig*")
if err != nil {
log.Fatalf("failed to glob .plzconfig files: %v", err)
}
for _, file := range profiles {
path := filepath.Join(destDir, file)
path := filepath.Join(e.targetDir, file)
if err := os.RemoveAll(path); err != nil {
log.Fatalf("failed to copy .plzconfig file %s: %v", file, err)
}
Expand All @@ -82,12 +104,12 @@ func exportPlzConf(destDir string) {
}

// exportSources exports any source files (srcs and data) for the rule
func exportSources(graph *core.BuildGraph, dir string, target *core.BuildTarget) {
func (e *export) exportSources(target *core.BuildTarget) {
for _, src := range append(target.AllSources(), target.AllData()...) {
if _, ok := src.Label(); !ok { // We'll handle these dependencies later
for _, p := range src.FullPaths(graph) {
for _, p := range src.FullPaths(e.state.Graph) {
if !filepath.IsAbs(p) { // Don't copy system file deps.
if err := fs.RecursiveCopy(p, filepath.Join(dir, p), 0); err != nil {
if err := fs.RecursiveCopy(p, filepath.Join(e.targetDir, p), 0); err != nil {
log.Fatalf("Error copying file: %s\n", err)
}
}
Expand All @@ -96,28 +118,65 @@ func exportSources(graph *core.BuildGraph, dir string, target *core.BuildTarget)
}
}

// exportPackage exports the package BUILD file and all sources
func (e *export) exportPackage(pkgName string) {
if pkgName == parse.InternalPackageName {
return
}
if e.exportedPackages[pkgName] {
return
}
e.exportedPackages[pkgName] = true

err := filepath.WalkDir(pkgName, func(path string, d iofs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
if path != pkgName && fs.IsPackage(e.state.Config.Parse.BuildFileName, path) {
return filepath.SkipDir // We want to stop when we find another package in our dir tree
}
return nil
}
if !d.Type().IsRegular() {
return nil // Ignore symlinks, which are almost certainly generated sources.
}
dest := filepath.Join(e.targetDir, path)
if err := fs.EnsureDir(dest); err != nil {
return err
}
return fs.CopyFile(path, dest, 0)
})
if err != nil {
log.Fatalf("failed to export package: %v", 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] {
func (e *export) export(target *core.BuildTarget) {
if e.exportedTargets[target.Label] {
return
}
// We want to export the package that made this subrepo available, but we still need to walk the target deps
// as it may depend on other subrepos or first party targets
if target.Subrepo != nil {
export(graph, dir, target.Subrepo.Target, done)
e.export(target.Subrepo.Target)
} else if e.noTrim {
// Export the whole package, rather than trying to trim the package down to only the targets we need
e.exportPackage(target.Label.PackageName)
} else {
exportSources(graph, dir, target)
e.exportSources(target)
}

done[target] = true
e.exportedTargets[target.Label] = true
for _, dep := range target.Dependencies() {
export(graph, dir, dep, done)
e.export(dep)
}
for _, subinclude := range graph.PackageOrDie(target.Label).AllSubincludes(graph) {
export(graph, dir, graph.TargetOrDie(subinclude), done)
for _, subinclude := range e.state.Graph.PackageOrDie(target.Label).AllSubincludes(e.state.Graph) {
e.export(e.state.Graph.TargetOrDie(subinclude))
}
if parent := target.Parent(graph); parent != nil && parent != target {
export(graph, dir, parent, done)
if parent := target.Parent(e.state.Graph); parent != nil && parent != target {
e.export(parent)
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/please.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ var opts struct {

Export struct {
Output string `short:"o" long:"output" required:"true" description:"Directory to export into"`
NoTrim bool `long:"notrim" description:"export the build file as is, without trying to trim unused targets"`
Args struct {
Targets []core.BuildLabel `positional-arg-name:"targets" description:"Labels to export."`
} `positional-args:"true"`
Expand Down Expand Up @@ -759,7 +760,7 @@ var buildFunctions = map[string]func() int{
"export": func() int {
success, state := runBuild(opts.Export.Args.Targets, false, false, false)
if success {
export.ToDir(state, opts.Export.Output, state.ExpandOriginalLabels())
export.ToDir(state, opts.Export.Output, opts.Export.NoTrim, state.ExpandOriginalLabels())
}
return toExitCode(success, state)
},
Expand Down
Loading