Skip to content

Commit 4f67573

Browse files
authored
Merge pull request #55 from pnkfelix/link-to-current-nightly
Link to current nightly
2 parents c090fa0 + b074ad7 commit 4f67573

File tree

1 file changed

+102
-21
lines changed

1 file changed

+102
-21
lines changed

src/main.rs

Lines changed: 102 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::env;
99
use std::ffi::OsString;
1010
use std::fmt;
1111
use std::fs;
12+
use std::iter;
1213
use std::io::{self, Read, Write};
1314
use std::path::{Path, PathBuf};
1415
use std::process::{self, Command, Stdio};
@@ -246,7 +247,7 @@ impl Toolchain {
246247
match self.spec {
247248
ToolchainSpec::Ci { ref commit, alt } => {
248249
let alt_s = if alt { format!("-alt") } else { String::new() };
249-
format!("ci-{}{}-{}", commit, alt_s, self.host)
250+
format!("bisector-ci-{}{}-{}", commit, alt_s, self.host)
250251
}
251252
// N.B. We need to call this with a nonstandard name so that rustup utilizes the
252253
// fallback cargo logic.
@@ -287,19 +288,16 @@ impl DownloadParams {
287288
if cfg.args.alt { "-alt" } else { "" }
288289
);
289290

290-
DownloadParams {
291-
url_prefix: url_prefix,
292-
tmp_dir: cfg.rustup_tmp_path.clone(),
293-
install_dir: cfg.toolchains_path.clone(),
294-
install_cargo: cfg.args.with_cargo,
295-
install_src: cfg.args.with_src,
296-
force_install: cfg.args.force_install,
297-
}
291+
Self::from_cfg_with_url_prefix(cfg, url_prefix)
298292
}
299293

300294
fn for_nightly(cfg: &Config) -> Self {
295+
Self::from_cfg_with_url_prefix(cfg, NIGHTLY_SERVER.to_string())
296+
}
297+
298+
fn from_cfg_with_url_prefix(cfg: &Config, url_prefix: String) -> Self {
301299
DownloadParams {
302-
url_prefix: NIGHTLY_SERVER.to_string(),
300+
url_prefix: url_prefix,
303301
tmp_dir: cfg.rustup_tmp_path.clone(),
304302
install_dir: cfg.toolchains_path.clone(),
305303
install_cargo: cfg.args.with_cargo,
@@ -428,6 +426,8 @@ enum InstallError {
428426
TempDir(#[cause] io::Error),
429427
#[fail(display = "Could not move tempdir into destination: {}", _0)]
430428
Move(#[cause] io::Error),
429+
#[fail(display = "Could not run subcommand {}: {}", command, cause)]
430+
Subcommand { command: String, #[cause] cause: io::Error }
431431
}
432432

433433
#[derive(Debug)]
@@ -472,11 +472,23 @@ impl Toolchain {
472472
}
473473

474474
fn remove(&self, dl_params: &DownloadParams) -> Result<(), Error> {
475-
if !self.is_current_nightly() {
476-
eprintln!("uninstalling {}", self);
477-
let dir = dl_params.install_dir.join(self.rustup_name());
478-
fs::remove_dir_all(&dir)?;
479-
}
475+
eprintln!("uninstalling {}", self);
476+
self.do_remove(dl_params)
477+
}
478+
479+
/// Removes the (previously installed) bisector rustc described by `dl_params`.
480+
///
481+
/// The main reason to call this (instead of `fs::remove_dir_all` directly)
482+
/// is to guard against deleting state not managed by `cargo-bisect-rustc`.
483+
fn do_remove(&self, dl_params: &DownloadParams) -> Result<(), Error> {
484+
let rustup_name = self.rustup_name();
485+
486+
// Guard against destroying directories that this tool didn't create.
487+
assert!(rustup_name.starts_with("bisector-nightly") ||
488+
rustup_name.starts_with("bisector-ci"));
489+
490+
let dir = dl_params.install_dir.join(rustup_name);
491+
fs::remove_dir_all(&dir)?;
480492

481493
Ok(())
482494
}
@@ -680,24 +692,53 @@ impl Toolchain {
680692
}
681693

682694
fn install(&self, client: &Client, dl_params: &DownloadParams) -> Result<(), InstallError> {
683-
if self.is_current_nightly() {
684-
// pre existing installation
685-
return Ok(());
686-
}
687-
688695
debug!("installing {}", self);
689696
let tmpdir = TempDir::new_in(&dl_params.tmp_dir, &self.rustup_name())
690697
.map_err(InstallError::TempDir)?;
691698
let dest = dl_params.install_dir.join(self.rustup_name());
692699
if dl_params.force_install {
693-
let _ = fs::remove_dir_all(&dest);
700+
let _ = self.do_remove(dl_params);
694701
}
695702

696703
if dest.is_dir() {
697704
// already installed
698705
return Ok(());
699706
}
700707

708+
if self.is_current_nightly() {
709+
// make link to pre-existing installation
710+
debug!("installing (via link) {}", self);
711+
712+
let nightly_path: String = {
713+
let cmd = CommandTemplate::new(["rustc", "--print", "sysroot"]
714+
.iter()
715+
.map(|s| s.to_string()));
716+
let stdout = cmd.output()?.stdout;
717+
let output = String::from_utf8_lossy(&stdout);
718+
// the output should be the path, terminated by a newline
719+
let mut path = output.to_string();
720+
let last = path.pop();
721+
assert_eq!(last, Some('\n'));
722+
path
723+
};
724+
725+
let cmd = CommandTemplate::new(["rustup", "toolchain", "link"]
726+
.iter()
727+
.map(|s| s.to_string())
728+
.chain(iter::once(self.rustup_name()))
729+
.chain(iter::once(nightly_path)));
730+
if cmd.status()?.success() {
731+
return Ok(());
732+
} else {
733+
return Err(InstallError::Subcommand {
734+
command: cmd.string(),
735+
cause: io::Error::new(io::ErrorKind::Other, "failed to link via `rustup`"),
736+
});
737+
}
738+
}
739+
740+
debug!("installing via download {}", self);
741+
701742
let rustc_filename = format!("rustc-nightly-{}", self.host);
702743

703744
let location = match self.spec {
@@ -772,6 +813,46 @@ impl Toolchain {
772813
}
773814
}
774815

816+
// A simpler wrapper struct to make up for impoverished `Command` in libstd.
817+
struct CommandTemplate(Vec<String>);
818+
819+
impl CommandTemplate {
820+
fn new(strings: impl Iterator<Item=String>) -> Self {
821+
CommandTemplate(strings.collect())
822+
}
823+
824+
fn command(&self) -> Command {
825+
assert!(self.0.len() > 0);
826+
let mut cmd = Command::new(&self.0[0]);
827+
for arg in &self.0[1..] {
828+
cmd.arg(arg);
829+
}
830+
cmd
831+
}
832+
833+
fn string(&self) -> String {
834+
assert!(self.0.len() > 0);
835+
let mut s = self.0[0].to_string();
836+
for arg in &self.0[1..] {
837+
s.push_str(" ");
838+
s.push_str(arg);
839+
}
840+
s
841+
}
842+
843+
fn status(&self) -> Result<process::ExitStatus, InstallError> {
844+
self.command().status().map_err(|cause| {
845+
InstallError::Subcommand { command: self.string(), cause }
846+
})
847+
}
848+
849+
fn output(&self) -> Result<process::Output, InstallError> {
850+
self.command().output().map_err(|cause| {
851+
InstallError::Subcommand { command: self.string(), cause }
852+
})
853+
}
854+
}
855+
775856
struct Config {
776857
args: Opts,
777858
rustup_tmp_path: PathBuf,

0 commit comments

Comments
 (0)