Skip to content

Commit e3b8c61

Browse files
committed
feat: Make rust-analyzer work partially when missing an internet connection
1 parent 0765978 commit e3b8c61

File tree

3 files changed

+65
-14
lines changed

3 files changed

+65
-14
lines changed

crates/project-model/src/build_dependencies.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ impl WorkspaceBuildScripts {
7575
workspace.manifest_path(),
7676
current_dir,
7777
sysroot,
78+
workspace.no_deps(),
7879
)?;
7980
Self::run_per_ws(cmd, workspace, progress)
8081
}
@@ -105,6 +106,7 @@ impl WorkspaceBuildScripts {
105106
&ManifestPath::try_from(workspace_root.clone()).unwrap(),
106107
current_dir,
107108
&Sysroot::empty(),
109+
false,
108110
)?;
109111
// NB: Cargo.toml could have been modified between `cargo metadata` and
110112
// `cargo check`. We shouldn't assume that package ids we see here are
@@ -399,6 +401,7 @@ impl WorkspaceBuildScripts {
399401
manifest_path: &ManifestPath,
400402
current_dir: &AbsPath,
401403
sysroot: &Sysroot,
404+
no_deps: bool,
402405
) -> io::Result<Command> {
403406
let mut cmd = match config.run_build_script_command.as_deref() {
404407
Some([program, args @ ..]) => {
@@ -455,6 +458,9 @@ impl WorkspaceBuildScripts {
455458
}
456459

457460
cmd.arg("--keep-going");
461+
if no_deps {
462+
cmd.arg("--no-deps");
463+
}
458464

459465
cmd
460466
}

crates/project-model/src/cargo_workspace.rs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pub struct CargoWorkspace {
3333
workspace_root: AbsPathBuf,
3434
target_directory: AbsPathBuf,
3535
manifest_path: ManifestPath,
36+
// Whether this workspace was queried with `--no-deps`.
37+
no_deps: bool,
3638
}
3739

3840
impl ops::Index<Package> for CargoWorkspace {
@@ -259,6 +261,18 @@ impl CargoWorkspace {
259261
sysroot: &Sysroot,
260262
locked: bool,
261263
progress: &dyn Fn(String),
264+
) -> anyhow::Result<cargo_metadata::Metadata> {
265+
Self::fetch_metadata_(cargo_toml, current_dir, config, sysroot, locked, false, progress)
266+
}
267+
268+
fn fetch_metadata_(
269+
cargo_toml: &ManifestPath,
270+
current_dir: &AbsPath,
271+
config: &CargoConfig,
272+
sysroot: &Sysroot,
273+
locked: bool,
274+
no_deps: bool,
275+
progress: &dyn Fn(String),
262276
) -> anyhow::Result<cargo_metadata::Metadata> {
263277
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
264278

@@ -314,6 +328,9 @@ impl CargoWorkspace {
314328
if locked {
315329
other_options.push("--locked".to_owned());
316330
}
331+
if no_deps {
332+
other_options.push("--no-deps".to_owned());
333+
}
317334
meta.other_options(other_options);
318335

319336
// FIXME: Fetching metadata is a slow process, as it might require
@@ -324,6 +341,22 @@ impl CargoWorkspace {
324341
(|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
325342
let output = meta.cargo_command().output()?;
326343
if !output.status.success() {
344+
if !no_deps {
345+
// If we failed to fetch metadata with deps, try again without them.
346+
// This makes r-a still work partially when offline.
347+
if let Ok(metadata) = Self::fetch_metadata_(
348+
cargo_toml,
349+
current_dir,
350+
config,
351+
sysroot,
352+
locked,
353+
true,
354+
progress,
355+
) {
356+
return Ok(metadata);
357+
}
358+
}
359+
327360
return Err(cargo_metadata::Error::CargoMetadata {
328361
stderr: String::from_utf8(output.stderr)?,
329362
});
@@ -431,8 +464,8 @@ impl CargoWorkspace {
431464
pkg_data.targets.push(tgt);
432465
}
433466
}
434-
let resolve = meta.resolve.expect("metadata executed with deps");
435-
for mut node in resolve.nodes {
467+
let no_deps = meta.resolve.is_none();
468+
for mut node in meta.resolve.map_or_else(Vec::new, |it| it.nodes) {
436469
let &source = pkg_by_id.get(&node.id).unwrap();
437470
node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
438471
let dependencies = node
@@ -451,7 +484,14 @@ impl CargoWorkspace {
451484

452485
let target_directory = AbsPathBuf::assert(meta.target_directory);
453486

454-
CargoWorkspace { packages, targets, workspace_root, target_directory, manifest_path }
487+
CargoWorkspace {
488+
packages,
489+
targets,
490+
workspace_root,
491+
target_directory,
492+
manifest_path,
493+
no_deps,
494+
}
455495
}
456496

457497
pub fn packages(&self) -> impl ExactSizeIterator<Item = Package> + '_ {
@@ -533,6 +573,10 @@ impl CargoWorkspace {
533573
fn is_unique(&self, name: &str) -> bool {
534574
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
535575
}
576+
577+
pub fn no_deps(&self) -> bool {
578+
self.no_deps
579+
}
536580
}
537581

538582
fn find_list_of_build_targets(

crates/project-model/src/sysroot.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -372,18 +372,19 @@ impl Sysroot {
372372
.flatten()
373373
};
374374

375-
let resolve = res.resolve.as_mut().expect("metadata executed with deps");
376-
resolve.nodes.retain_mut(|node| {
377-
// Replace `rustc-std-workspace` crate with the actual one in the dependency list
378-
node.deps.iter_mut().for_each(|dep| {
379-
let real_pkg = patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg);
380-
if let Some((_, real)) = real_pkg {
381-
dep.pkg = real;
382-
}
375+
if let Some(resolve) = res.resolve.as_mut() {
376+
resolve.nodes.retain_mut(|node| {
377+
// Replace `rustc-std-workspace` crate with the actual one in the dependency list
378+
node.deps.iter_mut().for_each(|dep| {
379+
let real_pkg = patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg);
380+
if let Some((_, real)) = real_pkg {
381+
dep.pkg = real;
382+
}
383+
});
384+
// Remove this node if it's a fake one
385+
!patches.clone().any(|((_, fake), _)| fake == node.id)
383386
});
384-
// Remove this node if it's a fake one
385-
!patches.clone().any(|((_, fake), _)| fake == node.id)
386-
});
387+
}
387388
// Remove the fake ones from the package list
388389
patches.map(|((idx, _), _)| idx).sorted().rev().for_each(|idx| {
389390
res.packages.remove(idx);

0 commit comments

Comments
 (0)