mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 21:13:37 +00:00
feat: Make rust-analyzer work partially when missing an internet connection
This commit is contained in:
parent
07659783fd
commit
07c1b83e98
4 changed files with 75 additions and 17 deletions
|
@ -33,6 +33,8 @@ pub struct CargoWorkspace {
|
||||||
workspace_root: AbsPathBuf,
|
workspace_root: AbsPathBuf,
|
||||||
target_directory: AbsPathBuf,
|
target_directory: AbsPathBuf,
|
||||||
manifest_path: ManifestPath,
|
manifest_path: ManifestPath,
|
||||||
|
// Whether this workspace was queried with `--no-deps`.
|
||||||
|
no_deps: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Index<Package> for CargoWorkspace {
|
impl ops::Index<Package> for CargoWorkspace {
|
||||||
|
@ -259,6 +261,18 @@ impl CargoWorkspace {
|
||||||
sysroot: &Sysroot,
|
sysroot: &Sysroot,
|
||||||
locked: bool,
|
locked: bool,
|
||||||
progress: &dyn Fn(String),
|
progress: &dyn Fn(String),
|
||||||
|
) -> anyhow::Result<cargo_metadata::Metadata> {
|
||||||
|
Self::fetch_metadata_(cargo_toml, current_dir, config, sysroot, locked, false, progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_metadata_(
|
||||||
|
cargo_toml: &ManifestPath,
|
||||||
|
current_dir: &AbsPath,
|
||||||
|
config: &CargoConfig,
|
||||||
|
sysroot: &Sysroot,
|
||||||
|
locked: bool,
|
||||||
|
no_deps: bool,
|
||||||
|
progress: &dyn Fn(String),
|
||||||
) -> anyhow::Result<cargo_metadata::Metadata> {
|
) -> anyhow::Result<cargo_metadata::Metadata> {
|
||||||
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
|
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
|
||||||
|
|
||||||
|
@ -314,6 +328,9 @@ impl CargoWorkspace {
|
||||||
if locked {
|
if locked {
|
||||||
other_options.push("--locked".to_owned());
|
other_options.push("--locked".to_owned());
|
||||||
}
|
}
|
||||||
|
if no_deps {
|
||||||
|
other_options.push("--no-deps".to_owned());
|
||||||
|
}
|
||||||
meta.other_options(other_options);
|
meta.other_options(other_options);
|
||||||
|
|
||||||
// FIXME: Fetching metadata is a slow process, as it might require
|
// FIXME: Fetching metadata is a slow process, as it might require
|
||||||
|
@ -324,6 +341,22 @@ impl CargoWorkspace {
|
||||||
(|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
|
(|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
|
||||||
let output = meta.cargo_command().output()?;
|
let output = meta.cargo_command().output()?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
|
if !no_deps {
|
||||||
|
// If we failed to fetch metadata with deps, try again without them.
|
||||||
|
// This makes r-a still work partially when offline.
|
||||||
|
if let Ok(metadata) = Self::fetch_metadata_(
|
||||||
|
cargo_toml,
|
||||||
|
current_dir,
|
||||||
|
config,
|
||||||
|
sysroot,
|
||||||
|
locked,
|
||||||
|
true,
|
||||||
|
progress,
|
||||||
|
) {
|
||||||
|
return Ok(metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Err(cargo_metadata::Error::CargoMetadata {
|
return Err(cargo_metadata::Error::CargoMetadata {
|
||||||
stderr: String::from_utf8(output.stderr)?,
|
stderr: String::from_utf8(output.stderr)?,
|
||||||
});
|
});
|
||||||
|
@ -431,8 +464,8 @@ impl CargoWorkspace {
|
||||||
pkg_data.targets.push(tgt);
|
pkg_data.targets.push(tgt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let resolve = meta.resolve.expect("metadata executed with deps");
|
let no_deps = meta.resolve.is_none();
|
||||||
for mut node in resolve.nodes {
|
for mut node in meta.resolve.map_or_else(Vec::new, |it| it.nodes) {
|
||||||
let &source = pkg_by_id.get(&node.id).unwrap();
|
let &source = pkg_by_id.get(&node.id).unwrap();
|
||||||
node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
|
node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
|
||||||
let dependencies = node
|
let dependencies = node
|
||||||
|
@ -451,7 +484,14 @@ impl CargoWorkspace {
|
||||||
|
|
||||||
let target_directory = AbsPathBuf::assert(meta.target_directory);
|
let target_directory = AbsPathBuf::assert(meta.target_directory);
|
||||||
|
|
||||||
CargoWorkspace { packages, targets, workspace_root, target_directory, manifest_path }
|
CargoWorkspace {
|
||||||
|
packages,
|
||||||
|
targets,
|
||||||
|
workspace_root,
|
||||||
|
target_directory,
|
||||||
|
manifest_path,
|
||||||
|
no_deps,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn packages(&self) -> impl ExactSizeIterator<Item = Package> + '_ {
|
pub fn packages(&self) -> impl ExactSizeIterator<Item = Package> + '_ {
|
||||||
|
@ -533,6 +573,10 @@ impl CargoWorkspace {
|
||||||
fn is_unique(&self, name: &str) -> bool {
|
fn is_unique(&self, name: &str) -> bool {
|
||||||
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
|
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn no_deps(&self) -> bool {
|
||||||
|
self.no_deps
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_list_of_build_targets(
|
fn find_list_of_build_targets(
|
||||||
|
|
|
@ -372,18 +372,19 @@ impl Sysroot {
|
||||||
.flatten()
|
.flatten()
|
||||||
};
|
};
|
||||||
|
|
||||||
let resolve = res.resolve.as_mut().expect("metadata executed with deps");
|
if let Some(resolve) = res.resolve.as_mut() {
|
||||||
resolve.nodes.retain_mut(|node| {
|
resolve.nodes.retain_mut(|node| {
|
||||||
// Replace `rustc-std-workspace` crate with the actual one in the dependency list
|
// Replace `rustc-std-workspace` crate with the actual one in the dependency list
|
||||||
node.deps.iter_mut().for_each(|dep| {
|
node.deps.iter_mut().for_each(|dep| {
|
||||||
let real_pkg = patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg);
|
let real_pkg = patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg);
|
||||||
if let Some((_, real)) = real_pkg {
|
if let Some((_, real)) = real_pkg {
|
||||||
dep.pkg = real;
|
dep.pkg = real;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
// Remove this node if it's a fake one
|
||||||
|
!patches.clone().any(|((_, fake), _)| fake == node.id)
|
||||||
});
|
});
|
||||||
// Remove this node if it's a fake one
|
}
|
||||||
!patches.clone().any(|((_, fake), _)| fake == node.id)
|
|
||||||
});
|
|
||||||
// Remove the fake ones from the package list
|
// Remove the fake ones from the package list
|
||||||
patches.map(|((idx, _), _)| idx).sorted().rev().for_each(|idx| {
|
patches.map(|((idx, _), _)| idx).sorted().rev().for_each(|idx| {
|
||||||
res.packages.remove(idx);
|
res.packages.remove(idx);
|
||||||
|
|
|
@ -441,14 +441,15 @@ impl ProjectWorkspace {
|
||||||
) -> anyhow::Result<WorkspaceBuildScripts> {
|
) -> anyhow::Result<WorkspaceBuildScripts> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. }
|
ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. }
|
||||||
| ProjectWorkspaceKind::Cargo { cargo, .. } => {
|
| ProjectWorkspaceKind::Cargo { cargo, .. }
|
||||||
|
if !cargo.no_deps() =>
|
||||||
|
{
|
||||||
WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, &self.sysroot)
|
WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, &self.sysroot)
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!("Failed to run build scripts for {}", cargo.workspace_root())
|
format!("Failed to run build scripts for {}", cargo.workspace_root())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ProjectWorkspaceKind::DetachedFile { cargo: None, .. }
|
_ => Ok(WorkspaceBuildScripts::default()),
|
||||||
| ProjectWorkspaceKind::Json { .. } => Ok(WorkspaceBuildScripts::default()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,18 @@ impl GlobalState {
|
||||||
self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
|
self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
|
||||||
|
|
||||||
for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) {
|
for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) {
|
||||||
|
if matches!(
|
||||||
|
&ws.kind,
|
||||||
|
ProjectWorkspaceKind::Cargo { cargo, .. } | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. }
|
||||||
|
if cargo.no_deps()
|
||||||
|
) {
|
||||||
|
status.health |= lsp_ext::Health::Warning;
|
||||||
|
format_to!(
|
||||||
|
message,
|
||||||
|
"Workspace `{}` has been queried without dependencies, connecting to crates.io might have failed.\n\n",
|
||||||
|
ws.manifest_or_root()
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(err) = ws.sysroot.error() {
|
if let Some(err) = ws.sysroot.error() {
|
||||||
status.health |= lsp_ext::Health::Warning;
|
status.health |= lsp_ext::Health::Warning;
|
||||||
format_to!(
|
format_to!(
|
||||||
|
|
Loading…
Reference in a new issue