]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | use std::fs; |
2 | use std::fs::File; | |
3 | use std::io::prelude::*; | |
4 | use std::path::{Path, PathBuf}; | |
5 | ||
6 | // This module takes an absolute path to a rustc repo and alters the dependencies to point towards | |
7 | // the respective rustc subcrates instead of using extern crate xyz. | |
8 | // This allows rust analyzer to analyze rustc internals and show proper information inside clippy | |
9 | // code. See https://github.com/rust-analyzer/rust-analyzer/issues/3517 and https://github.com/rust-lang/rust-clippy/issues/5514 for details | |
10 | ||
11 | /// # Panics | |
12 | /// | |
13 | /// Panics if `rustc_path` does not lead to a rustc repo or the files could not be read | |
14 | pub fn run(rustc_path: Option<&str>) { | |
15 | // we can unwrap here because the arg is required by clap | |
16 | let rustc_path = PathBuf::from(rustc_path.unwrap()) | |
17 | .canonicalize() | |
18 | .expect("failed to get the absolute repo path"); | |
19 | assert!(rustc_path.is_dir(), "path is not a directory"); | |
20 | let rustc_source_basedir = rustc_path.join("compiler"); | |
21 | assert!( | |
22 | rustc_source_basedir.is_dir(), | |
23 | "are you sure the path leads to a rustc repo?" | |
24 | ); | |
25 | ||
26 | let clippy_root_manifest = fs::read_to_string("Cargo.toml").expect("failed to read ./Cargo.toml"); | |
27 | let clippy_root_lib_rs = fs::read_to_string("src/driver.rs").expect("failed to read ./src/driver.rs"); | |
28 | inject_deps_into_manifest( | |
29 | &rustc_source_basedir, | |
30 | "Cargo.toml", | |
31 | &clippy_root_manifest, | |
32 | &clippy_root_lib_rs, | |
33 | ) | |
34 | .expect("Failed to inject deps into ./Cargo.toml"); | |
35 | ||
36 | let clippy_lints_manifest = | |
37 | fs::read_to_string("clippy_lints/Cargo.toml").expect("failed to read ./clippy_lints/Cargo.toml"); | |
38 | let clippy_lints_lib_rs = | |
39 | fs::read_to_string("clippy_lints/src/lib.rs").expect("failed to read ./clippy_lints/src/lib.rs"); | |
40 | inject_deps_into_manifest( | |
41 | &rustc_source_basedir, | |
42 | "clippy_lints/Cargo.toml", | |
43 | &clippy_lints_manifest, | |
44 | &clippy_lints_lib_rs, | |
45 | ) | |
46 | .expect("Failed to inject deps into ./clippy_lints/Cargo.toml"); | |
47 | } | |
48 | ||
49 | fn inject_deps_into_manifest( | |
50 | rustc_source_dir: &Path, | |
51 | manifest_path: &str, | |
52 | cargo_toml: &str, | |
53 | lib_rs: &str, | |
54 | ) -> std::io::Result<()> { | |
55 | // do not inject deps if we have aleady done so | |
56 | if cargo_toml.contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { | |
57 | eprintln!( | |
cdc7bbd5 | 58 | "cargo dev ide_setup: warning: deps already found inside {}, doing nothing.", |
f20569fa XL |
59 | manifest_path |
60 | ); | |
61 | return Ok(()); | |
62 | } | |
63 | ||
64 | let extern_crates = lib_rs | |
65 | .lines() | |
66 | // get the deps | |
67 | .filter(|line| line.starts_with("extern crate")) | |
68 | // we have something like "extern crate foo;", we only care about the "foo" | |
69 | // ↓ ↓ | |
70 | // extern crate rustc_middle; | |
71 | .map(|s| &s[13..(s.len() - 1)]); | |
72 | ||
73 | let new_deps = extern_crates.map(|dep| { | |
74 | // format the dependencies that are going to be put inside the Cargo.toml | |
75 | format!( | |
76 | "{dep} = {{ path = \"{source_path}/{dep}\" }}\n", | |
77 | dep = dep, | |
78 | source_path = rustc_source_dir.display() | |
79 | ) | |
80 | }); | |
81 | ||
82 | // format a new [dependencies]-block with the new deps we need to inject | |
83 | let mut all_deps = String::from("[target.'cfg(NOT_A_PLATFORM)'.dependencies]\n"); | |
84 | new_deps.for_each(|dep_line| { | |
85 | all_deps.push_str(&dep_line); | |
86 | }); | |
87 | all_deps.push_str("\n[dependencies]\n"); | |
88 | ||
89 | // replace "[dependencies]" with | |
90 | // [dependencies] | |
91 | // dep1 = { path = ... } | |
92 | // dep2 = { path = ... } | |
93 | // etc | |
94 | let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1); | |
95 | ||
96 | // println!("{}", new_manifest); | |
97 | let mut file = File::create(manifest_path)?; | |
98 | file.write_all(new_manifest.as_bytes())?; | |
99 | ||
100 | println!("Dependency paths injected: {}", manifest_path); | |
101 | ||
102 | Ok(()) | |
103 | } |