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

Add factory for creating paths relative to well-known roots #15805

Closed

Conversation

Yannic
Copy link
Contributor

@Yannic Yannic commented Jul 4, 2022

This change adds a factory for creating PathFragments relative to
pre-defined (named) roots (e.g., relative to %workspace%).

The syntax is choosen to match existing ad-hoc solutions for %workspace%,
or %builtins% in other places (so that we can ideally migrate them in
a follow-up).

We'll use this for parsing paths from the command-line (e.g.,
--credential_helper=%workspace%/foo).

Progress on https://github.com/bazelbuild/proposals/blob/main/designs/2022-06-07-bazel-credential-helpers.md

This change adds a factory for creating `PathFragments` relative to
pre-defined (named) roots (e.g., relative to `%workspace%`).

The syntax is choosen to match existing ad-hoc solutions for `%workspace%`,
or `%builtins%` in other places (so that we can ideally migrate them in
a follow-up).

We'll use this for parsing paths from the command-line (e.g.,
`--credential_helper=%workspace%/foo`).

Progress on https://github.com/bazelbuild/proposals/blob/main/designs/2022-06-07-bazel-credential-helpers.md
@Yannic
Copy link
Contributor Author

Yannic commented Jul 4, 2022

@tjgq PTAL

* (e.g., {@code %workspace%/foo} becomes {@code </path/to/workspace>/foo}).
*/
public final class CommandLinePathFactory {
private static final Pattern REPLACEMENT_PATTERN = Pattern.compile("^(%([a-z_]+)%/)?([^%].*)$");
Copy link
Contributor

Choose a reason for hiding this comment

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

Make the last * a + so that an empty path is rejected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

* is actually correct. We reject the empty path because of the required [^%] before. Changing it to + would wrongly reject single-char paths (which are fine)

Copy link
Contributor

Choose a reason for hiding this comment

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

Oops, you're right :)

if (root == null) {
throw new IllegalArgumentException(String.format(Locale.US, "Unknown root %s", rootName));
}
return root.getRelative(path);
Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, what's the result of

new CommandLinePathFactory(ImmutableMap.of("workspace", "/path/to/workspace")).create("%workspace%/../bar");

Should we make it a requirement that the path must resolve to a descendant of the root (or possible even disallow . and .. segments entirely)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it to reject upwards references. PathFragment.create() will take care of normalizing it.

}

@Test
public void UnknownRoot() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Method name should start with lowercase.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

of course...

assertThat(factory.create("/absolute/path/2"))
.isEqualTo(PathFragment.create("/absolute/path/2"));
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Add a test to verify that the empty path is rejected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


/** Tests for {@link CommandLinePathFactory}. */
@RunWith(JUnit4.class)
public class CommandLinePathFactoryTest {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this class also going to be used in the PATH lookup case? (i.e., --credential_helper=somehelper)? If so, we should have tests here for paths that don't start with a slash, or without slashes at all.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, let me clarify:

  • If we're going to use this class for PATH lookup (e.g. --credential_helper=foo), we should have a test for them.
  • Since we agreed in the proposal to disallow non-absolute paths with slashes (e.g. --credential_helper=foo/bar) unless they're relative to a %root%, we should reject them (and have a test to verify that we do).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added PATH lookup (I was originally planning to do it somewhere else, but we may as well do it in this factory)

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, I'm not so sure PATH lookup belongs here. (What I had in mind was to simply store the non-absolute path, and resolve it later.)

I expect this code will run once at options parsing time, which means the result will be cached during the lifetime of the Bazel server process. Hence, if you add or remove a binary from one of the PATH directories that could affect the resolution of a particular helper, it won't take effect until you restart the server, which might be surprising to users.

WDYT? Should we defer PATH resolution until the helper is invoked?

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, I think what I said above only applies to startup options. If we can make --credential_helper a non-startup option, then I think it's fine to do the resolution here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was thinking of not making it the same option kind as --remote_{cache,executor}, which I think is build. It feels weird to make the credential helper a startup option when those aren't.

Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect build is not enough (e.g. repository fetching is necessary for the query command to work) but I'm struggling to imagine a reason for it to be available at startup. Let's go with the current version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ack. I think query actually implies build for historical reasons.

@Yannic
Copy link
Contributor Author

Yannic commented Jul 7, 2022

PTAL


/** Tests for {@link CommandLinePathFactory}. */
@RunWith(JUnit4.class)
public class CommandLinePathFactoryTest {
Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, I'm not so sure PATH lookup belongs here. (What I had in mind was to simply store the non-absolute path, and resolve it later.)

I expect this code will run once at options parsing time, which means the result will be cached during the lifetime of the Bazel server process. Hence, if you add or remove a binary from one of the PATH directories that could affect the resolution of a particular helper, it won't take effect until you restart the server, which might be surprising to users.

WDYT? Should we defer PATH resolution until the helper is invoked?


String rootName = matcher.group(2);
PathFragment path = PathFragment.create(matcher.group(3));
if (path.containsUplevelReferences()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we just use PathFragment.isNormalized here? I can't imagine a good reason to include a . component either.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think we should. IIUC, PathFragment.isNormalized would mean that you need to pass / instead of \ on Windows, which feels like an unnecessary restriction.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ack, I thought it only checked for . and ...


String rootName = matcher.group(2);
PathFragment path = PathFragment.create(matcher.group(3));
if (path.containsUplevelReferences()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Ack, I thought it only checked for . and ...


/** Tests for {@link CommandLinePathFactory}. */
@RunWith(JUnit4.class)
public class CommandLinePathFactoryTest {
Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect build is not enough (e.g. repository fetching is necessary for the query command to work) but I'm struggling to imagine a reason for it to be available at startup. Let's go with the current version.

@Yannic
Copy link
Contributor Author

Yannic commented Jul 8, 2022

@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 Jul 8, 2022
@ckolli5
Copy link

ckolli5 commented Jul 11, 2022

@bazel-io fork 5.3.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 Jul 11, 2022
@ckolli5
Copy link

ckolli5 commented Jul 19, 2022

Hey @Yannic, we are trying to cherry-pick these changes to release-5.3.0. But pre-submit checks are failing due to missing dependencies. So, could you please help us in cherry picking these changes to release-5.3.0?

@Yannic
Copy link
Contributor Author

Yannic commented Jul 20, 2022

Taking a look @ckolli5

@Yannic Yannic deleted the credhelper-cmdline-patg-factory branch July 20, 2022 12:08
Yannic added a commit to EngFlow/bazel that referenced this pull request Jul 20, 2022
This change adds a factory for creating `PathFragments` relative to
pre-defined (named) roots (e.g., relative to `%workspace%`).

The syntax is choosen to match existing ad-hoc solutions for `%workspace%`,
or `%builtins%` in other places (so that we can ideally migrate them in
a follow-up).

We'll use this for parsing paths from the command-line (e.g.,
`--credential_helper=%workspace%/foo`).

Progress on https://github.com/bazelbuild/proposals/blob/main/designs/2022-06-07-bazel-credential-helpers.md

Closes bazelbuild#15805.

PiperOrigin-RevId: 460950483
Change-Id: Ie263fb6d6c2ea938a850a72793d551135df6862e
aranguyen pushed a commit to aranguyen/bazel that referenced this pull request Jul 20, 2022
This change adds a factory for creating `PathFragments` relative to
pre-defined (named) roots (e.g., relative to `%workspace%`).

The syntax is choosen to match existing ad-hoc solutions for `%workspace%`,
or `%builtins%` in other places (so that we can ideally migrate them in
a follow-up).

We'll use this for parsing paths from the command-line (e.g.,
`--credential_helper=%workspace%/foo`).

Progress on https://github.com/bazelbuild/proposals/blob/main/designs/2022-06-07-bazel-credential-helpers.md

Closes bazelbuild#15805.

PiperOrigin-RevId: 460950483
Change-Id: Ie263fb6d6c2ea938a850a72793d551135df6862e
aranguyen pushed a commit to aranguyen/bazel that referenced this pull request Jul 20, 2022
This change adds a factory for creating `PathFragments` relative to
pre-defined (named) roots (e.g., relative to `%workspace%`).

The syntax is choosen to match existing ad-hoc solutions for `%workspace%`,
or `%builtins%` in other places (so that we can ideally migrate them in
a follow-up).

We'll use this for parsing paths from the command-line (e.g.,
`--credential_helper=%workspace%/foo`).

Progress on https://github.com/bazelbuild/proposals/blob/main/designs/2022-06-07-bazel-credential-helpers.md

Closes bazelbuild#15805.

PiperOrigin-RevId: 460950483
Change-Id: Ie263fb6d6c2ea938a850a72793d551135df6862e
@ShreeM01 ShreeM01 removed the awaiting-review PR is awaiting review from an assigned reviewer label Sep 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team-ExternalDeps External dependency handling, remote repositiories, WORKSPACE file.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants