@@ -14,6 +14,10 @@ use std::fs::File;
14
14
use std:: io:: Read ;
15
15
use std:: path:: Path ;
16
16
17
+ use std:: process:: Command ;
18
+
19
+ use serde_json;
20
+
17
21
static LICENSES : & ' static [ & ' static str ] = & [
18
22
"MIT/Apache-2.0" ,
19
23
"MIT / Apache-2.0" ,
@@ -44,31 +48,68 @@ static EXCEPTIONS: &'static [&'static str] = &[
44
48
"clippy_lints" , // MPL-2.0 rls
45
49
] ;
46
50
51
+ // Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
52
+ static WHITELIST : & ' static [ ( & ' static str , & ' static str ) ] = & [ ] ;
53
+
54
+ // Some type for Serde to deserialize the output of `cargo metadata` to...
55
+
56
+ #[ derive( Deserialize ) ]
57
+ struct Output {
58
+ packages : Vec < Package > ,
59
+ _resolve : String ,
60
+ }
61
+
62
+ #[ derive( Deserialize ) ]
63
+ struct Package {
64
+ _id : String ,
65
+ name : String ,
66
+ version : String ,
67
+ _source : Option < String > ,
68
+ _manifest_path : String ,
69
+ }
70
+
71
+ /// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
72
+ ///
73
+ /// Specifically, this checks that the license is correct and that the dependencies are on the
74
+ /// whitelist.
47
75
pub fn check ( path : & Path , bad : & mut bool ) {
76
+ // Check licences
48
77
let path = path. join ( "vendor" ) ;
49
78
assert ! ( path. exists( ) , "vendor directory missing" ) ;
50
79
let mut saw_dir = false ;
51
- ' next_path : for dir in t ! ( path. read_dir( ) ) {
80
+ for dir in t ! ( path. read_dir( ) ) {
52
81
saw_dir = true ;
53
82
let dir = t ! ( dir) ;
54
83
55
84
// skip our exceptions
56
- for exception in EXCEPTIONS {
57
- if dir. path ( )
85
+ if EXCEPTIONS . iter ( ) . any ( |exception| {
86
+ dir. path ( )
58
87
. to_str ( )
59
88
. unwrap ( )
60
89
. contains ( & format ! ( "src/vendor/{}" , exception) )
61
- {
62
- continue ' next_path;
63
- }
90
+ } ) {
91
+ continue ;
64
92
}
65
93
66
94
let toml = dir. path ( ) . join ( "Cargo.toml" ) ;
67
- if !check_license ( & toml) {
68
- * bad = true ;
69
- }
95
+ * bad = * bad || !check_license ( & toml) ;
70
96
}
71
97
assert ! ( saw_dir, "no vendored source" ) ;
98
+
99
+ // Check dependencies
100
+ let deps = get_deps ( & path) ;
101
+ * bad = * bad
102
+ || deps. iter ( ) . any (
103
+ |& Package {
104
+ ref name,
105
+ ref version,
106
+ ..
107
+ } | {
108
+ WHITELIST
109
+ . iter ( )
110
+ . all ( |& ( wname, wversion) | name != wname || version != wversion)
111
+ } ,
112
+ ) ;
72
113
}
73
114
74
115
fn check_license ( path : & Path ) -> bool {
@@ -109,3 +150,20 @@ fn extract_license(line: &str) -> String {
109
150
"bad-license-parse" . into ( )
110
151
}
111
152
}
153
+
154
+ fn get_deps ( path : & Path ) -> Vec < Package > {
155
+ // Run `cargo metadata` to get the set of dependencies
156
+ let output = Command :: new ( "cargo" )
157
+ . arg ( "metadata" )
158
+ . arg ( "--format-version" )
159
+ . arg ( "1" )
160
+ . arg ( "--manifest-path" )
161
+ . arg ( path. join ( "Cargo.toml" ) )
162
+ . output ( )
163
+ . expect ( "Unable to run `cargo metadata`" )
164
+ . stdout ;
165
+ let output = String :: from_utf8_lossy ( & output) ;
166
+ let output: Output = serde_json:: from_str ( & output) . unwrap ( ) ;
167
+
168
+ output. packages
169
+ }
0 commit comments