diff --git a/src/build/filegroup.go b/src/build/filegroup.go index 2347e8181..e9b554a33 100644 --- a/src/build/filegroup.go +++ b/src/build/filegroup.go @@ -108,8 +108,8 @@ func buildFilegroup(state *core.BuildState, target *core.BuildTarget) (bool, err } changed := false outDir := target.OutDir() - localSources := target.AllSourceLocalPaths(state.Graph) - for i, source := range target.AllSourceFullPaths(state.Graph) { + localSources := target.AllSourceLocalPaths(state.Graph, state.Config.FeatureFlags.FFDefaultProvides) + for i, source := range target.AllSourceFullPaths(state.Graph, state.Config.FeatureFlags.FFDefaultProvides) { out := filepath.Join(outDir, localSources[i]) fileChanged, err := theFilegroupBuilder.Build(state, target, source, out) if err != nil { @@ -154,8 +154,8 @@ func buildFilegroup(state *core.BuildState, target *core.BuildTarget) (bool, err // This is a small optimisation to ensure we don't need to recalculate them unnecessarily. func copyFilegroupHashes(state *core.BuildState, target *core.BuildTarget) { outDir := target.OutDir() - localSources := target.AllSourceLocalPaths(state.Graph) - for i, source := range target.AllSourceFullPaths(state.Graph) { + localSources := target.AllSourceLocalPaths(state.Graph, state.Config.FeatureFlags.FFDefaultProvides) + for i, source := range target.AllSourceFullPaths(state.Graph, state.Config.FeatureFlags.FFDefaultProvides) { if out := filepath.Join(outDir, localSources[i]); out != source { state.PathHasher.CopyHash(source, out) } diff --git a/src/core/build_env.go b/src/core/build_env.go index 8e03806f1..873cf9d88 100644 --- a/src/core/build_env.go +++ b/src/core/build_env.go @@ -69,7 +69,7 @@ func TargetEnvironment(state *BuildState, target *BuildTarget) BuildEnv { // We read this as being slightly more POSIX-compliant than not having it set at all... func BuildEnvironment(state *BuildState, target *BuildTarget, tmpDir string) BuildEnv { env := TargetEnvironment(state, target) - sources := target.AllSourcePaths(state.Graph) + sources := target.AllSourcePaths(state.Graph, state.Config.FeatureFlags.FFDefaultProvides) outEnv := target.GetTmpOutputAll(target.Outputs()) abs := filepath.IsAbs(tmpDir) @@ -92,7 +92,7 @@ func BuildEnvironment(state *BuildState, target *BuildTarget, tmpDir string) Bui } // Named source groups if the target declared any. for name, srcs := range target.NamedSources { - paths := target.SourcePaths(state.Graph, srcs) + paths := target.SourcePaths(state.Graph, srcs, state.Config.FeatureFlags.FFDefaultProvides) // TODO(macripps): Quote these to prevent spaces from breaking everything (consider joining with NUL or sth?) env = append(env, "SRCS_"+strings.ToUpper(name)+"="+strings.Join(paths, " ")) } diff --git a/src/core/build_target.go b/src/core/build_target.go index faf37952b..938950f57 100644 --- a/src/core/build_target.go +++ b/src/core/build_target.go @@ -491,28 +491,28 @@ func (target *BuildTarget) StartTestSuite() { } // AllSourcePaths returns all the source paths for this target -func (target *BuildTarget) AllSourcePaths(graph *BuildGraph) []string { - return target.allSourcePaths(graph, BuildInput.Paths) +func (target *BuildTarget) AllSourcePaths(graph *BuildGraph, ffDefaultProvide bool) []string { + return target.allSourcePaths(graph, BuildInput.Paths, ffDefaultProvide) } // AllSourceFullPaths returns all the source paths for this target, with a leading // plz-out/gen etc if appropriate. -func (target *BuildTarget) AllSourceFullPaths(graph *BuildGraph) []string { - return target.allSourcePaths(graph, BuildInput.FullPaths) +func (target *BuildTarget) AllSourceFullPaths(graph *BuildGraph, ffDefaultProvide bool) []string { + return target.allSourcePaths(graph, BuildInput.FullPaths, ffDefaultProvide) } // AllSourceLocalPaths returns the local part of all the source paths for this target, // i.e. without this target's package in it. -func (target *BuildTarget) AllSourceLocalPaths(graph *BuildGraph) []string { - return target.allSourcePaths(graph, BuildInput.LocalPaths) +func (target *BuildTarget) AllSourceLocalPaths(graph *BuildGraph, ffDefaultProvide bool) []string { + return target.allSourcePaths(graph, BuildInput.LocalPaths, ffDefaultProvide) } type buildPathsFunc func(BuildInput, *BuildGraph) []string -func (target *BuildTarget) allSourcePaths(graph *BuildGraph, full buildPathsFunc) []string { +func (target *BuildTarget) allSourcePaths(graph *BuildGraph, full buildPathsFunc, ffDefaultProvide bool) []string { ret := make([]string, 0, len(target.Sources)) for _, source := range target.AllSources() { - ret = append(ret, target.sourcePaths(graph, source, full)...) + ret = append(ret, target.sourcePaths(graph, source, full, ffDefaultProvide)...) } return ret } @@ -533,7 +533,7 @@ func (target *BuildTarget) AllURLs(state *BuildState) []string { // TODO(peterebden,tatskaari): Work out if we really want to have this and how the suite of *Dependencies functions // // below should behave (preferably nicely). -func (target *BuildTarget) resolveDependencies(graph *BuildGraph, callback func(*BuildTarget) error) error { +func (target *BuildTarget) resolveDependencies(graph *BuildGraph, callback func(*BuildTarget) error, ffDefaultProvide bool) error { var g errgroup.Group target.mutex.RLock() for i := range target.dependencies { @@ -542,7 +542,7 @@ func (target *BuildTarget) resolveDependencies(graph *BuildGraph, callback func( continue // already done } g.Go(func() error { - if err := target.resolveOneDependency(graph, dep); err != nil { + if err := target.resolveOneDependency(graph, dep, ffDefaultProvide); err != nil { return err } for _, d := range dep.deps { @@ -557,14 +557,15 @@ func (target *BuildTarget) resolveDependencies(graph *BuildGraph, callback func( return g.Wait() } -func (target *BuildTarget) resolveOneDependency(graph *BuildGraph, dep *depInfo) error { +func (target *BuildTarget) resolveOneDependency(graph *BuildGraph, dep *depInfo, ffDefaultProvide bool) error { t := graph.WaitForTarget(*dep.declared) if t == nil { return fmt.Errorf("Couldn't find dependency %s", dep.declared) } dep.declared = &t.Label // saves memory by not storing the label twice once resolved - labels := t.provideFor(target) + // TODO(jpoole): shouldn't this use the ProvideFor wrapper that handles resolving to self if there's no match? + labels := t.provideFor(target, ffDefaultProvide) if len(labels) == 0 { target.mutex.Lock() @@ -595,7 +596,7 @@ func (target *BuildTarget) resolveOneDependency(graph *BuildGraph, dep *depInfo) // MustResolveDependencies is exposed only for testing purposes. // TODO(peterebden, tatskaari): See if we can get rid of this. func (target *BuildTarget) ResolveDependencies(graph *BuildGraph) error { - return target.resolveDependencies(graph, func(*BuildTarget) error { return nil }) + return target.resolveDependencies(graph, func(*BuildTarget) error { return nil }, false) } // DeclaredDependencies returns all the targets this target declared any kind of dependency on (including sources and tools). @@ -880,19 +881,19 @@ func (target *BuildTarget) GetRealOutput(output string) string { } // SourcePaths returns the source paths for a given set of sources. -func (target *BuildTarget) SourcePaths(graph *BuildGraph, sources []BuildInput) []string { +func (target *BuildTarget) SourcePaths(graph *BuildGraph, sources []BuildInput, ffDefaultProvide bool) []string { ret := make([]string, 0, len(sources)) for _, source := range sources { - ret = append(ret, target.sourcePaths(graph, source, BuildInput.Paths)...) + ret = append(ret, target.sourcePaths(graph, source, BuildInput.Paths, ffDefaultProvide)...) } return ret } // sourcePaths returns the source paths for a single source. -func (target *BuildTarget) sourcePaths(graph *BuildGraph, source BuildInput, f buildPathsFunc) []string { +func (target *BuildTarget) sourcePaths(graph *BuildGraph, source BuildInput, f buildPathsFunc, ffDefaultProvide bool) []string { if label, ok := source.nonOutputLabel(); ok { ret := []string{} - for _, providedLabel := range graph.TargetOrDie(label).ProvideFor(target) { + for _, providedLabel := range graph.TargetOrDie(label).ProvideFor(target, ffDefaultProvide) { ret = append(ret, f(providedLabel, graph)...) } return ret @@ -1195,8 +1196,8 @@ func (target *BuildTarget) AddProvide(language string, label BuildLabel) { } // ProvideFor returns the build label that we'd provide for the given target. -func (target *BuildTarget) ProvideFor(other *BuildTarget) []BuildLabel { - if p := target.provideFor(other); len(p) > 0 { +func (target *BuildTarget) ProvideFor(other *BuildTarget, ffDefaultProvide bool) []BuildLabel { + if p := target.provideFor(other, ffDefaultProvide); len(p) > 0 { return p } return []BuildLabel{target.Label} @@ -1204,11 +1205,16 @@ func (target *BuildTarget) ProvideFor(other *BuildTarget) []BuildLabel { // provideFor is like ProvideFor but returns an empty slice if there is a direct dependency. // It's a small optimisation to save allocating extra slices. -func (target *BuildTarget) provideFor(other *BuildTarget) []BuildLabel { +func (target *BuildTarget) provideFor(other *BuildTarget, ffDefaultProvide bool) []BuildLabel { target.mutex.RLock() defer target.mutex.RUnlock() + var defaultValue []BuildLabel + if def, ok := target.Provides["default"]; ok && ffDefaultProvide { + defaultValue = []BuildLabel{def} + } + if target.Provides == nil || len(other.Requires) == 0 { - return nil + return defaultValue } // Never do this if the other target has a data or tool dependency on us. for _, data := range other.Data { @@ -1228,6 +1234,10 @@ func (target *BuildTarget) provideFor(other *BuildTarget) []BuildLabel { ret = append(ret, label) } } + + if len(ret) == 0 { + return defaultValue + } return ret } diff --git a/src/core/build_target_benchmark_test.go b/src/core/build_target_benchmark_test.go index fbeed9e8d..5557d30b4 100644 --- a/src/core/build_target_benchmark_test.go +++ b/src/core/build_target_benchmark_test.go @@ -17,7 +17,7 @@ func BenchmarkProvideFor(b *testing.B) { b.Run("Simple", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - result = target1.provideFor(target2) + result = target1.provideFor(target2, true) } }) @@ -26,7 +26,7 @@ func BenchmarkProvideFor(b *testing.B) { b.Run("NoMatch", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - result = target2.provideFor(target1) + result = target2.provideFor(target1, true) } }) @@ -35,7 +35,7 @@ func BenchmarkProvideFor(b *testing.B) { b.Run("OneMatch", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - result = target2.provideFor(target1) + result = target2.provideFor(target1, true) } }) @@ -43,7 +43,7 @@ func BenchmarkProvideFor(b *testing.B) { b.Run("TwoMatches", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - result = target2.provideFor(target1) + result = target2.provideFor(target1, true) } }) @@ -52,7 +52,7 @@ func BenchmarkProvideFor(b *testing.B) { b.Run("FourMatches", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - result = target2.provideFor(target1) + result = target2.provideFor(target1, true) } }) @@ -60,7 +60,7 @@ func BenchmarkProvideFor(b *testing.B) { b.Run("IsData", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - result = target2.provideFor(target1) + result = target2.provideFor(target1, true) } }) } diff --git a/src/core/build_target_test.go b/src/core/build_target_test.go index ed6186ef4..273cf10d0 100644 --- a/src/core/build_target_test.go +++ b/src/core/build_target_test.go @@ -219,18 +219,41 @@ func TestProvideFor(t *testing.T) { // target1 is provided directly since they have a simple dependency target1 := makeTarget1("//src/core:target1", "PUBLIC") target2 := makeTarget1("//src/core:target2", "PUBLIC", target1) - assert.Equal(t, []BuildLabel{target1.Label}, target1.ProvideFor(target2)) + assert.Equal(t, []BuildLabel{target1.Label}, target1.ProvideFor(target2, true)) // Now have target2 provide target1. target3 will get target1 instead. target2.Provides = map[string]BuildLabel{"whatevs": target1.Label} target3 := makeTarget1("//src/core:target3", "PUBLIC", target2) target3.Requires = append(target3.Requires, "whatevs") - assert.Equal(t, []BuildLabel{target1.Label}, target2.ProvideFor(target3)) + assert.Equal(t, []BuildLabel{target1.Label}, target2.ProvideFor(target3, true)) // Now target4 has a data dependency on target2. It has the same requirement as target3 but // it gets target2 instead of target1, because that's just how data deps work. target4 := makeTarget1("//src/core:target4", "PUBLIC", target2) target4.Data = append(target4.Data, target2.Label) target4.Requires = append(target4.Requires, "whatevs") - assert.Equal(t, []BuildLabel{target2.Label}, target2.ProvideFor(target4)) + assert.Equal(t, []BuildLabel{target2.Label}, target2.ProvideFor(target4, true)) +} + +func TestDefaultProvide(t *testing.T) { + goTarget := makeTarget1("//src/core:go", "PUBLIC") + defaultTarget := makeTarget1("//src/core:default", "PUBLIC") + providesGo := makeTarget1("//src/core:provider", "PUBLIC", goTarget, defaultTarget) + + requireGo := makeTarget1("//src/core:req_go", "PUBLIC") + requirePython := makeTarget1("//src/core:req_python", "PUBLIC") + requireNothing := makeTarget1("//src/core:req_none", "PUBLIC") + + requireGo.Requires = []string{"go"} + requirePython.Requires = []string{"python"} + + providesGo.Provides = map[string]BuildLabel{ + "go": goTarget.Label, + "default": defaultTarget.Label, + } + + assert.Equal(t, []BuildLabel{defaultTarget.Label}, providesGo.ProvideFor(requirePython, true)) + assert.Equal(t, []BuildLabel{defaultTarget.Label}, providesGo.ProvideFor(requireNothing, true)) + assert.Equal(t, []BuildLabel{providesGo.Label}, providesGo.ProvideFor(requirePython, false)) + assert.Equal(t, []BuildLabel{goTarget.Label}, providesGo.ProvideFor(requireGo, true)) } func TestAddProvide(t *testing.T) { @@ -240,7 +263,7 @@ func TestAddProvide(t *testing.T) { target2.AddDependency(target1.Label) target2.AddProvide("go", ParseBuildLabel(":target1", "src/core")) target3.Requires = append(target3.Requires, "go") - assert.Equal(t, []BuildLabel{target1.Label}, target2.ProvideFor(target3)) + assert.Equal(t, []BuildLabel{target1.Label}, target2.ProvideFor(target3, true)) } func TestAddDatum(t *testing.T) { diff --git a/src/core/config.go b/src/core/config.go index df90be573..972d64daf 100644 --- a/src/core/config.go +++ b/src/core/config.go @@ -688,6 +688,7 @@ type Configuration struct { buildEnvStored *storedBuildEnv FeatureFlags struct { + FFDefaultProvides bool `help:"Allows setting 'default' in the provides map to control what happens when none of the provided targets match"` } `help:"Flags controlling preview features for the next release. Typically these config options gate breaking changes and only have a lifetime of one major release."` Metrics struct { PrometheusGatewayURL string `help:"The gateway URL to push prometheus updates to."` diff --git a/src/core/graph.go b/src/core/graph.go index e2ae1b19d..58feab212 100644 --- a/src/core/graph.go +++ b/src/core/graph.go @@ -157,10 +157,10 @@ func NewGraph() *BuildGraph { // DependentTargets returns the labels that 'from' should actually depend on when it declared a dependency on 'to'. // This is normally just 'to' but could be otherwise given require/provide shenanigans. -func (graph *BuildGraph) DependentTargets(from, to BuildLabel) []BuildLabel { +func (graph *BuildGraph) DependentTargets(from, to BuildLabel, ffDefaultProvide bool) []BuildLabel { fromTarget := graph.Target(from) if toTarget := graph.Target(to); fromTarget != nil && toTarget != nil { - return toTarget.ProvideFor(fromTarget) + return toTarget.ProvideFor(fromTarget, ffDefaultProvide) } return []BuildLabel{to} } diff --git a/src/core/graph_test.go b/src/core/graph_test.go index e6b108f0d..cc1510179 100644 --- a/src/core/graph_test.go +++ b/src/core/graph_test.go @@ -39,7 +39,7 @@ func TestDependentTargets(t *testing.T) { graph.AddTarget(target1) graph.AddTarget(target2) graph.AddTarget(target3) - assert.Equal(t, []BuildLabel{target3.Label}, graph.DependentTargets(target2.Label, target1.Label)) + assert.Equal(t, []BuildLabel{target3.Label}, graph.DependentTargets(target2.Label, target1.Label, true)) } func TestSubrepo(t *testing.T) { diff --git a/src/core/state.go b/src/core/state.go index a0f0c6934..8d466d69d 100644 --- a/src/core/state.go +++ b/src/core/state.go @@ -1034,7 +1034,7 @@ func (state *BuildState) ActivateTarget(pkg *Package, label, dependent BuildLabe } } } else { - for _, l := range state.Graph.DependentTargets(dependent, label) { + for _, l := range state.Graph.DependentTargets(dependent, label, state.Config.FeatureFlags.FFDefaultProvides) { // We use :all to indicate a dependency needed for parse. if err := state.QueueTarget(l, dependent, dependent.IsAllTargets(), mode); err != nil { return err @@ -1088,7 +1088,7 @@ func (state *BuildState) queueTarget(label, dependent BuildLabel, forceBuild boo if dependent.IsAllTargets() || dependent == OriginalTarget { return state.queueResolvedTarget(target, forceBuild, mode) } - for _, l := range target.ProvideFor(state.Graph.TargetOrDie(dependent)) { + for _, l := range target.ProvideFor(state.Graph.TargetOrDie(dependent), state.Config.FeatureFlags.FFDefaultProvides) { if l == label { if err := state.queueResolvedTarget(target, forceBuild, mode); err != nil { return err @@ -1167,7 +1167,7 @@ func (state *BuildState) queueTargetAsync(target *BuildTarget, forceBuild, build if err := target.resolveDependencies(state.Graph, func(t *BuildTarget) error { called.SetTrue() return state.queueResolvedTarget(t, forceBuild, ParseModeNormal) - }); err != nil { + }, state.Config.FeatureFlags.FFDefaultProvides); err != nil { state.asyncError(target.Label, err) return } diff --git a/src/core/utils.go b/src/core/utils.go index 1dabc5582..9bfa6c152 100644 --- a/src/core/utils.go +++ b/src/core/utils.go @@ -153,7 +153,7 @@ func IterInputs(state *BuildState, graph *BuildGraph, target *BuildTarget, inclu done[dependency.Label] = true if target == dependency || (target.NeedsTransitiveDependencies && !dependency.OutputIsComplete) { for _, dep := range dependency.BuildDependencies() { - for _, dep2 := range recursivelyProvideFor(graph, target, dependency, dep.Label) { + for _, dep2 := range recursivelyProvideFor(graph, target, dependency, dep.Label, state.Config.FeatureFlags.FFDefaultProvides) { if !done[dep2] && !dependency.IsTool(dep2) { inner(graph.TargetOrDie(dep2)) } @@ -161,7 +161,7 @@ func IterInputs(state *BuildState, graph *BuildGraph, target *BuildTarget, inclu } } else { for _, dep := range dependency.ExportedDependencies() { - for _, dep2 := range recursivelyProvideFor(graph, target, dependency, dep) { + for _, dep2 := range recursivelyProvideFor(graph, target, dependency, dep, state.Config.FeatureFlags.FFDefaultProvides) { if !done[dep2] { inner(graph.TargetOrDie(dep2)) } @@ -171,11 +171,11 @@ func IterInputs(state *BuildState, graph *BuildGraph, target *BuildTarget, inclu } go func() { for _, source := range target.AllSources() { - recursivelyProvideSource(graph, target, source, ch) + recursivelyProvideSource(graph, target, source, ch, state.Config.FeatureFlags.FFDefaultProvides) } if includeTools { for _, tool := range target.AllTools() { - recursivelyProvideSource(graph, target, tool, ch) + recursivelyProvideSource(graph, target, tool, ch, state.Config.FeatureFlags.FFDefaultProvides) } } if !sourcesOnly { @@ -187,14 +187,14 @@ func IterInputs(state *BuildState, graph *BuildGraph, target *BuildTarget, inclu } // recursivelyProvideFor recursively applies ProvideFor to a target. -func recursivelyProvideFor(graph *BuildGraph, target, dependency *BuildTarget, dep BuildLabel) []BuildLabel { +func recursivelyProvideFor(graph *BuildGraph, target, dependency *BuildTarget, dep BuildLabel, ffDefaultProvide bool) []BuildLabel { depTarget := graph.TargetOrDie(dep) - ret := depTarget.ProvideFor(dependency) + ret := depTarget.ProvideFor(dependency, ffDefaultProvide) if len(ret) == 1 && ret[0] == dep { // Dependency doesn't have a require/provide directly on this guy, up to the top-level // target. We have to check the dep first to keep things consistent with what targets // have actually been built. - ret = depTarget.ProvideFor(target) + ret = depTarget.ProvideFor(target, ffDefaultProvide) if len(ret) == 1 && ret[0] == dep { return ret } @@ -204,16 +204,16 @@ func recursivelyProvideFor(graph *BuildGraph, target, dependency *BuildTarget, d if r == dep { ret2 = append(ret2, r) // Providing itself, don't recurse } else { - ret2 = append(ret2, recursivelyProvideFor(graph, target, dependency, r)...) + ret2 = append(ret2, recursivelyProvideFor(graph, target, dependency, r, ffDefaultProvide)...) } } return ret2 } // recursivelyProvideSource is similar to recursivelyProvideFor but operates on a BuildInput. -func recursivelyProvideSource(graph *BuildGraph, target *BuildTarget, src BuildInput, ch chan BuildInput) { +func recursivelyProvideSource(graph *BuildGraph, target *BuildTarget, src BuildInput, ch chan BuildInput, ffDefaultProvide bool) { if label, ok := src.nonOutputLabel(); ok { - for _, p := range recursivelyProvideFor(graph, target, target, label) { + for _, p := range recursivelyProvideFor(graph, target, target, label, ffDefaultProvide) { ch <- p } return @@ -278,7 +278,7 @@ func IterRuntimeFiles(graph *BuildGraph, target *BuildTarget, absoluteOuts bool, } // IterInputPaths yields all the transitive input files for a rule (sources & data files), similar to above (again). -func IterInputPaths(graph *BuildGraph, target *BuildTarget) <-chan string { +func IterInputPaths(graph *BuildGraph, target *BuildTarget, ffDefaultProvide bool) <-chan string { // Use a couple of maps to protect us from dep-graph loops and to stop parsing the same target // multiple times. We also only want to push files to the channel that it has not already seen. donePaths := map[string]bool{} @@ -305,7 +305,7 @@ func IterInputPaths(graph *BuildGraph, target *BuildTarget) <-chan string { // Otherwise we should recurse for this build label (and gather its sources) } else { t := graph.TargetOrDie(label) - for _, d := range recursivelyProvideFor(graph, target, t, t.Label) { + for _, d := range recursivelyProvideFor(graph, target, t, t.Label, ffDefaultProvide) { inner(graph.TargetOrDie(d)) } } @@ -328,7 +328,7 @@ func IterInputPaths(graph *BuildGraph, target *BuildTarget) <-chan string { // Otherwise we should recurse for this build label (and gather its sources) } else { t := graph.TargetOrDie(label) - for _, d := range recursivelyProvideFor(graph, target, t, t.Label) { + for _, d := range recursivelyProvideFor(graph, target, t, t.Label, ffDefaultProvide) { inner(graph.TargetOrDie(d)) } } @@ -336,7 +336,7 @@ func IterInputPaths(graph *BuildGraph, target *BuildTarget) <-chan string { // Finally recurse for all the deps of this rule. for _, dep := range target.Dependencies() { - for _, d := range recursivelyProvideFor(graph, target, dep, dep.Label) { + for _, d := range recursivelyProvideFor(graph, target, dep, dep.Label, ffDefaultProvide) { inner(graph.TargetOrDie(d)) } } diff --git a/src/please.go b/src/please.go index ad5e58d10..3ae51a1d9 100644 --- a/src/please.go +++ b/src/please.go @@ -785,7 +785,7 @@ var buildFunctions = map[string]func() int{ a := plz.ReadStdinLabels([]core.BuildLabel{opts.Query.SomePath.Args.Target1}) b := plz.ReadStdinLabels([]core.BuildLabel{opts.Query.SomePath.Args.Target2}) return runQuery(true, append(a, b...), func(state *core.BuildState) { - if err := query.SomePath(state.Graph, a, b, opts.Query.SomePath.Except, opts.Query.SomePath.Hidden); err != nil { + if err := query.SomePath(state.Graph, a, b, opts.Query.SomePath.Except, opts.Query.SomePath.Hidden, state.Config.FeatureFlags.FFDefaultProvides); err != nil { fmt.Printf("%s\n", err) os.Exit(1) } @@ -803,7 +803,7 @@ var buildFunctions = map[string]func() int{ }, "query.input": func() int { return runQuery(true, opts.Query.Input.Args.Targets, func(state *core.BuildState) { - query.TargetInputs(state.Graph, state.ExpandOriginalLabels()) + query.TargetInputs(state.Graph, state.ExpandOriginalLabels(), state.Config.FeatureFlags.FFDefaultProvides) }) }, "query.output": func() int { diff --git a/src/query/graph.go b/src/query/graph.go index e15356b31..8a3fc3942 100644 --- a/src/query/graph.go +++ b/src/query/graph.go @@ -148,7 +148,7 @@ func makeJSONPackage(state *core.BuildState, pkg *core.Package) JSONPackage { func makeJSONTarget(state *core.BuildState, target *core.BuildTarget) JSONTarget { t := JSONTarget{ - Sources: makeJSONInputField(state.Graph, target.AllSourcePaths(state.Graph), target.NamedSources), + Sources: makeJSONInputField(state.Graph, target.AllSourcePaths(state.Graph, state.Config.FeatureFlags.FFDefaultProvides), target.NamedSources), Tools: makeJSONInputField(state.Graph, buildInputsToStrings(state.Graph, target.AllTools()), target.AllNamedTools()), } for in := range core.IterSources(state, state.Graph, target, false) { diff --git a/src/query/inputs.go b/src/query/inputs.go index 1cd416742..9e3955c22 100644 --- a/src/query/inputs.go +++ b/src/query/inputs.go @@ -10,10 +10,10 @@ import ( ) // TargetInputs prints all inputs for a single target. -func TargetInputs(graph *core.BuildGraph, labels []core.BuildLabel) { +func TargetInputs(graph *core.BuildGraph, labels []core.BuildLabel, ffDefaultProvide bool) { inputPaths := map[string]bool{} for _, label := range labels { - for sourcePath := range core.IterInputPaths(graph, graph.TargetOrDie(label)) { + for sourcePath := range core.IterInputPaths(graph, graph.TargetOrDie(label), ffDefaultProvide) { inputPaths[sourcePath] = true } } diff --git a/src/query/reverse_deps.go b/src/query/reverse_deps.go index dc60eaf08..02ce4a94c 100644 --- a/src/query/reverse_deps.go +++ b/src/query/reverse_deps.go @@ -81,7 +81,7 @@ type revdeps struct { } // newRevdeps creates a new reverse dependency searcher. revdeps is non-reusable. -func newRevdeps(graph *core.BuildGraph, hidden, followSubincludes bool, maxDepth int) *revdeps { +func newRevdeps(graph *core.BuildGraph, hidden, followSubincludes bool, maxDepth int, ffDefaultProvide bool) *revdeps { // Initialise a map of labels to the packages that subinclude them upfront so we can include those targets as // dependencies efficiently later subincludes := make(map[core.BuildLabel][]*core.Package) @@ -94,7 +94,7 @@ func newRevdeps(graph *core.BuildGraph, hidden, followSubincludes bool, maxDepth } return &revdeps{ - revdeps: buildRevdeps(graph), + revdeps: buildRevdeps(graph, ffDefaultProvide), subincludes: subincludes, followSubincludes: followSubincludes, os: &openSet{ @@ -107,7 +107,7 @@ func newRevdeps(graph *core.BuildGraph, hidden, followSubincludes bool, maxDepth } // buildRevdeps builds the reverse dependency map from a build graph. -func buildRevdeps(graph *core.BuildGraph) map[core.BuildLabel][]*core.BuildTarget { +func buildRevdeps(graph *core.BuildGraph, ffDefaultProvide bool) map[core.BuildLabel][]*core.BuildTarget { targets := graph.AllTargets() revdeps := make(map[core.BuildLabel][]*core.BuildTarget, len(targets)) for _, t := range targets { @@ -115,7 +115,7 @@ func buildRevdeps(graph *core.BuildGraph) map[core.BuildLabel][]*core.BuildTarge if t2 := graph.Target(d); t2 == nil { revdeps[d] = append(revdeps[d], t2) } else { - for _, p := range t2.ProvideFor(t) { + for _, p := range t2.ProvideFor(t, ffDefaultProvide) { revdeps[p] = append(revdeps[p], t) } } @@ -129,7 +129,7 @@ func buildRevdeps(graph *core.BuildGraph) map[core.BuildLabel][]*core.BuildTarge // FindRevdeps will return a set of build targets that are reverse dependencies of the provided labels. func FindRevdeps(state *core.BuildState, targets core.BuildLabels, hidden, followSubincludes bool, depth int) map[*core.BuildTarget]struct{} { - r := newRevdeps(state.Graph, hidden, followSubincludes, depth) + r := newRevdeps(state.Graph, hidden, followSubincludes, depth, state.Config.FeatureFlags.FFDefaultProvides) // Initialise the open set with the original targets for _, label := range targets { target := state.Graph.TargetOrDie(label) diff --git a/src/query/somepath.go b/src/query/somepath.go index 75b91bdc1..4c63aa2ca 100644 --- a/src/query/somepath.go +++ b/src/query/somepath.go @@ -9,11 +9,12 @@ import ( // SomePath finds and returns a path between two targets, or between one and a set of targets. // Useful for a "why on earth do I depend on this thing" type query. -func SomePath(graph *core.BuildGraph, from, to, except []core.BuildLabel, showHidden bool) error { +func SomePath(graph *core.BuildGraph, from, to, except []core.BuildLabel, showHidden, ffDefaultProvide bool) error { s := somepath{ - graph: graph, - except: make(map[core.BuildLabel]struct{}, len(except)), - memo: map[core.BuildLabel]map[core.BuildLabel]struct{}{}, + graph: graph, + except: make(map[core.BuildLabel]struct{}, len(except)), + memo: map[core.BuildLabel]map[core.BuildLabel]struct{}{}, + ffDefaultProvide: ffDefaultProvide, } for _, ex := range except { s.except[ex] = struct{}{} @@ -58,9 +59,10 @@ func expandAllTargets(graph *core.BuildGraph, labels []core.BuildLabel) []core.B } type somepath struct { - graph *core.BuildGraph - memo map[core.BuildLabel]map[core.BuildLabel]struct{} - except map[core.BuildLabel]struct{} + graph *core.BuildGraph + memo map[core.BuildLabel]map[core.BuildLabel]struct{} + except map[core.BuildLabel]struct{} + ffDefaultProvide bool } func (s *somepath) SomePath(target1, target2 core.BuildLabel) []core.BuildLabel { @@ -77,10 +79,10 @@ func (s *somepath) somePath(target1, target2 core.BuildLabel) []core.BuildLabel m = map[core.BuildLabel]struct{}{} s.memo[target2] = m } - return somePath(s.graph, s.graph.TargetOrDie(target1), s.graph.TargetOrDie(target2), m, s.except) + return somePath(s.graph, s.graph.TargetOrDie(target1), s.graph.TargetOrDie(target2), m, s.except, s.ffDefaultProvide) } -func somePath(graph *core.BuildGraph, target1, target2 *core.BuildTarget, seen, except map[core.BuildLabel]struct{}) []core.BuildLabel { +func somePath(graph *core.BuildGraph, target1, target2 *core.BuildTarget, seen, except map[core.BuildLabel]struct{}, ffDefaultProvide bool) []core.BuildLabel { if target1.Label == target2.Label { return []core.BuildLabel{target1.Label} } else if target1.Parent(graph) == target2 { @@ -97,15 +99,15 @@ func somePath(graph *core.BuildGraph, target1, target2 *core.BuildTarget, seen, if _, present := except[t.Label]; present { continue } - for _, l := range t.ProvideFor(target1) { - if path := somePath(graph, graph.TargetOrDie(l), target2, seen, except); len(path) != 0 { + for _, l := range t.ProvideFor(target1, ffDefaultProvide) { + if path := somePath(graph, graph.TargetOrDie(l), target2, seen, except, ffDefaultProvide); len(path) != 0 { return append([]core.BuildLabel{target1.Label}, path...) } } } } if target1.Subrepo != nil && target1.Subrepo.Target != nil { - if path := somePath(graph, target1.Subrepo.Target, target2, seen, except); len(path) != 0 { + if path := somePath(graph, target1.Subrepo.Target, target2, seen, except, ffDefaultProvide); len(path) != 0 { return append([]core.BuildLabel{target1.Label}, path...) } } diff --git a/src/test/coverage.go b/src/test/coverage.go index 74a4f39d4..e092b2d42 100644 --- a/src/test/coverage.go +++ b/src/test/coverage.go @@ -68,7 +68,7 @@ func collectCoverageFiles(state *core.BuildState, includeAllFiles bool) map[stri func collectAllFiles(state *core.BuildState, target *core.BuildTarget, coverageFiles map[string]bool, includeAllFiles, deps bool, doneTargets map[*core.BuildTarget]bool) { if !doneTargets[target] { doneTargets[target] = true - for _, path := range target.AllSourcePaths(state.Graph) { + for _, path := range target.AllSourcePaths(state.Graph, state.Config.FeatureFlags.FFDefaultProvides) { if hasCoverageExtension(state, path) { coverageFiles[path] = !target.IsTest() && !target.TestOnly // Skip test source files from actual coverage display }