Skip to content

Add some help with updating the registry in offline mode. #6871

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

Merged
merged 4 commits into from
Apr 29, 2019
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
6 changes: 6 additions & 0 deletions src/cargo/sources/registry/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ impl<'cfg> RegistryIndex<'cfg> {
let summaries = summaries
.iter()
.filter(|&(summary, yanked)| {
// Note: This particular logic can cause problems with
// optional dependencies when offline. If at least 1 version
// of an optional dependency is downloaded, but that version
// does not satisfy the requirements, then resolution will
// fail. Unfortunately, whether or not something is optional
// is not known here.
(online || load.is_crate_downloaded(summary.package_id()))
&& (!yanked || {
log::debug!("{:?}", yanked_whitelist);
Expand Down
12 changes: 12 additions & 0 deletions src/cargo/sources/registry/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {

fn update_index(&mut self) -> CargoResult<()> {
if self.config.cli_unstable().offline {
if self.repo()?.is_empty()? {
// An empty repository is guaranteed to fail, since hitting
// this path means we need at least one crate. This is an
// attempt to provide a better error message other than "no
// matching package named …".
failure::bail!(
"unable to fetch {} in offline mode\n\
Try running without the offline flag, or try running \
`cargo fetch` within your project directory before going offline.",
self.source_id
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment here that we're explicitly switching the Ok to an Err because if we're updating the index we're guaranteed to require at leats one crate and since the index is empty it's guaranteed to have zero crates, therefore we're trying to give a better error message

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this suggestion is also a little sketchy. If you run cargo install foo for the first time, and the index is unavailable, it suggests running cargo fetch which will definitely not work. Maybe it is not worth it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point yeah, but I think that could be fixed by tweaking the error message? It could mention that you should try running with out --offline or otherwise run cargo fetch sooner perhaps?

}
return Ok(());
}
if self.config.cli_unstable().no_index_update {
Expand Down
307 changes: 0 additions & 307 deletions tests/testsuite/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -956,261 +956,6 @@ Did you mean `a`?",
.run();
}

#[test]
fn cargo_compile_path_with_offline() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []

[dependencies.bar]
path = "bar"
"#,
)
.file("src/lib.rs", "")
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "")
.build();

p.cargo("build -Zoffline")
.masquerade_as_nightly_cargo()
.run();
}

#[test]
fn cargo_compile_with_downloaded_dependency_with_offline() {
Package::new("present_dep", "1.2.3")
.file("Cargo.toml", &basic_manifest("present_dep", "1.2.3"))
.file("src/lib.rs", "")
.publish();

{
// make package downloaded
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"

[dependencies]
present_dep = "1.2.3"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("build").run();
}

let p2 = project()
.at("bar")
.file(
"Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"

[dependencies]
present_dep = "1.2.3"
"#,
)
.file("src/lib.rs", "")
.build();

p2.cargo("build -Zoffline")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[COMPILING] present_dep v1.2.3
[COMPILING] bar v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
)
.run();
}

#[test]
fn cargo_compile_offline_not_try_update() {
let p = project()
.at("bar")
.file(
"Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"

[dependencies]
not_cached_dep = "1.2.5"
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("build -Zoffline")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr(
"\
error: no matching package named `not_cached_dep` found
location searched: registry `[..]`
required by package `bar v0.1.0 ([..])`
As a reminder, you're using offline mode (-Z offline) \
which can sometimes cause surprising resolution failures, \
if this error is too confusing you may wish to retry \
without the offline flag.",
)
.run();
}

#[test]
fn compile_offline_without_maxvers_cached() {
Package::new("present_dep", "1.2.1").publish();
Package::new("present_dep", "1.2.2").publish();

Package::new("present_dep", "1.2.3")
.file("Cargo.toml", &basic_manifest("present_dep", "1.2.3"))
.file(
"src/lib.rs",
r#"pub fn get_version()->&'static str {"1.2.3"}"#,
)
.publish();

Package::new("present_dep", "1.2.5")
.file("Cargo.toml", &basic_manifest("present_dep", "1.2.5"))
.file("src/lib.rs", r#"pub fn get_version(){"1.2.5"}"#)
.publish();

{
// make package cached
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"

[dependencies]
present_dep = "=1.2.3"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("build").run();
}

let p2 = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"

[dependencies]
present_dep = "1.2"
"#,
)
.file(
"src/main.rs",
"\
extern crate present_dep;
fn main(){
println!(\"{}\", present_dep::get_version());
}",
)
.build();

p2.cargo("run -Zoffline")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[COMPILING] present_dep v1.2.3
[COMPILING] foo v0.1.0 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
Running `[..]`",
)
.with_stdout("1.2.3")
.run();
}

#[test]
fn offline_unused_target_dep() {
// -Z offline with a target dependency that is not used and not downloaded.
Package::new("unused_dep", "1.0.0").publish();
Package::new("used_dep", "1.0.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
[dependencies]
used_dep = "1.0"
[target.'cfg(unused)'.dependencies]
unused_dep = "1.0"
"#,
)
.file("src/lib.rs", "")
.build();
// Do a build that downloads only what is necessary.
p.cargo("build")
.with_stderr_contains("[DOWNLOADED] used_dep [..]")
.with_stderr_does_not_contain("[DOWNLOADED] unused_dep [..]")
.run();
p.cargo("clean").run();
// Build offline, make sure it works.
p.cargo("build -Z offline")
.masquerade_as_nightly_cargo()
.run();
}

#[test]
fn offline_missing_optional() {
Package::new("opt_dep", "1.0.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
[dependencies]
opt_dep = { version = "1.0", optional = true }
"#,
)
.file("src/lib.rs", "")
.build();
// Do a build that downloads only what is necessary.
p.cargo("build")
.with_stderr_does_not_contain("[DOWNLOADED] opt_dep [..]")
.run();
p.cargo("clean").run();
// Build offline, make sure it works.
p.cargo("build -Z offline")
.masquerade_as_nightly_cargo()
.run();
p.cargo("build -Z offline --features=opt_dep")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[ERROR] failed to download `opt_dep v1.0.0`

Caused by:
can't make HTTP request in the offline mode
",
)
.with_status(101)
.run();
}

#[test]
fn incompatible_dependencies() {
Package::new("bad", "0.1.0").publish();
Expand Down Expand Up @@ -1310,58 +1055,6 @@ failed to select a version for `bad` which could resolve this conflict",
.run();
}

#[test]
fn compile_offline_while_transitive_dep_not_cached() {
let baz = Package::new("baz", "1.0.0");
let baz_path = baz.archive_dst();
baz.publish();

let mut content = Vec::new();

let mut file = File::open(baz_path.clone()).ok().unwrap();
let _ok = file.read_to_end(&mut content).ok().unwrap();
drop(file);
drop(File::create(baz_path.clone()).ok().unwrap());

Package::new("bar", "0.1.0").dep("baz", "1.0.0").publish();

let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"

[dependencies]
bar = "0.1.0"
"#,
)
.file("src/main.rs", "fn main(){}")
.build();

// simulate download bar, but fail to download baz
p.cargo("build")
.with_status(101)
.with_stderr_contains("[..]failed to verify the checksum of `baz[..]")
.run();

drop(File::create(baz_path).ok().unwrap().write_all(&content));

p.cargo("build -Zoffline")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr(
"\
[ERROR] failed to download `baz v1.0.0`

Caused by:
can't make HTTP request in the offline mode
",
)
.run();
}

#[test]
fn compile_path_dep_then_change_version() {
let p = project()
Expand Down
Loading