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

[WIP] Unresolved symlinks #15866

Closed
wants to merge 6 commits into from
Closed

Conversation

fmeum
Copy link
Collaborator

@fmeum fmeum commented Jul 13, 2022

No description provided.

The check in ActionMetadataHandler that an output declared to be a
symlink is indeed created as a symlink by the action was ineffective as
it would only run if a stat of the output showed that is already was a
symlink. The test only passed by accident since it runs sandboxed and
the sandbox setup would call Path.readSymbolicLink on what it expects to
be a symlink. As this does not happen on Windows, the test correctly
fails there.

This is fixed by calling Path.readSymbolicLink on the output path of an
expected symlink before rather than after stat-ing it and trusting the
file type contained in the stat info.

With this issue fixed, bazel_symlink_test can be enabled on Windows with
the following test-only changes:
* Pass --windows_enable_symlinks as a startup option.
* Use relative instead of absolute symlink targets as these have
  consistent shape under Unix and Windows.
* Use a helper java_binary to create symlinks rather than `ln -s`, which
  doesn't seem to be able to create unresolved symlinks on Windows.
Also adds support for such symlinks to the remote worker implementation.
@aiuto
Copy link
Contributor

aiuto commented Jul 20, 2022

Is there a bug and design behind this?
@alexjski : you might be interested in this.

@fmeum
Copy link
Collaborator Author

fmeum commented Jul 20, 2022

This PR combines the changes of three other PRs (#15781, #15773, #15700) that are currently awaiting review. Their ultimate goal is to stabilize --experimental_allow_unresolved_symlinks (#10298).

if (e instanceof NotASymlinkException) {
reporter.handle(Event.error(
action.getOwner().getLocation(),
String.format("declared output '%s' is not a symlink", output.prettyPrint())));
Copy link
Contributor

Choose a reason for hiding this comment

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

How about "Output '%s' was declared as a symlink, but is a '%s'"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, will update the corresponding PR if possible.

@@ -185,14 +185,14 @@ protected PathFragment readSymbolicLink(PathFragment path) throws IOException {
}

@Override
protected void createSymbolicLink(PathFragment linkPath, PathFragment targetFragment)
protected void createSymbolicLink(PathFragment linkPath, String rawTarget)
Copy link
Contributor

Choose a reason for hiding this comment

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

I am none too happy about turning this into just taking a raw string. What is it about the PathFragment normalization that needs to be addressed in this commit? Passing around simple strings increases the ways things can go wrong.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A symlink with target bar/../foo is not the same as a symlink with target foo: If bar is itself a symlink (or a junction on Windows), then bar/../foo will resolve relative to the target of bar.

Given these complications around symlinks, there has to be a way for Bazel to create "raw" symlinks via its filesystem abstractions. The respective PR is still WIP, but I plan to add comments explaining that the PathFragment overload should be preferred in almost all cases - except where it doesn't work, e.g. when explicitly creating a raw symlink.

@alexjski
Copy link
Contributor

Is there a bug and design behind this?

I agree that the context would be really useful here. That also goes together with @larsrc-google's excellent question about using raw string for symlinks--the explanation is sufficient for why that technically is needed, but it would be interesting to know what particular use cases need the symlinks not to be normalized.

@fmeum
Copy link
Collaborator Author

fmeum commented Jul 22, 2022

@alexjski Please see the individual PRs for context:

More recent context can also be found at #15454.

The current PR is merely a testbed to verify all the PRs function together, it is not a good starting point for a review (hence is marked as Draft).

@alexjski
Copy link
Contributor

The current PR is merely a testbed to verify all the PRs function together, it is not a good starting point for a review (hence is marked as Draft).

Thank you for the explanation! Should we move the discussion to the corresponding PRs instead?

@aiuto
Copy link
Contributor

aiuto commented Jul 22, 2022

@alexjski You might see some context in bazelbuild/rules_pkg#115.

The basic requirement is that when you are building distribution packages, you almost always want symlinks preserved rather than followed. For example, you want a binary and support files to live under /usr/share/my_package/{bin, lib, messages, ...}, and you want a symlink from /usr/bin/my_binary to /usr/share/my_package/bin/my_binary. The issue I pointed to talks about this from the perspective of NodeJS packages where, they have large symlink forests.

I've been approaching this from the rules_pkg side. My latest thinking is that

  • Rule authors need to be able to tell if a source file is a symlink or not, so they can offer the ability to the users to either resolve or keep intact
  • Some rules might also need the ability to handle symlinks in tree artifacts in one of two ways, but that is not Bazel's problem. When they walk the tree they can look for symlinks and do what they wan.

@fmeum fmeum closed this Sep 13, 2022
@fmeum fmeum deleted the unresolved-symlinks branch September 13, 2022 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants