Skip to content
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

Exclude convenience symlinks after changing the output base #21005

Closed
wants to merge 2 commits into from

Conversation

cameron-martin
Copy link
Contributor

@cameron-martin cameron-martin commented Jan 23, 2024

When the output base is changed after the convenience symlinks have been created, queries such as //... try to traverse into them and load them as packages since they are only excluded based on whether the resolved location is in the output base. This adds some heuristics to determine if a symlink is a convenience symlink:

  1. The symlink name has an appropriate suffix.
  2. An ancestor of the symlink target at the appropriate level is called execroot.
  3. The execroot directory contains a file called DO_NOT_BUILD_HERE.

These heuristics should work if both the output base and the symlink prefix change while being quite robust to false positives.

This is important for IDE integration, where the output base is often changed for queries, to prevent concurrent builds from blocking them. An example of this is the vscode-bazel extension.

Fixes #10653
Fixes #13951

@github-actions github-actions bot added the awaiting-review PR is awaiting review from an assigned reviewer label Jan 23, 2024
@iancha1992 iancha1992 added team-Core Skyframe, bazel query, BEP, options parsing, bazelrc team-OSS Issues for the Bazel OSS team: installation, release processBazel packaging, website labels Jan 23, 2024
@meteorcloudy meteorcloudy removed the team-OSS Issues for the Bazel OSS team: installation, release processBazel packaging, website label Jan 30, 2024
@brentleyjones
Copy link
Contributor

@iancha1992 Can we get someone to review this?

@iancha1992
Copy link
Member

@iancha1992 Can we get someone to review this?

@Wyverald @jin @meteorcloudy

@Wyverald
Copy link
Member

@haxorz, is team-Core the right label for this? If not, do you know which team owns the convenience symlinks?

@haxorz
Copy link
Contributor

haxorz commented Feb 13, 2024

@cameron-martin -

(1) Was the DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN sentinel file (https://bazel.build/run/build#specifying-build-targets) considered a as workaround for #10653 ?

(2) Is it intentional in your PR that we'd be changing the semantics for a traversal of a directory containing a dirent whose name just happens to start with the symlink prefix? (Consider bazel query //foo/... i.e. no bazel build even creating the convenience symlinks in the first place.) I think we'd want to do something a little more involved and care about the target of the link, and perhaps even the siblings of the target.

@Wyverald - team-Core vestigially owns the convenience symlinks functionality. We own the directory traversal functionality more strongly and actively.

@cameron-martin
Copy link
Contributor Author

cameron-martin commented Feb 14, 2024

@haxorz Using a DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN sentinel file sounds way more robust. There is also the DO_NOT_BUILD_HERE file in the execroot that could be inspected to exclude this directory. Is it a good idea to use this file for this purpose?

@haxorz
Copy link
Contributor

haxorz commented Feb 14, 2024

+cc @lberki because back in the day he was involved both the things mentioned below.

Using a DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN sentinel file sounds way more robust

Yeah.

In 1e66ccd we changed Bazel to respect the DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN sentinel file as an follow up to changing Bazel to follow directory symlinks when resolving recursive target patterns. This is not a coincidence; that behavior change had some unintended consequences internally due to legacy repo contents... so we added that feature as a workaround.

Yes, you could use that workaround. I was suggesting you could instruct your IDE users to create a DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN file in the top-level directory. This would work, right (but be annoying)?

There is also the DO_NOT_BUILD_HERE file in the execroot that could be inspected to exclude this directory. Is it a good idea to use this file for this purpose?

This would be more complicated but would be most robust because Bazel would be trying to prevent the situation in #10653 from mattering at all.

A nitpick would be to either rename that or use a new one with a different name. DO_NOT_BUILD_HERE is currently pretty narrow (see the single consumption in BlazeOptionHandler.java). So I'd recommend instead involving a new sentinel file (maybe DONT_TRAVERSE_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN, so as to have the name be self-documenting wrt DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN). You could change Bazel to create this file (as a sibling to DO_NOT_BUILD_HERE!) in the output base, and then modify the recursive target pattern traversal code to respect it.

I will preemptively say though: If you do this, the merge with Blaze internally at Google is going to require some care. DO_NOT_BUILD_HERE was introduced in 2009, and the claim back then was that there were some usages of blaze query inside the output base (you can even still see this in the Bazel source code; check out the comment for Command#canRunInOutputDirectory). So if you proceed with this approach, someone internally is going to have to set aside time to investigate this and potentially figure out a way to obsolete it.

@lberki
Copy link
Contributor

lberki commented Feb 14, 2024

I did some research internally and it looks running any Bazel command under the execroot is rare enough that it can be safely ignored (see internal thread; I can't discuss the details here) and I'll send out a change to remove it as soon as the presubmits pass.

I consider DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN a hack so I'd rather not copy that pattern. It's Yet Another Knob we need to support forever. Instead how about using a heuristics: If

  1. The symlink ends with -bin, -out -genfiles, -testlogs or -<basename of the directory it is in> (the prefix is configurable with --symlink_prefix, the suffixes are not)
  2. It points directly to a directory whose ancestor of the appropriate level is called execroot
  3. The execroot directory contains a file called DO_NOT_BUILD_HERE
  4. OPTIONAL: If DO_NOT_BUILD_HERE contains the name of the directory being inspected although that can result in a false negative since symlinks can lead to any given directory being accessible under multiple names

that directory is not traversed?

@lberki
Copy link
Contributor

lberki commented Feb 14, 2024

Update: I found a corner case that @Wyverald added to the build of Bazel like a day ago: if you run Bazel query from a genrule AND you are not running in a sandbox AND you plop down a MODULE.bazel / WORKSPACE file in the original cwd of the genrule, you'll be using the "query can run in the output base" exception.

I'll still go ahead with the removal because it looks like it's a very special case only affecting who works on Bazel (in fact, it only showed up on our Windows presubmits), but with a little less confidence.

copybara-service bot pushed a commit that referenced this pull request Feb 14, 2024
…put base.

This is legacy functionality from 2009 (in the case of "query") and 2012 (in the case of "print_action", which is when that command was invented).

Motivated by #21005 .

RELNOTES[INC]: "bazel query" and "bazel print_action" can't run under the output base anymore.

PiperOrigin-RevId: 607036900
Change-Id: Ic9272d42d07b802924b4420408146de830a82ad8
@cameron-martin
Copy link
Contributor Author

@lberki I've updated the PR with the majority of the heuristics that you mentioned. However, I'm unsure of how to implement point 3, since I get the feeling from surrounding code that filesystem access should be done via skyframe rather than more directly. However I'm not too hot on how skyframe works. Could I have some pointers on how to achieve this?

I'm also unsure about what depth successor the -genfiles symlink is of the execroot, since I've never seen this before (is this just a blaze thing?).

@lberki
Copy link
Contributor

lberki commented Feb 16, 2024

Thanks for updating the pull request! I added a code snippet which I'm pretty sure works after some light editing (I didn't compile it)

When the output base is changed after the convenience symlinks have been created, queries such as `//...` try to traverse into them and load them as packages since they are only excluded based on whether the resolved location is in the output base. This adds some heuristics to determine if a symlink is a convenience symlink:

1. The symlink name has an appropriate suffix.
2. An ancestor of the symlink target at the appropriate level is called `execroot`.
3. The `execroot` directory contains a file called `DO_NOT_BUILD_HERE`.

These heuristics should work if both the output base and the symlink prefix change while being quite robust to false positives.

Fixes bazelbuild#10653
Copy link
Contributor

@lberki lberki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for taking my time; this accidentally fell off my task list.

* Split large or statement into multiple ifs.
* Check if there is enough path segments in `isInExecRoot`.
@cameron-martin
Copy link
Contributor Author

@lberki I've addressed the latest review comments.

@lberki
Copy link
Contributor

lberki commented Feb 24, 2024

Thanks. Looks good to me now!

@lberki lberki added awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally and removed awaiting-review PR is awaiting review from an assigned reviewer labels Feb 24, 2024
@github-actions github-actions bot removed the awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally label Feb 27, 2024
@fmeum
Copy link
Collaborator

fmeum commented Feb 27, 2024

@bazel-io flag

@bazel-io bazel-io added the potential release blocker Flagged by community members using "@bazel-io flag". Should be added to a release blocker milestone label Feb 27, 2024
@cameron-martin cameron-martin deleted the fix-10653 branch February 27, 2024 10:28
@meteorcloudy
Copy link
Member

@bazel-io fork 7.1.0

@bazel-io bazel-io removed the potential release blocker Flagged by community members using "@bazel-io flag". Should be added to a release blocker milestone label Feb 27, 2024
bazel-io pushed a commit to bazel-io/bazel that referenced this pull request Feb 27, 2024
When the output base is changed after the convenience symlinks have been created, queries such as `//...` try to traverse into them and load them as packages since they are only excluded based on whether the resolved location is in the output base. This adds some heuristics to determine if a symlink is a convenience symlink:

1. The symlink name has an appropriate suffix.
2. An ancestor of the symlink target at the appropriate level is called `execroot`.
3. The `execroot` directory contains a file called `DO_NOT_BUILD_HERE`.

These heuristics should work if both the output base and the symlink prefix change while being quite robust to false positives.

This is important for IDE integration, where the [output base is often changed](https://bazel.build/run/scripts#output-base-option) for queries, to prevent concurrent builds from blocking them. An example of this is the vscode-bazel extension.

Fixes bazelbuild#10653
Fixes bazelbuild#13951

Closes bazelbuild#21005.

PiperOrigin-RevId: 610667735
Change-Id: I1869c9a2063f7f526950e48c0b1ee6efa89fd202
iancha1992 pushed a commit to iancha1992/bazel that referenced this pull request Feb 29, 2024
…put base.

This is legacy functionality from 2009 (in the case of "query") and 2012 (in the case of "print_action", which is when that command was invented).

Motivated by bazelbuild#21005 .

RELNOTES[INC]: "bazel query" and "bazel print_action" can't run under the output base anymore.

PiperOrigin-RevId: 607036900
Change-Id: Ic9272d42d07b802924b4420408146de830a82ad8
github-merge-queue bot pushed a commit that referenced this pull request Mar 4, 2024
…21505)

When the output base is changed after the convenience symlinks have been
created, queries such as `//...` try to traverse into them and load them
as packages since they are only excluded based on whether the resolved
location is in the output base. This adds some heuristics to determine
if a symlink is a convenience symlink:

1. The symlink name has an appropriate suffix.
2. An ancestor of the symlink target at the appropriate level is called
`execroot`.
3. The `execroot` directory contains a file called `DO_NOT_BUILD_HERE`.

These heuristics should work if both the output base and the symlink
prefix change while being quite robust to false positives.

This is important for IDE integration, where the [output base is often
changed](https://bazel.build/run/scripts#output-base-option) for
queries, to prevent concurrent builds from blocking them. An example of
this is the vscode-bazel extension.

Fixes #10653
Fixes #13951

Closes #21005.

Commit
8f74ace

PiperOrigin-RevId: 610667735
Change-Id: I1869c9a2063f7f526950e48c0b1ee6efa89fd202

Co-authored-by: Cameron Martin <cameronmartin123@gmail.com>
Co-authored-by: Yun Peng <pcloudy@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team-Core Skyframe, bazel query, BEP, options parsing, bazelrc
Projects
None yet
9 participants