Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/cli/self_update/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@ pub(crate) fn do_remove_from_path(process: &Process) -> Result<()> {
let file = utils::read_file("rcfile", rc)?;
let file_bytes = file.into_bytes();
// FIXME: This is whitespace sensitive where it should not be.
if let Some(idx) = file_bytes
.windows(source_bytes.len())
.position(|w| w == source_bytes.as_slice())
{
if let Some(idx) = find_exact_line(&file_bytes, &source_bytes) {
// Here we rewrite the file without the offending line.
let mut new_bytes = file_bytes[..idx].to_vec();
new_bytes.extend(&file_bytes[idx + source_bytes.len()..]);
Expand Down Expand Up @@ -148,10 +145,7 @@ fn remove_legacy_source_command(source_cmd: String, process: &Process) -> Result
let file = utils::read_file("rcfile", &rc)?;
let file_bytes = file.into_bytes();
// FIXME: This is whitespace sensitive where it should not be.
if let Some(idx) = file_bytes
.windows(cmd_bytes.len())
.position(|w| w == cmd_bytes.as_slice())
{
if let Some(idx) = find_exact_line(&file_bytes, &cmd_bytes) {
// Here we rewrite the file without the offending line.
let mut new_bytes = file_bytes[..idx].to_vec();
new_bytes.extend(&file_bytes[idx + cmd_bytes.len()..]);
Expand All @@ -162,6 +156,16 @@ fn remove_legacy_source_command(source_cmd: String, process: &Process) -> Result
Ok(())
}

fn find_exact_line(file: &[u8], line: &[u8]) -> Option<usize> {
// The trailing newline enforces the end boundary; check the start boundary here.
assert!(line.ends_with(b"\n"));
file.windows(line.len())
.enumerate()
.find_map(|(idx, candidate)| {
(candidate == line && (idx == 0 || file[idx - 1] == b'\n')).then_some(idx)
})
}

fn remove_legacy_paths(process: &Process) -> Result<()> {
// Before the work to support more kinds of shells, which was released in
// version 1.23.0 of Rustup, we always inserted this line instead, which is
Expand Down
35 changes: 35 additions & 0 deletions tests/suite/cli_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,41 @@ error: could not amend shell profile[..]
}
}

#[tokio::test]
async fn install_preserves_guarded_legacy_source() {
let cx = CliTestContext::new(Scenario::Empty).await;
let profile = cx.config.homedir.join(".bash_profile");
let guarded_source = "[ -f \"$HOME/.cargo/env\" ] && source \"$HOME/.cargo/env\"\n";
raw::write_file(&profile, guarded_source).unwrap();

let mut cmd = cx.config.cmd("rustup-init", &INIT_NONE[1..]);
cmd.env_remove("CARGO_HOME");
assert!(cmd.output().unwrap().status.success());

let new_profile = fs::read_to_string(&profile).unwrap();
let expected = guarded_source.to_owned() + &source("$HOME/.cargo", POSIX_SH);
assert_eq!(new_profile, expected);
}

#[tokio::test]
async fn uninstall_preserves_guarded_source() {
let cx = CliTestContext::new(Scenario::Empty).await;
let profile = cx.config.homedir.join(".bash_profile");
let guarded_source = "[ -f \"$HOME/.cargo/env\" ] && . \"$HOME/.cargo/env\"\n";
raw::write_file(&profile, guarded_source).unwrap();

let mut cmd = cx.config.cmd("rustup-init", &INIT_NONE[1..]);
cmd.env_remove("CARGO_HOME");
assert!(cmd.output().unwrap().status.success());

let mut cmd = cx.config.cmd("rustup", ["self", "uninstall", "-y"]);
cmd.env_remove("CARGO_HOME");
assert!(cmd.output().unwrap().status.success());

let new_profile = fs::read_to_string(&profile).unwrap();
assert_eq!(new_profile, guarded_source);
}

#[tokio::test]
async fn uninstall_cleans_up_legacy_paths() {
let cx = CliTestContext::new(Scenario::Empty).await;
Expand Down
Loading