Skip to content

Commit

Permalink
Update to most recent viable nightly
Browse files Browse the repository at this point in the history
Previously, if the user had components installed on `nightly` which were
not available for the latest nightly, `rustup update` would not update
the user's nightly at all. With this patch, rustup will try
progressively older nightlies until it finds a nightly that supports all
the components the user has installed for their current nightly.

Fixes rust-lang#1628.
Makes progress towards rust-lang#1501.
Fixes the underlying issue in rust-lang#1676.
  • Loading branch information
jonhoo committed Sep 16, 2019
1 parent d84e6e5 commit 9a056f7
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 75 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ no-self-update = []

# Sorted by alphabetic order
[dependencies]
chrono = "0.4"
clap = "2"
download = { path = "download" }
error-chain = "0.12"
Expand Down
78 changes: 78 additions & 0 deletions src/dist/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::dist::temp;
use crate::errors::*;
use crate::utils::utils;

use chrono::prelude::*;
use lazy_static::lazy_static;
use regex::Regex;

Expand Down Expand Up @@ -599,6 +600,81 @@ fn update_from_dist_<'a>(
profile: Option<Profile>,
prefix: &InstallPrefix,
force_update: bool,
) -> Result<Option<String>> {
let mut toolchain = toolchain.clone();
let mut fetched = String::new();
let backtrack = toolchain.channel == "nightly" && toolchain.date.is_none();
loop {
match try_update_from_dist_(
download,
update_hash,
&toolchain,
profile,
prefix,
force_update,
&mut fetched,
) {
Ok(v) => break Ok(v),
Err(e) => {
if !backtrack {
break Err(e);
}

let components =
if let ErrorKind::RequestedComponentsUnavailable(components, ..) = e.kind() {
components
} else {
break Err(e);
};

(download.notify_handler)(Notification::SkippingNightlyMissingComponent(
components,
));

// The user asked to update their nightly, but the latest nightly does not have all
// the components that the user currently has installed. Let's try the previous
// nightly (recursively) until we find a nightly that does.
//
// NOTE: we don't need to explicitly check for the case where the next nightly to
// try is _older_ than the current nightly, since we know that the user's current
// nightlys supports the components they have installed, and thus would always
// terminate the search.
if let Some(ref mut date) = toolchain.date {
// recurse
toolchain.date = Some(
Utc.from_utc_date(
&NaiveDate::parse_from_str(date, "%Y-%m-%d")
.expect("we constructed this date string below"),
)
.pred()
.format("%Y-%m-%d")
.to_string(),
);
} else {
// Pick a nightly that is one day older than the latest.
toolchain.date = Some(
Utc.from_utc_date(
&NaiveDate::parse_from_str(&fetched, "%Y-%m-%d")
.expect("manifest carries invalid date"),
)
.pred()
.format("%Y-%m-%d")
.to_string(),
);
}
}
}
}
}

fn try_update_from_dist_<'a>(
download: DownloadCfg<'a>,
update_hash: Option<&Path>,
toolchain: &ToolchainDesc,
profile: Option<Profile>,
prefix: &InstallPrefix,
force_update: bool,
fetched: &mut String,
) -> Result<Option<String>> {
let toolchain_str = toolchain.to_string();
let manifestation = Manifestation::open(prefix.clone(), toolchain.target.clone())?;
Expand All @@ -622,6 +698,8 @@ fn update_from_dist_<'a>(
remove_components: Vec::new(),
};

*fetched = m.date.clone();

return match manifestation.update(
&m,
changes,
Expand Down
8 changes: 8 additions & 0 deletions src/dist/notifications.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::dist::dist::TargetTriple;
use crate::dist::manifest::Component;
use crate::dist::temp;
use crate::errors::*;
use crate::utils::notify::NotificationLevel;
Expand Down Expand Up @@ -29,6 +30,7 @@ pub enum Notification<'a> {
DownloadingManifest(&'a str),
DownloadedManifest(&'a str, Option<&'a str>),
DownloadingLegacyManifest,
SkippingNightlyMissingComponent(&'a [Component]),
ManifestChecksumFailedHack,
ComponentUnavailable(&'a str, Option<&'a TargetTriple>),
StrayHash(&'a Path),
Expand Down Expand Up @@ -66,6 +68,7 @@ impl<'a> Notification<'a> {
| ManifestChecksumFailedHack
| RollingBack
| DownloadingManifest(_)
| SkippingNightlyMissingComponent(_)
| DownloadedManifest(_, _) => NotificationLevel::Info,
CantReadUpdateHash(_)
| ExtensionNotInstalled(_)
Expand Down Expand Up @@ -158,6 +161,11 @@ impl<'a> Display for Notification<'a> {
"removing stray hash found at '{}' in order to continue",
path.display()
),
SkippingNightlyMissingComponent(components) => write!(
f,
"skipping nightly which is missing installed component '{}'",
components[0].short_name_in_manifest()
),
}
}
}
21 changes: 21 additions & 0 deletions tests/cli-misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,27 @@ fn update_unavailable_rustc() {
});
}

#[test]
fn update_nightly_even_with_incompat() {
clitools::setup(Scenario::MissingComponent, &|config| {
set_current_dist_date(config, "2019-09-12");
expect_ok(config, &["rustup", "default", "nightly"]);

expect_stdout_ok(config, &["rustc", "--version"], "hash-n-1");
expect_ok(config, &["rustup", "component", "add", "rls"]);
expect_component_executable(config, "rls");

// latest nightly is now one that does not have RLS
set_current_dist_date(config, "2019-09-14");

expect_component_executable(config, "rls");
// update should bring us to latest nightly that does
expect_ok(config, &["rustup", "update", "nightly", "--no-self-update"]);
expect_stdout_ok(config, &["rustc", "--version"], "hash-n-2");
expect_component_executable(config, "rls");
});
}

#[test]
fn completion_rustup() {
setup(&|config| {
Expand Down
Loading

0 comments on commit 9a056f7

Please sign in to comment.