-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
109 lines (98 loc) · 3.18 KB
/
main.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
use cargo_lock::package::source::GitReference;
use serde::{Deserialize, Serialize};
use serde_json::{self, json};
use std::{env, fs, path::Path, process};
#[derive(Serialize, Deserialize)]
struct ScanResult {
license: Option<String>,
crates: Option<Vec<serde_json::Value>>,
}
fn scan(
project: &String,
should_check_for_cargo_lock: bool,
) -> Result<ScanResult, String> {
let license = {
let cargo_toml_path = Path::new(&project).join("Cargo.toml");
let contents = fs::read_to_string(&cargo_toml_path).map_err(|err| {
format!("Failed to read {:?}: {:?}", &cargo_toml_path, err)
})?;
let manifest: cargo_toml::Manifest =
toml::from_str(&contents).map_err(|err| {
format!("Failed to parse {:?}: {:?}", &cargo_toml_path, err)
})?;
manifest.package.map(|pkg| pkg.license).flatten()
};
let crates = if should_check_for_cargo_lock {
let cargo_lock_path = Path::new(&project).join("Cargo.lock");
let lockfile =
cargo_lock::Lockfile::load(&cargo_lock_path).map_err(|err| {
format!(
"Failed to parse lockfile of {:?}: {:?}",
cargo_lock_path, err
)
})?;
Some(
lockfile
.packages
.iter()
.map(|pkg| {
let source = pkg.source.as_ref().map(|source| {
if source.is_git() {
match source.git_reference() {
Some(git_ref) => {
let git_ref = match git_ref {
GitReference::Tag(tag) => json!({ "tag": "tag", "value": tag }),
GitReference::Branch(branch) => {
let value = source.precise().unwrap_or(branch);
json!({ "tag": "ref", "value": value })
}
GitReference::Rev(rev) => json!({ "tag": "rev", "value": rev }),
};
json!({ "tag": "git", "repository": source.url().to_string(), "ref": git_ref })
},
None => json!({ "tag": "unexpected", "value": source })
}
} else if source.is_default_registry() {
json!({ "tag": "crates.io" })
} else {
json!({ "tag": "unexpected", "value": source })
}
});
json!({ "name": pkg.name, "version": pkg.version, "source": source })
})
.collect(),
)
} else {
None
};
Ok(ScanResult { license, crates })
}
fn main() {
let mut args = env::args();
let _ = args
.next()
.expect("Expected to have the first argument: the program's path");
let project = args
.next()
.expect("Missing the first argument: the project's root");
let should_check_for_cargo_lock = {
let raw = args
.next()
.expect("Missing the second argument: should_check_for_cargo_lock");
match raw.as_str() {
"true" => true,
"false" => false,
_ => {
eprintln!("should_check_for_cargo_lock argument should either be \"true\" or \"false\"");
process::exit(1);
}
}
};
match scan(&project, should_check_for_cargo_lock) {
Ok(result) => println!("{}", json!(result)),
Err(err) => {
eprintln!("{}", err);
process::exit(1);
}
};
}