-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support buildfiles function for external repositories in Bazel query #14497
Conversation
@zhengwei143 You've been in this code more than most other people. Can you take a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving comments on overall design and utility to @zhengwei143, just commenting on performance and bugs.
Package pkg = x.getPackage(); | ||
if (seenPackages.add(pkg.getPackageIdentifier())) { | ||
if (x instanceof Rule && pkg.getPackageIdentifier().getCanonicalForm().equals("//external")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use LabelConstants#EXTERNAL_PACKAGE_IDENTIFIER. PackageIdentifiers are interned, so this check becomes instant, as opposed to potentially a character-by-character String equality check (depending on how the JVM canonicalizes string constants).
.toList(); | ||
for (CallStackEntry entry : callStackEntries) { | ||
PathFragment extFile = PathFragment.create(entry.location.file()); | ||
PathFragment workspaceRoot = pkg.getPackageDirectory().asFragment(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please pull this out of the for loop so you're not doing the same work on each iteration.
// External repository rules | ||
if (seenRepos.add(x.getName())) { | ||
ImmutableList<CallStackEntry> callStackEntries = x.getAssociatedRule().getCallStack() | ||
.toList(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: if this is a performance issue, could provide an iterator from CallStack, since you don't need anything else about the immutable list here.
for (CallStackEntry entry : callStackEntries) { | ||
PathFragment extFile = PathFragment.create(entry.location.file()); | ||
PathFragment workspaceRoot = pkg.getPackageDirectory().asFragment(); | ||
if (extFile.startsWith(workspaceRoot)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when does this check fail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the extension file is in an external repo, then this check will fail. For example, if we have this in WORKSPACE
:
load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies")
go_rules_dependencies()
Then the location of the extension file for the target //external:platforms
(which is one of the repos loaded by go_rule_dependencies()
) will be in somewhere like /private/var/tmp/_bazel_zplin/db67431f618bf23018777556a2edc2eb/external/io_bazel_rules_go/go/private/repositories.bzl
, which is outside the workspace root.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't that external bzl file be a valid result if buildfiles returned it, though? I can imagine a user being surprised that only bzl files in the main repository are returned.
ImmutableList<CallStackEntry> callStackEntries = x.getAssociatedRule().getCallStack() | ||
.toList(); | ||
for (CallStackEntry entry : callStackEntries) { | ||
PathFragment extFile = PathFragment.create(entry.location.file()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
couldn't there be duplicates here? Please add a test that covers this situation (the bzl file calls another function in the same file)
if (extFile.startsWith(workspaceRoot)) { | ||
try { | ||
Label extension = Label.create( | ||
extFile.relativeTo(workspaceRoot).getParentDirectory().getPathString(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this construction true? A bzl file can be in a subdirectory of a package. Please add a test for this situation.
' name = "io_bazel_rules_go",', | ||
' sha256 = "2b1641428dff9018f9e85c0384f03ec6c10660d935b750e3fa1492a281a53b0f",', | ||
' urls = [', | ||
' "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.29.0/rules_go-v0.29.0.zip",', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change test to not require network access.
Package pkg = x.getPackage(); | ||
if (seenPackages.add(pkg.getPackageIdentifier())) { | ||
if (x instanceof Rule && pkg.getPackageIdentifier().getCanonicalForm().equals("//external")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will still be incomplete if you have a non-Rule target in a Package, right? You can get a situation with exports_files([...])
or just if the query restricts the output to source files or output files. The package will still be loaded and require those bzl files to work correctly (and since buildfiles
is often used to check if a package needs to be reloaded, that's important), but those bzl files won't be listed here. That makes me think you're doing this at a fundamentally wrong place, although I don't have a better one to suggest since I'm not familiar with external repos. In any case, please add a test for these situations: querying for a source file exported via exports_files([...])
; querying for an output file (the output of a genrule, not the genrule itself); and a query that filters for source files (kind('source_file',...)
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a special case for //external
. The only non-rule target there is WORKSPACE
. For example, from Bazel's own repo:
bazel query 'kind("source file", //external:all-targets)'
//external:WORKSPACE
For genrule
and exports_files
in external repos, their labels are like @some_repo//:data.txt
, which is not in the //external
package, and out of scope of this pull request. I can write tests to cover them, but their behavior in buildfiles
is not affected by this pull request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. Thanks, you can disregard this comment in that case.
Closing in favor of #14630 |
This is an alternative approach to fix #14280. It adds transitive closure of Starlark dependencies to `//external` package when loading `WORKSPACE` file, so it can be processed in the same way as `BUILD` files during query execution. Comparing to the approach taken in #14497, this approach is less intrusive, but not able to distinguish the extension files needed by `//external:foo` and `//external:bar`, meaning `buildfiles(//external:foo)` returns the same result as `buildfiles(//external:*)`. However, this behavior is consistent with other packages. For example, `buildfiles(//foo:bar)` has the same result as `buildfiles(//foo:*)`. Closes #14630. PiperOrigin-RevId: 424092916
This is an alternative approach to fix bazelbuild#14280. It adds transitive closure of Starlark dependencies to `//external` package when loading `WORKSPACE` file, so it can be processed in the same way as `BUILD` files during query execution. Comparing to the approach taken in bazelbuild#14497, this approach is less intrusive, but not able to distinguish the extension files needed by `//external:foo` and `//external:bar`, meaning `buildfiles(//external:foo)` returns the same result as `buildfiles(//external:*)`. However, this behavior is consistent with other packages. For example, `buildfiles(//foo:bar)` has the same result as `buildfiles(//foo:*)`. Closes bazelbuild#14630. PiperOrigin-RevId: 424092916 (cherry picked from commit a6c3f23)
This is an alternative approach to fix bazelbuild#14280. It adds transitive closure of Starlark dependencies to `//external` package when loading `WORKSPACE` file, so it can be processed in the same way as `BUILD` files during query execution. Comparing to the approach taken in bazelbuild#14497, this approach is less intrusive, but not able to distinguish the extension files needed by `//external:foo` and `//external:bar`, meaning `buildfiles(//external:foo)` returns the same result as `buildfiles(//external:*)`. However, this behavior is consistent with other packages. For example, `buildfiles(//foo:bar)` has the same result as `buildfiles(//foo:*)`. Closes bazelbuild#14630. PiperOrigin-RevId: 424092916 (cherry picked from commit a6c3f23)
* Adding Starlark dependencies to the package //external This is an alternative approach to fix #14280. It adds transitive closure of Starlark dependencies to `//external` package when loading `WORKSPACE` file, so it can be processed in the same way as `BUILD` files during query execution. Comparing to the approach taken in #14497, this approach is less intrusive, but not able to distinguish the extension files needed by `//external:foo` and `//external:bar`, meaning `buildfiles(//external:foo)` returns the same result as `buildfiles(//external:*)`. However, this behavior is consistent with other packages. For example, `buildfiles(//foo:bar)` has the same result as `buildfiles(//foo:*)`. Closes #14630. PiperOrigin-RevId: 424092916 (cherry picked from commit a6c3f23) * Avoid bazel_module_test timeout on macos https://buildkite.com/bazel/bazel-bazel/builds/17785#9a1fb564-c6f9-4e69-ac8f-87c422a002b0 By setting the test size to "large". RELNOTES:None PiperOrigin-RevId: 409114345 (cherry picked from commit 1d99391) Co-authored-by: Zhongpeng Lin <zplin@uber.com> Co-authored-by: pcloudy <pcloudy@google.com>
All repository rules are in the package
//external
, which is different from other packages. CallingPackage.getBuildFile()
returns theWORKSPACE
file andPackage.getStarlarkFileDependencies()
returns empty. A possible fix is to have the graph keep track of all Starlark files loaded byWORKSPACE
, so we can treat the package//external
in the same way as other packages during query execution. However, this means that evaluatingbuildfiles(//external:foo)
is the same as evaluatingbuildfiles(//external:*)
, which would include Starlark files not related to the repository@foo
.This PR takes a different approach by using the call stack of an external repository to get the precise set of Starlark files needed by
//external:foo
.Fixed #14280