-
Notifications
You must be signed in to change notification settings - Fork 31
/
build.rs
141 lines (123 loc) · 4.53 KB
/
build.rs
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
// Copyright 2016 The Rustw Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
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;
// FIXME use `join` not `/`
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);
// FIXME(#170) configure save-analysis
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
}
// Remove any old or duplicate json files.
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) {
// We're going to put all files for the same crate in one bucket, then delete duplicates.
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
};
// The JSON file does not correspond with any crate from `cargo
// metadata`, so it is presumably an old dep that has been removed.
// So, we should delete it.
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;
}
// Sort by date created (JSON files are effectively read only)
bucket.sort_by(|a, b| b.1.cmp(&a.1));
// And delete all but the newest file.
for &(ref path, _) in &bucket[1..] {
info!("deleting {:?}", path);
if let Err(e) = remove_file(path) {
debug!("Error deleting file, {:?}: {}", path, e);
}
}
}
}
}
}