-
Notifications
You must be signed in to change notification settings - Fork 892
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
Remove use of hard links to symlinks on macOS. #3137
Remove use of hard links to symlinks on macOS. #3137
Conversation
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.
Thank you for trying to submit a fix. The shellcheck issue is definitely not your fault.
I think this change is acceptable since it does fix a long-standing issue with homebrew, although I'd also like to see a small patch to the rustup-init side of things to detect that it is being launched from a symbolic link and to warn the user that this may mean they will end up with confusion as to versions since they appear to be using a package manager to manage the installer for a package manager. If you don't feel up to the latter, then don't worry we can consider adding it later.
In a development tree, all the tests should always pass. Given they're clearly passing in CI (e.g. https://github.com/rust-lang/rustup/actions/runs/3861468865/jobs/6582462931#step:14:1032 ) I'd like to know how they're failing locally for you.
Finally I'd like to know how this behaves updating from a version of rustup
which put symlinks to hardlinks in place to a version with this fix.
Rant about homebrew
What this change does is to mask a bug in homebrew's approach to packaging Rust. Specifically they should not be packaging rustup in this manner and despite attempts to correct this there has been no traction.Realistically homebrew should be packaging only rustup-init.sh
or they should be properly packaging rustup
along with all the proxy links, and building said rustup
with the no-self-update
feature. I can understand that you wouldn't want to do that yourself though.
Hi @kinnison, Thanks so much for the helpful review comments! Let me address your concerns one at a time...
I'm happy to work on this, although I'll admit I'm going to have to do some research to figure out how to tell whether the current process was launched from a symbolic link. Any tips you have in this regard would be welcome, as well as any suggested wording for the warning. Since you seem willing to have it come in separately from this fix, I will work on it in a separate PR, so as not to confuse this conversation.
After some investigation (which would have been made unnecessary if I had carefully read the entire contributing doc 🤕 ), I found that the version number comes from src/cli/common.rs which uses git_testament. So I tagged my local branch with the package version and now all the tests pass on my local machine. It's kind of interesting that they worked in CI - perhaps CI does the tagging or uses a trusted branch?
I'm not quite following. If you mean "hardlinks to symlinks" rather than "symlinks to hardlinks", then I think I understand and I can test that. |
Normal CI isn't using trusted branches, so it's a little odd that you needed that git tag, but so long as you can test locally I'm not too worried. Yes I meant as you understood - it's the "upgrade" process of converting from hardlinks to symlinks -> symlinks to symlinks which needs validation since our test-suite as it stands can't do that check. |
As far as I can tell, there is no scenario where a self update of an existing install will find hard links to a symlink and then need to replace them, because self update of existing installs always starts by first downloading and then copying the updated This is one of the reasons why homebrew's rustup-init is built with the What I have tested is running homebrew's rustup-init sequence with a no-self-update build of this PR, and that works just fine:
Thus, this patch preserves the initial install behavior (in copy_file) that homebrew relies on, and just fixes the hard links currently created to be symlinks instead (because the installed rustup is a symlink). On another topic, my research into how this all works is making me think that the additional fix you asked for:
is not actually necessary. There is nothing wrong with launching rustup-init from a symlink when you are doing an initial install. But if a package manager (such as homebrew) works in this way, it had better use a @kinnison Your thoughts? |
@kinnison Just checking in about this PR. Is there anything you want me to do to make it merge-ready? |
@kinnison is busy at the moment.
To my mind the failure is earlier: when rustup-init runs, it should realise it was launched from a symlink, resolve the symlink, and hard link to the target. Is there any reason not to do that? [If the answer is that homebrew cannot guarantee same-filesystem semantics, we could fall-back to copying the binary - but then you'd need a self-updating install. Which we're generally in favour of here.] Another variation would be to symlink directly to the actual binary, not symlink to symlink. Rustup uses hard links to keep page cache pressure and startup times low, symlinks aren't a huge problem - but the proxies do get called a lot in a cargo run. We're working on bypassing them safely to cut down overheads, so the hardlink or symlink thing will be less relevant soon I hope. Ultimately the question is where do we - homebrew folk + rustup folk want to get to. As @kinnison says, we're not feeling listened to. But perhaps we're not listening well enough either. |
@rbtcollins Thanks much for responding while @kinnison is busy. With all due respect, I think maybe rust-lang is overthinking this one special case. Here's a different way of looking at the current situation:
This logic is completely independent of the (rigid) homebrew convention that hardlinks/executables are never to be placed in per-user directories. If rustup were to change to notice that it was a symlink and find the actual rustup executable, it would end up hardwiring the user's cargo directory to the homebrew Cellar executables in violation of all homebrew rules. A homebrew update of the rust toolchain would then break the user's install. A homebrew install of rustup with this PR in place will work "just fine" (although fractionally less performant than before). But the current homebrew install (without this PR) can't be backed up or copied across filesystems because of Apple's lack of support for hardlinks to symlinks. I believe that's a more severe problem than the performance penalty this PR introduces. And users who are concerned about performance can always use the official rustup install instead of homebrew's package-managed install (which already has a double-symlink in every lookup). Hope this helps clarify my thinking. |
Could you please rebase this, the failing tests have been fixed in the interim, but I'd just like to be sure. Also, 'all due respect'? /shakes head |
Happy to rebase! And I can't quite tell if you were amused or upset by "all due respect," but I am an absolute newbie at rust-lang contributions and I have tremendous respect for the rust language maintainers, so I meant that very sincerely! |
I wasn't sure of the intent :) - in some cultural backgrounds, it is often a cutting sarcastic remark. In others it is a genuine superlative. Thanks for clarifying :) |
6c34b71
to
be662a9
Compare
I have rebased on top of current master and all local tests pass on Mac (the only platform with a code change). I did notice that there's a new clippy warning on Windows about doing a |
Fixes #3136 (macOS only) by checking to see if the source path being linked to is itself a symlink, and using a symlink rather than a hard link if it is.
Per the contributing guidelines:
update_exact
, which I can't see how to make work given this has a development version.I have field tested this by using it as the binary for homebrew's rustup-init, which places a symlink for rustup.
This is a first submission to the rust-lang tree for me. All comments welcome.