mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Re-implement dependecny tracking for cargo script
This commit is contained in:
parent
2f828073aa
commit
0b24599cf9
10 changed files with 187 additions and 234 deletions
|
@ -2,7 +2,7 @@
|
|||
//! metadata` or `rust-project.json`) into representation stored in the salsa
|
||||
//! database -- `CrateGraph`.
|
||||
|
||||
use std::{collections::VecDeque, fmt, fs, io::BufRead, iter, sync};
|
||||
use std::{collections::VecDeque, fmt, fs, iter, sync};
|
||||
|
||||
use anyhow::{format_err, Context};
|
||||
use base_db::{
|
||||
|
@ -99,9 +99,9 @@ pub enum ProjectWorkspace {
|
|||
// //
|
||||
/// Project with a set of disjoint files, not belonging to any particular workspace.
|
||||
/// Backed by basic sysroot crates for basic completion and highlighting.
|
||||
DetachedFiles {
|
||||
/// The set of detached files.
|
||||
files: Vec<AbsPathBuf>,
|
||||
DetachedFile {
|
||||
/// The file in question.
|
||||
file: AbsPathBuf,
|
||||
/// The sysroot loaded for this workspace.
|
||||
sysroot: Result<Sysroot, Option<String>>,
|
||||
/// Holds cfg flags for the current target. We get those by running
|
||||
|
@ -120,50 +120,6 @@ pub enum ProjectWorkspace {
|
|||
},
|
||||
}
|
||||
|
||||
/// Tracks the cargo toml parts in cargo scripts, to detect if they
|
||||
/// changed and reload workspace in that case.
|
||||
pub struct CargoScriptTomls(pub FxHashMap<AbsPathBuf, String>);
|
||||
|
||||
impl CargoScriptTomls {
|
||||
fn extract_toml_part(p: &AbsPath) -> Option<String> {
|
||||
let mut r = String::new();
|
||||
let f = std::fs::File::open(p).ok()?;
|
||||
let f = std::io::BufReader::new(f);
|
||||
let mut started = false;
|
||||
for line in f.lines() {
|
||||
let line = line.ok()?;
|
||||
if started {
|
||||
if line.trim() == "//! ```" {
|
||||
return Some(r);
|
||||
}
|
||||
r += &line;
|
||||
} else {
|
||||
if line.trim() == "//! ```cargo" {
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn track_file(&mut self, p: AbsPathBuf) {
|
||||
let toml = CargoScriptTomls::extract_toml_part(&p).unwrap_or_default();
|
||||
self.0.insert(p, toml);
|
||||
}
|
||||
|
||||
pub fn need_reload(&mut self, p: &AbsPath) -> bool {
|
||||
let Some(prev) = self.0.get_mut(p) else {
|
||||
return false; // File is not tracked
|
||||
};
|
||||
let next = CargoScriptTomls::extract_toml_part(p).unwrap_or_default();
|
||||
if *prev == next {
|
||||
return false;
|
||||
}
|
||||
*prev = next;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ProjectWorkspace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Make sure this isn't too verbose.
|
||||
|
@ -213,8 +169,8 @@ impl fmt::Debug for ProjectWorkspace {
|
|||
.field("n_cfg_overrides", &cfg_overrides.len());
|
||||
debug_struct.finish()
|
||||
}
|
||||
ProjectWorkspace::DetachedFiles {
|
||||
files,
|
||||
ProjectWorkspace::DetachedFile {
|
||||
file,
|
||||
sysroot,
|
||||
rustc_cfg,
|
||||
toolchain,
|
||||
|
@ -223,7 +179,8 @@ impl fmt::Debug for ProjectWorkspace {
|
|||
cargo_script,
|
||||
} => f
|
||||
.debug_struct("DetachedFiles")
|
||||
.field("n_files", &files.len())
|
||||
.field("file", &file)
|
||||
.field("cargo_script", &cargo_script.is_some())
|
||||
.field("sysroot", &sysroot.is_ok())
|
||||
.field("cargo_script", &cargo_script.is_some())
|
||||
.field("n_rustc_cfg", &rustc_cfg.len())
|
||||
|
@ -479,71 +436,79 @@ impl ProjectWorkspace {
|
|||
pub fn load_detached_files(
|
||||
detached_files: Vec<AbsPathBuf>,
|
||||
config: &CargoConfig,
|
||||
cargo_script_tomls: &mut CargoScriptTomls,
|
||||
) -> anyhow::Result<ProjectWorkspace> {
|
||||
let dir = detached_files
|
||||
.first()
|
||||
.and_then(|it| it.parent())
|
||||
.ok_or_else(|| format_err!("No detached files to load"))?;
|
||||
let sysroot = match &config.sysroot {
|
||||
Some(RustLibSource::Path(path)) => {
|
||||
Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata)
|
||||
.map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}")))
|
||||
}
|
||||
Some(RustLibSource::Discover) => Sysroot::discover(
|
||||
dir,
|
||||
&config.extra_env,
|
||||
config.sysroot_query_metadata,
|
||||
)
|
||||
.map_err(|e| {
|
||||
Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}"))
|
||||
}),
|
||||
None => Err(None),
|
||||
};
|
||||
) -> Vec<anyhow::Result<ProjectWorkspace>> {
|
||||
dbg!(detached_files
|
||||
.into_iter()
|
||||
.map(|detached_file| {
|
||||
let dir = detached_file
|
||||
.parent()
|
||||
.ok_or_else(|| format_err!("detached file has no parent"))?;
|
||||
let sysroot = match &config.sysroot {
|
||||
Some(RustLibSource::Path(path)) => {
|
||||
Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata)
|
||||
.map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}")))
|
||||
}
|
||||
Some(RustLibSource::Discover) => {
|
||||
Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata)
|
||||
.map_err(|e| {
|
||||
Some(format!(
|
||||
"Failed to find sysroot for {dir}. Is rust-src installed? {e}"
|
||||
))
|
||||
})
|
||||
}
|
||||
None => Err(None),
|
||||
};
|
||||
|
||||
let sysroot_ref = sysroot.as_ref().ok();
|
||||
let toolchain =
|
||||
match get_toolchain_version(dir, sysroot_ref, Tool::Rustc, &config.extra_env, "rustc ")
|
||||
{
|
||||
Ok(it) => it,
|
||||
Err(e) => {
|
||||
tracing::error!("{e}");
|
||||
None
|
||||
}
|
||||
};
|
||||
let sysroot_ref = sysroot.as_ref().ok();
|
||||
let toolchain = match get_toolchain_version(
|
||||
dir,
|
||||
sysroot_ref,
|
||||
Tool::Rustc,
|
||||
&config.extra_env,
|
||||
"rustc ",
|
||||
) {
|
||||
Ok(it) => it,
|
||||
Err(e) => {
|
||||
tracing::error!("{e}");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref));
|
||||
let data_layout = target_data_layout::get(
|
||||
RustcDataLayoutConfig::Rustc(sysroot_ref),
|
||||
None,
|
||||
&config.extra_env,
|
||||
);
|
||||
let cargo_toml = ManifestPath::try_from(detached_files[0].clone()).unwrap();
|
||||
let meta = CargoWorkspace::fetch_metadata(
|
||||
&cargo_toml,
|
||||
cargo_toml.parent(),
|
||||
config,
|
||||
sysroot_ref,
|
||||
&|_| (),
|
||||
)
|
||||
.with_context(|| {
|
||||
format!("Failed to read Cargo metadata from Cargo.toml file {cargo_toml}")
|
||||
})?;
|
||||
let cargo = CargoWorkspace::new(meta);
|
||||
let rustc_cfg =
|
||||
rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref));
|
||||
let data_layout = target_data_layout::get(
|
||||
RustcDataLayoutConfig::Rustc(sysroot_ref),
|
||||
None,
|
||||
&config.extra_env,
|
||||
);
|
||||
|
||||
for file in &detached_files {
|
||||
cargo_script_tomls.track_file(file.clone());
|
||||
}
|
||||
let cargo_script = ManifestPath::try_from(detached_file.clone())
|
||||
.ok()
|
||||
.and_then(|file| {
|
||||
CargoWorkspace::fetch_metadata(
|
||||
&file,
|
||||
file.parent(),
|
||||
config,
|
||||
sysroot_ref,
|
||||
&|_| (),
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.map(CargoWorkspace::new);
|
||||
|
||||
Ok(ProjectWorkspace::DetachedFiles {
|
||||
files: detached_files,
|
||||
sysroot,
|
||||
rustc_cfg,
|
||||
toolchain,
|
||||
target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
|
||||
cfg_overrides: config.cfg_overrides.clone(),
|
||||
cargo_script: Some(cargo),
|
||||
})
|
||||
Ok(ProjectWorkspace::DetachedFile {
|
||||
file: detached_file,
|
||||
sysroot,
|
||||
rustc_cfg,
|
||||
toolchain,
|
||||
target_layout: data_layout
|
||||
.map(Arc::from)
|
||||
.map_err(|it| Arc::from(it.to_string())),
|
||||
cfg_overrides: config.cfg_overrides.clone(),
|
||||
cargo_script,
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Runs the build scripts for this [`ProjectWorkspace`].
|
||||
|
@ -565,7 +530,7 @@ impl ProjectWorkspace {
|
|||
format!("Failed to run build scripts for {}", cargo.workspace_root())
|
||||
})
|
||||
}
|
||||
ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
|
||||
ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFile { .. } => {
|
||||
Ok(WorkspaceBuildScripts::default())
|
||||
}
|
||||
}
|
||||
|
@ -623,11 +588,11 @@ impl ProjectWorkspace {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn workspace_definition_path(&self) -> Option<&AbsPath> {
|
||||
pub fn workspace_definition_path(&self) -> &AbsPath {
|
||||
match self {
|
||||
ProjectWorkspace::Cargo { cargo, .. } => Some(cargo.workspace_root()),
|
||||
ProjectWorkspace::Json { project, .. } => Some(project.path()),
|
||||
ProjectWorkspace::DetachedFiles { .. } => None,
|
||||
ProjectWorkspace::Cargo { cargo, .. } => cargo.workspace_root(),
|
||||
ProjectWorkspace::Json { project, .. } => project.path(),
|
||||
ProjectWorkspace::DetachedFile { file, .. } => file,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -635,10 +600,10 @@ impl ProjectWorkspace {
|
|||
match self {
|
||||
ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. }
|
||||
| ProjectWorkspace::Json { sysroot: Ok(sysroot), .. }
|
||||
| ProjectWorkspace::DetachedFiles { sysroot: Ok(sysroot), .. } => {
|
||||
| ProjectWorkspace::DetachedFile { sysroot: Ok(sysroot), .. } => {
|
||||
sysroot.discover_proc_macro_srv()
|
||||
}
|
||||
ProjectWorkspace::DetachedFiles { .. } => {
|
||||
ProjectWorkspace::DetachedFile { .. } => {
|
||||
Err(anyhow::format_err!("cannot find proc-macro server, no sysroot was found"))
|
||||
}
|
||||
ProjectWorkspace::Cargo { cargo, .. } => Err(anyhow::format_err!(
|
||||
|
@ -769,15 +734,13 @@ impl ProjectWorkspace {
|
|||
}))
|
||||
.collect()
|
||||
}
|
||||
ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
|
||||
.iter()
|
||||
.map(|detached_file| PackageRoot {
|
||||
is_local: true,
|
||||
include: vec![detached_file.clone()],
|
||||
exclude: Vec::new(),
|
||||
})
|
||||
.chain(mk_sysroot(sysroot.as_ref()))
|
||||
.collect(),
|
||||
ProjectWorkspace::DetachedFile { file, sysroot, .. } => iter::once(PackageRoot {
|
||||
is_local: true,
|
||||
include: vec![file.clone()],
|
||||
exclude: Vec::new(),
|
||||
})
|
||||
.chain(mk_sysroot(sysroot.as_ref()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -793,9 +756,9 @@ impl ProjectWorkspace {
|
|||
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
|
||||
cargo.packages().len() + sysroot_package_len + rustc_package_len
|
||||
}
|
||||
ProjectWorkspace::DetachedFiles { sysroot, files, .. } => {
|
||||
ProjectWorkspace::DetachedFile { sysroot, .. } => {
|
||||
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
|
||||
sysroot_package_len + files.len()
|
||||
sysroot_package_len + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -848,8 +811,8 @@ impl ProjectWorkspace {
|
|||
),
|
||||
sysroot,
|
||||
),
|
||||
ProjectWorkspace::DetachedFiles {
|
||||
files,
|
||||
ProjectWorkspace::DetachedFile {
|
||||
file,
|
||||
sysroot,
|
||||
rustc_cfg,
|
||||
toolchain: _,
|
||||
|
@ -868,10 +831,10 @@ impl ProjectWorkspace {
|
|||
&WorkspaceBuildScripts::default(),
|
||||
)
|
||||
} else {
|
||||
detached_files_to_crate_graph(
|
||||
detached_file_to_crate_graph(
|
||||
rustc_cfg.clone(),
|
||||
load,
|
||||
files,
|
||||
file,
|
||||
sysroot.as_ref().ok(),
|
||||
cfg_overrides,
|
||||
)
|
||||
|
@ -949,8 +912,8 @@ impl ProjectWorkspace {
|
|||
&& cfg_overrides == o_cfg_overrides
|
||||
}
|
||||
(
|
||||
Self::DetachedFiles {
|
||||
files,
|
||||
Self::DetachedFile {
|
||||
file,
|
||||
sysroot,
|
||||
rustc_cfg,
|
||||
cargo_script,
|
||||
|
@ -958,8 +921,8 @@ impl ProjectWorkspace {
|
|||
target_layout,
|
||||
cfg_overrides,
|
||||
},
|
||||
Self::DetachedFiles {
|
||||
files: o_files,
|
||||
Self::DetachedFile {
|
||||
file: o_file,
|
||||
sysroot: o_sysroot,
|
||||
rustc_cfg: o_rustc_cfg,
|
||||
cargo_script: o_cargo_script,
|
||||
|
@ -968,7 +931,7 @@ impl ProjectWorkspace {
|
|||
cfg_overrides: o_cfg_overrides,
|
||||
},
|
||||
) => {
|
||||
files == o_files
|
||||
file == o_file
|
||||
&& sysroot == o_sysroot
|
||||
&& rustc_cfg == o_rustc_cfg
|
||||
&& toolchain == o_toolchain
|
||||
|
@ -1285,10 +1248,10 @@ fn cargo_to_crate_graph(
|
|||
res
|
||||
}
|
||||
|
||||
fn detached_files_to_crate_graph(
|
||||
fn detached_file_to_crate_graph(
|
||||
rustc_cfg: Vec<CfgFlag>,
|
||||
load: FileLoader<'_>,
|
||||
detached_files: &[AbsPathBuf],
|
||||
detached_file: &AbsPathBuf,
|
||||
sysroot: Option<&Sysroot>,
|
||||
override_cfg: &CfgOverrides,
|
||||
) -> (CrateGraph, ProcMacroPaths) {
|
||||
|
@ -1305,34 +1268,32 @@ fn detached_files_to_crate_graph(
|
|||
override_cfg.apply(&mut cfg_options, "");
|
||||
let cfg_options = Arc::new(cfg_options);
|
||||
|
||||
for detached_file in detached_files {
|
||||
let file_id = match load(detached_file) {
|
||||
Some(file_id) => file_id,
|
||||
None => {
|
||||
tracing::error!("Failed to load detached file {:?}", detached_file);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let display_name = detached_file
|
||||
.file_stem()
|
||||
.map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_owned()));
|
||||
let detached_file_crate = crate_graph.add_crate_root(
|
||||
file_id,
|
||||
Edition::CURRENT,
|
||||
display_name.clone(),
|
||||
None,
|
||||
cfg_options.clone(),
|
||||
None,
|
||||
Env::default(),
|
||||
false,
|
||||
CrateOrigin::Local {
|
||||
repo: None,
|
||||
name: display_name.map(|n| n.canonical_name().to_owned()),
|
||||
},
|
||||
);
|
||||
let file_id = match load(detached_file) {
|
||||
Some(file_id) => file_id,
|
||||
None => {
|
||||
tracing::error!("Failed to load detached file {:?}", detached_file);
|
||||
return (crate_graph, FxHashMap::default());
|
||||
}
|
||||
};
|
||||
let display_name = detached_file
|
||||
.file_stem()
|
||||
.map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_owned()));
|
||||
let detached_file_crate = crate_graph.add_crate_root(
|
||||
file_id,
|
||||
Edition::CURRENT,
|
||||
display_name.clone(),
|
||||
None,
|
||||
cfg_options.clone(),
|
||||
None,
|
||||
Env::default(),
|
||||
false,
|
||||
CrateOrigin::Local {
|
||||
repo: None,
|
||||
name: display_name.map(|n| n.canonical_name().to_owned()),
|
||||
},
|
||||
);
|
||||
|
||||
public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate);
|
||||
}
|
||||
public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate);
|
||||
(crate_graph, FxHashMap::default())
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue