1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use config::Config;
use cargo_metadata;
use std::collections::HashMap;
use std::fs::{read_dir, remove_file};
use std::path::Path;
use std::process::Command;
use std::sync::Arc;
const TARGET_DIR: &str = "target/rls";
#[derive(Clone)]
pub struct Builder {
config: Arc<Config>,
build_args: BuildArgs,
}
#[derive(Clone, Debug)]
pub struct BuildArgs {
pub program: String,
pub args: Vec<String>,
pub workspace_root: String,
}
impl Builder {
pub fn new(
config: Arc<Config>,
build_args: BuildArgs,
) -> Builder {
Builder { config, build_args }
}
fn init_cmd(&self) -> Command {
let mut cmd = Command::new(&self.build_args.program);
cmd.arg("check");
cmd.args(&self.build_args.args);
cmd.env("RUSTFLAGS", "-Zunstable-options -Zsave-analysis");
cmd.env("CARGO_TARGET_DIR", TARGET_DIR);
cmd.env("RUST_LOG", "");
cmd
}
pub fn build(&self) -> Option<i32> {
let mut cmd = self.init_cmd();
let status = cmd.status().expect("Running build failed");
let result = status.code();
self.clean_analysis();
result
}
fn clean_analysis(&self) {
let crate_names = cargo_metadata::metadata_deps(None, true)
.map(|metadata| metadata.packages)
.unwrap_or_default()
.into_iter()
.map(|package| package.name.replace("-", "_"))
.collect::<Vec<_>>();
let analysis_dir = Path::new(&TARGET_DIR)
.join("debug")
.join("deps")
.join("save-analysis");
if let Ok(dir_contents) = read_dir(&analysis_dir) {
let mut buckets = HashMap::new();
for entry in dir_contents {
let entry = entry.expect("unexpected error reading save-analysis directory");
let name = entry.file_name();
let mut name = name.to_str().unwrap();
if !name.ends_with("json") {
continue;
}
let hyphen = name.find('-');
let hyphen = match hyphen {
Some(h) => h,
None => continue,
};
let name = &name[..hyphen];
let match_name = if name.starts_with("lib") {
&name[3..]
} else {
&name
};
if !crate_names.iter().any(|name| name == match_name) {
info!("deleting {:?}", entry.path());
if let Err(e) = remove_file(entry.path()) {
debug!("Error deleting file, {:?}: {}", entry.file_name(), e);
}
continue;
}
buckets
.entry(name.to_owned())
.or_insert_with(|| vec![])
.push((
entry.path(),
entry
.metadata()
.expect("no file metadata")
.modified()
.expect("no modified time"),
))
}
for bucket in buckets.values_mut() {
if bucket.len() <= 1 {
continue;
}
bucket.sort_by(|a, b| b.1.cmp(&a.1));
for &(ref path, _) in &bucket[1..] {
info!("deleting {:?}", path);
if let Err(e) = remove_file(path) {
debug!("Error deleting file, {:?}: {}", path, e);
}
}
}
}
}
}