Skip to content
Open
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
0ef91bc
Package level metadata that includes a mapping of build statements to…
Mar 27, 2026
63f1b0d
export using BuildFileMetadata logic
Mar 27, 2026
419bd56
register caller scope for callstack-like traversal
Apr 7, 2026
8e1bd00
bufio writer for build statements
Apr 7, 2026
258b170
rewrite export logic into explicit flow
Apr 20, 2026
4110735
export targets related to build statement
Apr 20, 2026
a4252c9
enrich target with subincludes by looping though all scopes
Apr 20, 2026
82f117f
separate buildstmt register from adding target
Apr 20, 2026
eb657de
select and write subincludes
Apr 20, 2026
6535794
skip statement for preloaded subincludes
Apr 21, 2026
8e6c9c0
test: trim subincludes
Apr 21, 2026
9f0b4fe
rename file
Apr 21, 2026
0e597c6
use slices.collect and sort interface
Apr 21, 2026
de76e2c
rewrite export with 2 concrete interfaces: default and notrim
Apr 22, 2026
03ed361
notrim: full copy BUILD file and visit sources
Apr 22, 2026
717aba1
double new lines between targets
Apr 22, 2026
94160bf
suppress diff output when enforcing repo differences
Apr 24, 2026
582319e
export by filtering the original BUILD file
Apr 24, 2026
e6a5293
subincludes use label short string
Apr 24, 2026
ea329c3
Simplify package filtering method into a more explicit "switch" case
Apr 24, 2026
1a47c22
skip subrepos and internal packages when writing package file
Apr 24, 2026
a35119a
fix reusing err var resulted in failed filtering
Apr 24, 2026
9c1522c
doc strings for package metadata
Apr 26, 2026
9395a59
export missing doc strings
Apr 26, 2026
3c3d3d0
test: named go_repo and change testify for slimmer UUID
Apr 29, 2026
13e95cb
export dependencies of subrepos - 13/14 tests passing
Apr 29, 2026
28b5441
test: internal repo test using temp directory to avoid stale data
Apr 29, 2026
781af3a
fix: 0 label subinclude
Apr 29, 2026
2f8355c
adjusting dependency lookup and adjacent target test to include secon…
Apr 29, 2026
3e89c85
test: add custom tool to native test
Apr 30, 2026
9c5af3e
test: go_test export with several deps
Apr 30, 2026
922da6f
optional metadata parsing
May 1, 2026
5aeb360
test: minimal subinclude statement
May 1, 2026
517486a
collect map keys on active subinclude labels
May 1, 2026
f8f8e3f
non-fatal warning for missing source while exporting
May 1, 2026
8aa98e3
skip internal package export
May 1, 2026
5fa64f4
move some fatal to error and continue
May 1, 2026
e60dbb6
missing docstrings
May 1, 2026
c7409ab
run go fmt and plz fmt
May 1, 2026
be87020
move to error and continue for target lookup
May 1, 2026
6f73f78
rename new parser method on test files
May 1, 2026
762c016
use pkg.Metadata directly and remove intermediate pkg methods
May 11, 2026
406f95a
mutex in packagemetadata
May 12, 2026
b86ff9f
update stmt provider to avoid dereference
May 12, 2026
c7cd118
NewPackage with variadic optional functions
May 12, 2026
faf8c33
infof to debugf
May 12, 2026
dd8cfca
package metadata doc comments improvements
May 12, 2026
084f233
improve doc comments and adjust method visibility for export.go
May 12, 2026
bf0f734
hide build output when testing export
May 12, 2026
33d2bc2
open and write of exported package file merged into the same method
May 12, 2026
54f577c
update export_test.go with suggestions
May 12, 2026
ae5f520
apply review suggestions to export.go
May 13, 2026
5f0e549
rename and doc fields for scope
May 13, 2026
e59ab5b
revert new line change of target
May 14, 2026
917fe61
set builtin code filename for scope for debugging
May 14, 2026
b012ab8
Rework packagemetadata to return empty slices or nil instead of error…
May 14, 2026
2edfee0
linter fix imports
May 14, 2026
f59b5d0
ensure subrepo target exists. Failing to export //... on this repo
May 14, 2026
790a437
go test for filtered package
May 15, 2026
f589998
Add doc comments for providers in asp.interpreter
May 15, 2026
75521e2
test: function def in package file
May 15, 2026
2e2edde
unit testing current statement and active subincludes
May 15, 2026
0e74e53
remove nested maps and pointers in favor of using build labels
May 18, 2026
ef76bca
unexport noTrim implementation
May 18, 2026
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
3 changes: 1 addition & 2 deletions src/BUILD.plz
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ go_binary(
deps = [
"///third_party/go/github.com_thought-machine_go-flags//:go-flags",
"///third_party/go/go.uber.org_automaxprocs//maxprocs",
"//src/audit",
"//src/assets",
"//src/audit",
"//src/build",
"//src/cache",
"//src/clean",
Expand All @@ -29,7 +29,6 @@ go_binary(
"//src/help",
"//src/metrics",
"//src/output",
"//src/parse",
"//src/plz",
"//src/plzinit",
"//src/process",
Expand Down
13 changes: 13 additions & 0 deletions src/core/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type Package struct {
targets map[string]*BuildTarget
// Set of output files from rules.
Outputs map[string]*BuildTarget
// Includes metadata from parsing the package BUILD file.
Metadata PackageMetadata
// Protects access to above
mutex sync.RWMutex
}
Expand All @@ -43,13 +45,24 @@ func NewPackage(name string) *Package {
return NewPackageSubrepo(name, "")
}

// NewPackageWithOpts constructs a new package with the given name, and enables additional features
// given the flags enabled in the build state.
func NewPackageWithOpts(state *BuildState, name string) *Package {
Comment thread
DuBento marked this conversation as resolved.
Outdated
pkg := NewPackage(name)
if state.ParseMetadata {
pkg.Metadata = newPackageMetadata()
}
Comment thread
DuBento marked this conversation as resolved.
return pkg
}

// NewPackageSubrepo constructs a new package with the given name and subrepo.
func NewPackageSubrepo(name, subrepo string) *Package {
return &Package{
Name: name,
SubrepoName: subrepo,
targets: map[string]*BuildTarget{},
Outputs: map[string]*BuildTarget{},
Metadata: newNoopPackageMetadata(),
}
}

Expand Down
154 changes: 154 additions & 0 deletions src/core/package_metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package core

import (
"fmt"
"slices"
)

// BuildStatement represents the start and end byte positions of a parsed statement in a BUILD file.
type BuildStatement struct {
Start, End int
}

// Len returns the byte length of the build statement.
func (bs *BuildStatement) Len() int64 {
return int64(bs.End - bs.Start)
}

// StartPos returns the starting byte position of the build statement.
func (bs *BuildStatement) StartPos() int64 {
return int64(bs.Start)
}

// BuildStatements is a slice of BuildStatement that implements sort.Interface.
type BuildStatements []BuildStatement

func (s BuildStatements) Len() int { return len(s) }
func (s BuildStatements) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s BuildStatements) Less(i, j int) bool { return s[i].StartPos() < s[j].StartPos() }

// BuildStatementProvider is a type for methods that generate new build statements.
type BuildStatementProvider func() *BuildStatement

// SubincludesLabelProvider is a type for methods that generate labels from a subincludes.
type SubincludesLabelProvider func() BuildLabels
Comment thread
DuBento marked this conversation as resolved.
Outdated

// PackageMetadata stores metadata about parsed BUILD files, mapping statements and subincludes
// to their respective targets.
type PackageMetadata interface {
// RegisterStatementTarget maps a build statement to a target it generated.
Comment thread
DuBento marked this conversation as resolved.
Outdated
RegisterStatementTarget(target *BuildTarget, stmtProvider BuildStatementProvider)
// RegisterRequiredSubinclude maps a target to the subincludes required to build it.
RegisterRequiredSubinclude(target *BuildTarget, labelProvider SubincludesLabelProvider)
// RegisterSubincludeStmt maps a subinclude statement to a label it includes.
RegisterSubincludeStmt(label BuildLabel, stmtProvider BuildStatementProvider)
// FindStatement returns the build statement that generated the given target.
FindStatement(target *BuildTarget) (*BuildStatement, error)
// FindTargets returns all targets generated by the given build statement.
FindTargets(stmt *BuildStatement) ([]*BuildTarget, error)
// FindRequiredSubincludes returns all subinclude labels required by the given target.
FindRequiredSubincludes(target *BuildTarget) (BuildLabels, error)
// GetSubincludedLabels returns the labels included by a given subinclude statement.
GetSubincludedLabels(stmt *BuildStatement) (BuildLabels, bool)
}

// packageMetadataImpl stores metadata about parsed BUILD files, mapping statements and subincludes
// to their respective targets.
type packageMetadataImpl struct {
// a list of targets generated from each built statement
StmtToTarget map[BuildStatement][]*BuildTarget
// the subincluded label dependencies per target
TargetToSubinclude map[*BuildTarget]BuildLabels
// all the labels included for each subincludes statement
LabelsPerSubincludeStmt map[BuildStatement]BuildLabels
}

func newPackageMetadata() PackageMetadata {
return &packageMetadataImpl{
StmtToTarget: map[BuildStatement][]*BuildTarget{},
TargetToSubinclude: map[*BuildTarget]BuildLabels{},
LabelsPerSubincludeStmt: map[BuildStatement]BuildLabels{},
}
}

// RegisterStatementTarget maps a build statement to a target it generated.
func (bfm *packageMetadataImpl) RegisterStatementTarget(target *BuildTarget, stmtProvider BuildStatementProvider) {
stmt := stmtProvider()
bfm.StmtToTarget[*stmt] = append(bfm.StmtToTarget[*stmt], target)
Comment thread
DuBento marked this conversation as resolved.
Outdated
}

// RegisterRequiredSubinclude maps a target to the subincludes required to build it.
func (bfm *packageMetadataImpl) RegisterRequiredSubinclude(target *BuildTarget, labelProvider SubincludesLabelProvider) {
labels := labelProvider()
if len(labels) == 0 {
log.Infof("Attempted to register empty subinclude labels for target %s", target.String())
Comment thread
DuBento marked this conversation as resolved.
Outdated
return
}

bfm.TargetToSubinclude[target] = append(bfm.TargetToSubinclude[target], labels...)
}

// RegisterSubincludeStmt maps a subinclude statement to a label it includes.
func (bfm *packageMetadataImpl) RegisterSubincludeStmt(label BuildLabel, stmtProvider BuildStatementProvider) {
stmt := stmtProvider()
bfm.LabelsPerSubincludeStmt[*stmt] = append(bfm.LabelsPerSubincludeStmt[*stmt], label)
}

// FindStatement returns the build statement that generated the given target.
func (bfm *packageMetadataImpl) FindStatement(target *BuildTarget) (*BuildStatement, error) {
for stmt, targets := range bfm.StmtToTarget {
if slices.Contains(targets, target) {
return &stmt, nil
}
}
return nil, fmt.Errorf("Target %s not found in statement metadata.", target.String())
}

// FindTargets returns all targets generated by the given build statement.
func (bfm *packageMetadataImpl) FindTargets(stmt *BuildStatement) ([]*BuildTarget, error) {
targets, ok := bfm.StmtToTarget[*stmt]
if !ok {
return nil, fmt.Errorf("Targets not found for statement %v.", stmt)
}
return targets, nil
}

// FindRequiredSubincludes returns all subinclude labels required by the given target.
func (bfm *packageMetadataImpl) FindRequiredSubincludes(target *BuildTarget) (BuildLabels, error) {
subincludes, ok := bfm.TargetToSubinclude[target]
if !ok {
return nil, fmt.Errorf("Subincludes not found for target %v.", target)
}
return subincludes, nil
}

// GetSubincludedLabels returns the labels included by a given subinclude statement.
func (bfm *packageMetadataImpl) GetSubincludedLabels(stmt *BuildStatement) (BuildLabels, bool) {
v, ok := bfm.LabelsPerSubincludeStmt[*stmt]
return v, ok
}

type noopPackageMetadata struct{}

func newNoopPackageMetadata() PackageMetadata {
return &noopPackageMetadata{}
}

func (n *noopPackageMetadata) RegisterStatementTarget(target *BuildTarget, stmtProvider BuildStatementProvider) {
}
func (n *noopPackageMetadata) RegisterRequiredSubinclude(target *BuildTarget, labelProvider SubincludesLabelProvider) {
}
func (n *noopPackageMetadata) RegisterSubincludeStmt(label BuildLabel, stmtProvider BuildStatementProvider) {
}
func (n *noopPackageMetadata) FindStatement(target *BuildTarget) (*BuildStatement, error) {
return nil, fmt.Errorf("metadata not tracked")
}
func (n *noopPackageMetadata) FindTargets(stmt *BuildStatement) ([]*BuildTarget, error) {
return nil, fmt.Errorf("metadata not tracked")
}
func (n *noopPackageMetadata) FindRequiredSubincludes(target *BuildTarget) (BuildLabels, error) {
return nil, fmt.Errorf("metadata not tracked")
}
func (n *noopPackageMetadata) GetSubincludedLabels(stmt *BuildStatement) (BuildLabels, bool) {
return nil, false
}
2 changes: 2 additions & 0 deletions src/core/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ type BuildState struct {
// NeedDebugDeps is true if we're doing a `plz debug` and we need to build the debug tools and
// data
NeedDebugDeps bool
// ParseMetadata is true if we want to store build file metadata
ParseMetadata bool

// initOnce is used to control loading the subrepo .plzconfig
initOnce *sync.Once
Expand Down
13 changes: 12 additions & 1 deletion src/export/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@ go_library(
pgo_file = "//:pgo",
visibility = ["PUBLIC"],
deps = [
"///third_party/go/github.com_please-build_buildtools//build",
"//src/cli/logging",
"//src/core",
"//src/fs",
"//src/gc",
"//src/parse",
"//src/parse/asp",
],
)

go_test(
name = "export_test",
srcs = ["export_test.go"],
deps = [
":export",
"///third_party/go/github.com_stretchr_testify//assert",
"//src/core",
],
)
Loading
Loading