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
use std::path::{Path, PathBuf};
use std::process::Command;
pub struct CargoDirectories {
pub workspace_root: PathBuf,
pub target_directory: PathBuf,
}
impl CargoDirectories {
fn from_cargo(cargo_executable: &str, manifest_dir: &Path) -> Self {
let output = Command::new(cargo_executable)
.current_dir(manifest_dir)
.args(["metadata", "--no-deps", "--format-version=1"])
.output()
.unwrap();
let result = String::from_utf8(output.stdout).expect("Command output should be utf-8");
let value = serde_json::from_str::<serde_json::Value>(&result)
.expect("Should match the CargoMetadata definition");
let obj = value.as_object().expect("Metadata should be object");
let target_directory = PathBuf::from(
obj.get("target_directory")
.expect("Should have target directory")
.as_str()
.unwrap()
.to_owned(),
);
let workspace_root = PathBuf::from(
obj.get("workspace_root")
.expect("Should have target directory")
.as_str()
.unwrap()
.to_owned(),
);
CargoDirectories {
target_directory,
workspace_root,
}
}
pub fn new(cargo_executable: &str) -> CargoDirectories {
let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
let mut workspace_root = manifest_dir.clone();
loop {
let target = workspace_root.join("target");
let cargo_toml = workspace_root.join("Cargo.toml");
if target.exists() && cargo_toml.exists() {
return CargoDirectories {
target_directory: target,
workspace_root,
};
}
if !workspace_root.pop() {
break;
}
}
CargoDirectories::from_cargo(cargo_executable, &manifest_dir)
}
}