mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00

This commit is targeted at further improving the error messages generated from git errors. For authentication errors the actual URL fetched is now printed out as well if it's different from the original URL. This should help handle `insteadOf` logic where SSH urls are used instead of HTTPS urls and users can know to track that down. Otherwise the logic about recommending `net.git-fetch-with-cli` was tweaked a bit and moved to the same location as the rest of our error reporting. Note that a change piggy-backed here as well is that `Caused by:` errors are now automatically all tabbed over a bit instead of only having the first line tabbed over. This required a good number of tests to be updated, but it's just an updated in renderings.
565 lines
14 KiB
Rust
565 lines
14 KiB
Rust
//! Tests for --offline flag.
|
|
|
|
use cargo_test_support::{basic_manifest, git, main_file, path2url, project, registry::Package};
|
|
use std::fs;
|
|
|
|
#[cargo_test]
|
|
fn offline_unused_target_dep() {
|
|
// --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 --offline").run();
|
|
}
|
|
|
|
#[cargo_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 --offline").run();
|
|
p.cargo("build --offline --features=opt_dep")
|
|
.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();
|
|
}
|
|
|
|
#[cargo_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 --offline").run();
|
|
}
|
|
|
|
#[cargo_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 --offline")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] present_dep v1.2.3
|
|
[COMPILING] bar v0.1.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cargo_compile_offline_not_try_update() {
|
|
// When --offline needs to download the registry, provide a reasonable
|
|
// error hint to run without --offline.
|
|
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();
|
|
|
|
let msg = "\
|
|
[ERROR] no matching package named `not_cached_dep` found
|
|
location searched: registry `https://github.com/rust-lang/crates.io-index`
|
|
required by package `bar v0.1.0 ([..]/bar)`
|
|
As a reminder, you're using offline mode (--offline) which can sometimes cause \
|
|
surprising resolution failures, if this error is too confusing you may wish to \
|
|
retry without the offline flag.
|
|
";
|
|
|
|
p.cargo("build --offline")
|
|
.with_status(101)
|
|
.with_stderr(msg)
|
|
.run();
|
|
|
|
// While we're here, also check the config works.
|
|
p.change_file(".cargo/config", "net.offline = true");
|
|
p.cargo("build").with_status(101).with_stderr(msg).run();
|
|
}
|
|
|
|
#[cargo_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 --offline")
|
|
.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();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cargo_compile_forbird_git_httpsrepo_offline() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
|
|
[project]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["chabapok@example.com"]
|
|
|
|
[dependencies.dep1]
|
|
git = 'https://github.com/some_user/dep1.git'
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build --offline").with_status(101).with_stderr("\
|
|
[ERROR] failed to get `dep1` as a dependency of package `foo v0.5.0 [..]`
|
|
|
|
Caused by:
|
|
failed to load source for dependency `dep1`
|
|
|
|
Caused by:
|
|
Unable to update https://github.com/some_user/dep1.git
|
|
|
|
Caused by:
|
|
can't checkout from 'https://github.com/some_user/dep1.git': you are in the offline mode (--offline)").run();
|
|
}
|
|
|
|
#[cargo_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 baz_content = fs::read(&baz_path).unwrap();
|
|
// Truncate the file to simulate a download failure.
|
|
fs::write(&baz_path, &[]).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();
|
|
|
|
// Restore the file contents.
|
|
fs::write(&baz_path, &baz_content).unwrap();
|
|
|
|
p.cargo("build --offline")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[ERROR] failed to download `bar v0.1.0`
|
|
|
|
Caused by:
|
|
can't make HTTP request in the offline mode
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn update_offline() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[project]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "*"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.build();
|
|
p.cargo("update --offline")
|
|
.with_status(101)
|
|
.with_stderr("error: you can't update in the offline mode[..]")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cargo_compile_offline_with_cached_git_dep() {
|
|
let git_project = git::new("dep1", |project| {
|
|
project
|
|
.file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
pub static COOL_STR:&str = "cached git repo rev1";
|
|
"#,
|
|
)
|
|
});
|
|
|
|
let repo = git2::Repository::open(&git_project.root()).unwrap();
|
|
let rev1 = repo.revparse_single("HEAD").unwrap().id();
|
|
|
|
// Commit the changes and make sure we trigger a recompile
|
|
git_project.change_file(
|
|
"src/lib.rs",
|
|
r#"pub static COOL_STR:&str = "cached git repo rev2";"#,
|
|
);
|
|
git::add(&repo);
|
|
let rev2 = git::commit(&repo);
|
|
|
|
// cache to registry rev1 and rev2
|
|
let prj = project()
|
|
.at("cache_git_dep")
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[project]
|
|
name = "cache_git_dep"
|
|
version = "0.5.0"
|
|
|
|
[dependencies.dep1]
|
|
git = '{}'
|
|
rev = "{}"
|
|
"#,
|
|
git_project.url(),
|
|
rev1
|
|
),
|
|
)
|
|
.file("src/main.rs", "fn main(){}")
|
|
.build();
|
|
prj.cargo("build").run();
|
|
|
|
prj.change_file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[project]
|
|
name = "cache_git_dep"
|
|
version = "0.5.0"
|
|
|
|
[dependencies.dep1]
|
|
git = '{}'
|
|
rev = "{}"
|
|
"#,
|
|
git_project.url(),
|
|
rev2
|
|
),
|
|
);
|
|
prj.cargo("build").run();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[project]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
|
|
[dependencies.dep1]
|
|
git = '{}'
|
|
"#,
|
|
git_project.url()
|
|
),
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
&main_file(r#""hello from {}", dep1::COOL_STR"#, &["dep1"]),
|
|
)
|
|
.build();
|
|
|
|
let git_root = git_project.root();
|
|
|
|
p.cargo("build --offline")
|
|
.with_stderr(format!(
|
|
"\
|
|
[COMPILING] dep1 v0.5.0 ({}#[..])
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
|
|
path2url(git_root),
|
|
))
|
|
.run();
|
|
|
|
assert!(p.bin("foo").is_file());
|
|
|
|
p.process(&p.bin("foo"))
|
|
.with_stdout("hello from cached git repo rev2\n")
|
|
.run();
|
|
|
|
p.change_file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[project]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
|
|
[dependencies.dep1]
|
|
git = '{}'
|
|
rev = "{}"
|
|
"#,
|
|
git_project.url(),
|
|
rev1
|
|
),
|
|
);
|
|
|
|
p.cargo("build --offline").run();
|
|
p.process(&p.bin("foo"))
|
|
.with_stdout("hello from cached git repo rev1\n")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn offline_resolve_optional_fail() {
|
|
// Example where resolve fails offline.
|
|
//
|
|
// This happens if at least 1 version of an optional dependency is
|
|
// available, but none of them satisfy the requirements. The current logic
|
|
// that handles this is `RegistryIndex::query_inner`, and it doesn't know
|
|
// if the package being queried is an optional one. This is not ideal, it
|
|
// would be best if it just ignored optional (unselected) dependencies.
|
|
Package::new("dep", "1.0.0").publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
dep = { version = "1.0", optional = true }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("fetch").run();
|
|
|
|
// Change dep to 2.0.
|
|
p.change_file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
dep = { version = "2.0", optional = true }
|
|
"#,
|
|
);
|
|
|
|
p.cargo("build --offline")
|
|
.with_status(101)
|
|
.with_stderr("\
|
|
[ERROR] failed to select a version for the requirement `dep = \"^2.0\"`
|
|
candidate versions found which didn't match: 1.0.0
|
|
location searched: `[..]` index (which is replacing registry `https://github.com/rust-lang/crates.io-index`)
|
|
required by package `foo v0.1.0 ([..]/foo)`
|
|
perhaps a crate was updated and forgotten to be re-vendored?
|
|
As a reminder, you're using offline mode (--offline) which can sometimes cause \
|
|
surprising resolution failures, if this error is too confusing you may wish to \
|
|
retry without the offline flag.
|
|
")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn offline_with_all_patched() {
|
|
// Offline works if everything is patched.
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
dep = "1.0"
|
|
|
|
[patch.crates-io]
|
|
dep = {path = "dep"}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "pub fn f() { dep::foo(); }")
|
|
.file("dep/Cargo.toml", &basic_manifest("dep", "1.0.0"))
|
|
.file("dep/src/lib.rs", "pub fn foo() {}")
|
|
.build();
|
|
|
|
p.cargo("check --offline").run();
|
|
}
|