Skip to content

Commit 2378a9b

Browse files
committed
Resolve: Be less strict while offline.
1 parent 6bdb9d3 commit 2378a9b

File tree

4 files changed

+118
-20
lines changed

4 files changed

+118
-20
lines changed

src/cargo/core/package.rs

+6
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,12 @@ impl<'a, 'cfg> Downloads<'a, 'cfg> {
442442
/// eventually be returned from `wait_for_download`. Returns `Some(pkg)` if
443443
/// the package is ready and doesn't need to be downloaded.
444444
pub fn start(&mut self, id: PackageId) -> CargoResult<Option<&'a Package>> {
445+
Ok(self
446+
.start_inner(id)
447+
.chain_err(|| format!("failed to download `{}`", id))?)
448+
}
449+
450+
fn start_inner(&mut self, id: PackageId) -> CargoResult<Option<&'a Package>> {
445451
// First up see if we've already cached this package, in which case
446452
// there's nothing to do.
447453
let slot = self

src/cargo/sources/registry/index.rs

+35-12
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ impl<'cfg> RegistryIndex<'cfg> {
200200
ret.reserve(contents.lines().count());
201201
let lines = contents.lines().map(|s| s.trim()).filter(|l| !l.is_empty());
202202

203-
let online = !self.config.cli_unstable().offline;
204203
// Attempt forwards-compatibility on the index by ignoring
205204
// everything that we ourselves don't understand, that should
206205
// allow future cargo implementations to break the
@@ -215,11 +214,7 @@ impl<'cfg> RegistryIndex<'cfg> {
215214
return None;
216215
}
217216
};
218-
if online || load.is_crate_downloaded(summary.package_id()) {
219-
Some((summary, locked))
220-
} else {
221-
None
222-
}
217+
Some((summary, locked))
223218
}));
224219

225220
Ok(())
@@ -274,17 +269,43 @@ impl<'cfg> RegistryIndex<'cfg> {
274269
yanked_whitelist: &HashSet<PackageId>,
275270
f: &mut dyn FnMut(Summary),
276271
) -> CargoResult<()> {
272+
if self.config.cli_unstable().offline {
273+
if self.query_inner_with_online(dep, load, yanked_whitelist, f, false)? != 0 {
274+
return Ok(());
275+
}
276+
// If offline, and there are no matches, try again with online.
277+
// This is necessary for dependencies that are not used (such as
278+
// target-cfg or optional), but are not downloaded. Normally the
279+
// build should succeed if they are not downloaded and not used,
280+
// but they still need to resolve. If they are actually needed
281+
// then cargo will fail to download and an error message
282+
// indicating that the required dependency is unavailable while
283+
// offline will be displayed.
284+
}
285+
self.query_inner_with_online(dep, load, yanked_whitelist, f, true)?;
286+
Ok(())
287+
}
288+
289+
fn query_inner_with_online(
290+
&mut self,
291+
dep: &Dependency,
292+
load: &mut dyn RegistryData,
293+
yanked_whitelist: &HashSet<PackageId>,
294+
f: &mut dyn FnMut(Summary),
295+
online: bool,
296+
) -> CargoResult<usize> {
277297
let source_id = self.source_id;
278298
let name = dep.package_name().as_str();
279299
let summaries = self.summaries(name, load)?;
280300
let summaries = summaries
281301
.iter()
282302
.filter(|&(summary, yanked)| {
283-
!yanked || {
284-
log::debug!("{:?}", yanked_whitelist);
285-
log::debug!("{:?}", summary.package_id());
286-
yanked_whitelist.contains(&summary.package_id())
287-
}
303+
(online || load.is_crate_downloaded(summary.package_id()))
304+
&& (!yanked || {
305+
log::debug!("{:?}", yanked_whitelist);
306+
log::debug!("{:?}", summary.package_id());
307+
yanked_whitelist.contains(&summary.package_id())
308+
})
288309
})
289310
.map(|s| s.0.clone());
290311

@@ -308,9 +329,11 @@ impl<'cfg> RegistryIndex<'cfg> {
308329
_ => true,
309330
});
310331

332+
let mut count = 0;
311333
for summary in summaries {
312334
f(summary);
335+
count += 1;
313336
}
314-
Ok(())
337+
Ok(count)
315338
}
316339
}

tests/testsuite/build.rs

+76-8
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,77 @@ fn main(){
11401140
.run();
11411141
}
11421142

1143+
#[test]
1144+
fn offline_unused_target_dep() {
1145+
// -Z offline with a target dependency that is not used and not downloaded.
1146+
Package::new("unused_dep", "1.0.0").publish();
1147+
Package::new("used_dep", "1.0.0").publish();
1148+
let p = project()
1149+
.file(
1150+
"Cargo.toml",
1151+
r#"
1152+
[project]
1153+
name = "foo"
1154+
version = "0.1.0"
1155+
[dependencies]
1156+
used_dep = "1.0"
1157+
[target.'cfg(unused)'.dependencies]
1158+
unused_dep = "1.0"
1159+
"#,
1160+
)
1161+
.file("src/lib.rs", "")
1162+
.build();
1163+
// Do a build that downloads only what is necessary.
1164+
p.cargo("build")
1165+
.with_stderr_contains("[DOWNLOADED] used_dep [..]")
1166+
.with_stderr_does_not_contain("[DOWNLOADED] unused_dep [..]")
1167+
.run();
1168+
p.cargo("clean").run();
1169+
// Build offline, make sure it works.
1170+
p.cargo("build -Z offline")
1171+
.masquerade_as_nightly_cargo()
1172+
.run();
1173+
}
1174+
1175+
#[test]
1176+
fn offline_missing_optional() {
1177+
Package::new("opt_dep", "1.0.0").publish();
1178+
let p = project()
1179+
.file(
1180+
"Cargo.toml",
1181+
r#"
1182+
[project]
1183+
name = "foo"
1184+
version = "0.1.0"
1185+
[dependencies]
1186+
opt_dep = { version = "1.0", optional = true }
1187+
"#,
1188+
)
1189+
.file("src/lib.rs", "")
1190+
.build();
1191+
// Do a build that downloads only what is necessary.
1192+
p.cargo("build")
1193+
.with_stderr_does_not_contain("[DOWNLOADED] opt_dep [..]")
1194+
.run();
1195+
p.cargo("clean").run();
1196+
// Build offline, make sure it works.
1197+
p.cargo("build -Z offline")
1198+
.masquerade_as_nightly_cargo()
1199+
.run();
1200+
p.cargo("build -Z offline --features=opt_dep")
1201+
.masquerade_as_nightly_cargo()
1202+
.with_stderr(
1203+
"\
1204+
[ERROR] failed to download `opt_dep v1.0.0`
1205+
1206+
Caused by:
1207+
can't make HTTP request in the offline mode
1208+
",
1209+
)
1210+
.with_status(101)
1211+
.run();
1212+
}
1213+
11431214
#[test]
11441215
fn incompatible_dependencies() {
11451216
Package::new("bad", "0.1.0").publish();
@@ -1282,14 +1353,11 @@ fn compile_offline_while_transitive_dep_not_cached() {
12821353
.with_status(101)
12831354
.with_stderr(
12841355
"\
1285-
error: no matching package named `baz` found
1286-
location searched: registry `[..]`
1287-
required by package `bar v0.1.0`
1288-
... which is depended on by `foo v0.0.1 ([CWD])`
1289-
As a reminder, you're using offline mode (-Z offline) \
1290-
which can sometimes cause surprising resolution failures, \
1291-
if this error is too confusing you may wish to retry \
1292-
without the offline flag.",
1356+
[ERROR] failed to download `baz v1.0.0`
1357+
1358+
Caused by:
1359+
can't make HTTP request in the offline mode
1360+
",
12931361
)
12941362
.run();
12951363
}

tests/testsuite/support/registry.rs

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ pub fn alt_api_url() -> Url {
126126
///
127127
/// p.cargo("run").with_stdout("24").run();
128128
/// ```
129+
#[must_use]
129130
pub struct Package {
130131
name: String,
131132
vers: String,

0 commit comments

Comments
 (0)