-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Handle symlinks to directories #6817
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Thanks for the PR! I sort of forget the context around this code, but do you remember why I wonder if we could possibly query git instead of the filesystem to attempt to learn if a symlink points to a directory? |
I have no clues how any of those things work, unfortunately.
|
Querying git looks like it would be more trouble than it's worth. It would need to read the link's contents, do an I would suggest maybe something like this would be simpler. diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs
index fd2e4bb5..d35e75ca 100644
--- a/src/cargo/sources/path.rs
+++ b/src/cargo/sources/path.rs
@@ -323,9 +323,17 @@ impl<'cfg> PathSource<'cfg> {
// the untracked files are often part of a build and may become relevant
// as part of a future commit.
let index_files = index.iter().map(|entry| {
- use libgit2_sys::GIT_FILEMODE_COMMIT;
- let is_dir = entry.mode == GIT_FILEMODE_COMMIT as u32;
- (join(root, &entry.path), Some(is_dir))
+ use libgit2_sys::{GIT_FILEMODE_COMMIT, GIT_FILEMODE_LINK};
+ // `is_dir` is an optimization to avoid calling `fs::metadata` on
+ // every file.
+ let is_dir = if entry.mode == GIT_FILEMODE_LINK as u32 {
+ // Let the code below figure out if this symbolic link points
+ // to a directory or not.
+ None
+ } else {
+ Some(entry.mode == GIT_FILEMODE_COMMIT as u32)
+ };
+ (join(root, &entry.path), is_dir)
});
let mut opts = git2::StatusOptions::new();
opts.include_untracked(true); @thomwiggers The tests are not generated. There is an introduction to writing tests at |
What is the desired behaviour for these symlinks anyway? Say we have the folowing project layout:
Do we then want to handle the symlink like a copy of the What about the following scenario?
There just archiving as a symlink would probably not be sufficient, and you do want cargo to copy the files in |
There appears to be a compile issue in unrelated code that I can't reproduce locally.
|
I think that should be fixed on master now, but it's a good point about how we want to support this. I think maybe an "ideal" would be supporting symlinks within a package but erroring out on symlinks that point outside the package, but dealing with paths and symlinks is so fraught with bugs that I think I'd personally just prefer to have a first-class error for directory symlinks or symlinks in general. |
Making it a strict error would seriously complicate maintenance of packages such as the one I'm building here: https://github.com/rustpq/pqcrypto. This project will at some point have:
This project will be importing a whole bunch of different C implementations of cryptographic libraries and generating Rust bindings to use them. The neat place to put the shared C code would be in the parent directory; having to mount the submodule or copy and commit the files in each separate subpackage would be a huge pain. |
I think if we want to support this we'll want to avoid symlinks in archives and just copy all the contents in, and if that works for your use case it seems like a reasonable way to implement this perhaps |
I believe that is how it works now (or with this patch when using git). |
Correct. In very weird edge cases where there are a lot of symlinks to the same files this might inflate packages, but on the other hand the compression algorithm should take care of that I guess. |
Rebased on master to re-trigger tests. |
Error on Windows:
Ah, wait, there's another hidden "the directory name is invalid" error. |
I needed to put in some extra effort to fix some things in how the test supports treat symlinks, but I think this should be reasonable now. Removing symlinks on Windows was broken. |
☔ The latest upstream changes (presumably #6900) made this pull request unmergeable. Please resolve the merge conflicts. |
I'm getting privilege errors for the below tests on Windows 10. I think it would be good to avoid that if the system isn't configured to handle symlinks on Windows.
Perhaps add some kind of check if symlinks are supported on Windows, and skip the test if they are not? Also, can you squash all the commits? |
Unfortunately you need admin privileges on Windows to create them in the first place. It's not possible to really skip tests in Rust... so I can't really do detection (marking them 'passed' seems inaccurate). I could perhaps mark them as |
I have rebased and cleaned up the commit history. I did not fully squash it, as I wanted the history to reflect the different things this PR addresses:
|
Appveyor appears to fail for completely unrelated reasons. |
☔ The latest upstream changes (presumably #7139) made this pull request unmergeable. Please resolve the merge conflicts. |
☔ The latest upstream changes (presumably #7137) made this pull request unmergeable. Please resolve the merge conflicts. |
Fixes #2748. Uses @ehuss's suggested fix. See #6817 (comment)
This patch allows you to run them when wanted with ``--ignored`` on Windows.
Seems like it's no longer necessary (this test ran fine when `--ignored` was specified
It appears rustfmt nightly and stable disagree... |
Yea, I was trying to figure out how to deal with the rustfmt changes, but I think I'm just gonna leave it until 1.38 hits stable. It is annoying. Thanks for seeing this through! @bors r+ |
📌 Commit d0f7c0e has been approved by |
Handle symlinks to directories When cargo encounters a link, check if it's a directory when considering it for further processing. I'm not sure how this interacts with things such as submodules – it allowed me to publish the crate [pqcrypto-kyber768](https://github.com/rustpq/pqcrypto) which uses a link to a submodule. Fixes #2748. This PR: * Add new tests that demonstrate that links to dirs can't be packaged * Fixes those tests * Enabled symlink tests to run on Windows * Fix a bug in the handling of symlinks * Add new test runner behaviour on Windows (it will ignore symlink-related tests and instead run them if you specify --ignored.)
☀️ Test successful - checks-azure |
Update cargo, rls ## cargo 12 commits in d0f828419d6ce6be21a90866964f58eb2c07cd56..26092da337b948719549cd5ed3d1051fd847afd7 2019-07-23 21:58:59 +0000 to 2019-07-31 23:24:32 +0000 - tests: Enable features to fix unstabilized `#[bench]` (rust-lang/cargo#7198) - Fix excluding target dirs from backups on OSX (rust-lang/cargo#7192) - Handle symlinks to directories (rust-lang/cargo#6817) - Enable pipelined compilation by default (rust-lang/cargo#7143) - Refactor resolve `Method` (rust-lang/cargo#7186) - Update `cargo_compile` module doc. (rust-lang/cargo#7187) - Clean up TargetInfo (rust-lang/cargo#7185) - Fix some issues with absolute paths in dep-info files. (rust-lang/cargo#7137) - Update the `url` crate to 2.0 (rust-lang/cargo#7175) - Tighten requirements for git2 crates (rust-lang/cargo#7176) - Fix a deadlocking test with master libgit2 (rust-lang/cargo#7179) - Fix detection of cyclic dependencies through `[patch]` (rust-lang/cargo#7174) ## rls 1 commits in 70347b5d4dfe78eeb9e6f6db85f773c8d43cd22b..93d9538c6000fcf6c8da763ef4ce7a8d407b7d24 2019-07-30 12:56:38 +0200 to 2019-07-31 21:42:49 +0200 - Update cargo (rust-lang/rls#1529)
When cargo encounters a link, check if it's a directory when considering it for further processing.
I'm not sure how this interacts with things such as submodules – it allowed me to publish the crate pqcrypto-kyber768 which uses a link to a submodule.
Fixes #2748.
This PR: