@@ -16,6 +16,7 @@ use std::{fmt, fs::write, path::PathBuf};
1616use clap:: ArgMatches ;
1717use serde:: { Deserialize , Serialize } ;
1818use serde_json:: Value ;
19+ //use git2::Repository;
1920
2021// use this to store the crates when interacting with the crates.toml file
2122#[ derive( Debug , Serialize , Deserialize ) ]
@@ -35,12 +36,13 @@ struct TomlCrate {
3536
3637// represents an archive we download from crates.io
3738#[ derive( Debug , Serialize , Deserialize , Eq , Hash , PartialEq ) ]
38- struct CrateSource {
39- name : String ,
40- version : String ,
39+ enum CrateSource {
40+ CratesIo { name : String , version : String } ,
41+ Git { name : String , url : String , commit : String } ,
4142}
4243
4344// represents the extracted sourcecode of a crate
45+ // we actually don't need to special-case git repos here because it does not matter for clippy, yay! (clippy only needs a simple path)
4446#[ derive( Debug ) ]
4547struct Crate {
4648 version : String ,
@@ -72,40 +74,70 @@ impl std::fmt::Display for ClippyWarning {
7274
7375impl CrateSource {
7476 fn download_and_extract ( & self ) -> Crate {
75- let extract_dir = PathBuf :: from ( "target/lintcheck/crates" ) ;
76- let krate_download_dir = PathBuf :: from ( "target/lintcheck/downloads" ) ;
77-
78- // url to download the crate from crates.io
79- let url = format ! (
80- "https://crates.io/api/v1/crates/{}/{}/download" ,
81- self . name, self . version
82- ) ;
83- println ! ( "Downloading and extracting {} {} from {}" , self . name, self . version, url) ;
84- let _ = std:: fs:: create_dir ( "target/lintcheck/" ) ;
85- let _ = std:: fs:: create_dir ( & krate_download_dir) ;
86- let _ = std:: fs:: create_dir ( & extract_dir) ;
87-
88- let krate_file_path = krate_download_dir. join ( format ! ( "{}-{}.crate.tar.gz" , & self . name, & self . version) ) ;
89- // don't download/extract if we already have done so
90- if !krate_file_path. is_file ( ) {
91- // create a file path to download and write the crate data into
92- let mut krate_dest = std:: fs:: File :: create ( & krate_file_path) . unwrap ( ) ;
93- let mut krate_req = ureq:: get ( & url) . call ( ) . unwrap ( ) . into_reader ( ) ;
94- // copy the crate into the file
95- std:: io:: copy ( & mut krate_req, & mut krate_dest) . unwrap ( ) ;
96-
97- // unzip the tarball
98- let ungz_tar = flate2:: read:: GzDecoder :: new ( std:: fs:: File :: open ( & krate_file_path) . unwrap ( ) ) ;
99- // extract the tar archive
100- let mut archive = tar:: Archive :: new ( ungz_tar) ;
101- archive. unpack ( & extract_dir) . expect ( "Failed to extract!" ) ;
102- }
103- // crate is extracted, return a new Krate object which contains the path to the extracted
104- // sources that clippy can check
105- Crate {
106- version : self . version . clone ( ) ,
107- name : self . name . clone ( ) ,
108- path : extract_dir. join ( format ! ( "{}-{}/" , self . name, self . version) ) ,
77+ match self {
78+ CrateSource :: CratesIo { name, version } => {
79+ let extract_dir = PathBuf :: from ( "target/lintcheck/crates" ) ;
80+ let krate_download_dir = PathBuf :: from ( "target/lintcheck/downloads" ) ;
81+
82+ // url to download the crate from crates.io
83+ let url = format ! ( "https://crates.io/api/v1/crates/{}/{}/download" , name, version) ;
84+ println ! ( "Downloading and extracting {} {} from {}" , name, version, url) ;
85+ let _ = std:: fs:: create_dir ( "target/lintcheck/" ) ;
86+ let _ = std:: fs:: create_dir ( & krate_download_dir) ;
87+ let _ = std:: fs:: create_dir ( & extract_dir) ;
88+
89+ let krate_file_path = krate_download_dir. join ( format ! ( "{}-{}.crate.tar.gz" , name, version) ) ;
90+ // don't download/extract if we already have done so
91+ if !krate_file_path. is_file ( ) {
92+ // create a file path to download and write the crate data into
93+ let mut krate_dest = std:: fs:: File :: create ( & krate_file_path) . unwrap ( ) ;
94+ let mut krate_req = ureq:: get ( & url) . call ( ) . unwrap ( ) . into_reader ( ) ;
95+ // copy the crate into the file
96+ std:: io:: copy ( & mut krate_req, & mut krate_dest) . unwrap ( ) ;
97+
98+ // unzip the tarball
99+ let ungz_tar = flate2:: read:: GzDecoder :: new ( std:: fs:: File :: open ( & krate_file_path) . unwrap ( ) ) ;
100+ // extract the tar archive
101+ let mut archive = tar:: Archive :: new ( ungz_tar) ;
102+ archive. unpack ( & extract_dir) . expect ( "Failed to extract!" ) ;
103+ }
104+ // crate is extracted, return a new Krate object which contains the path to the extracted
105+ // sources that clippy can check
106+ Crate {
107+ version : version. clone ( ) ,
108+ name : name. clone ( ) ,
109+ path : extract_dir. join ( format ! ( "{}-{}/" , name, version) ) ,
110+ }
111+ } ,
112+ CrateSource :: Git { name, url, commit } => {
113+ let repo_path = {
114+ let mut repo_path = PathBuf :: from ( "target/lintcheck/downloads" ) ;
115+ // add a -git suffix in case we have the same crate from crates.io and a git repo
116+ repo_path. push ( format ! ( "{}-git" , name) ) ;
117+ repo_path
118+ } ;
119+ // clone the repo if we have not done so
120+ if !repo_path. is_dir ( ) {
121+ Command :: new ( "git" )
122+ . arg ( "clone" )
123+ . arg ( url)
124+ . arg ( & repo_path)
125+ . output ( )
126+ . expect ( "Failed to clone git repo!" ) ;
127+ }
128+ // check out the commit/branch/whatever
129+ Command :: new ( "git" )
130+ . arg ( "checkout" )
131+ . arg ( commit)
132+ . output ( )
133+ . expect ( "Failed to check out commit" ) ;
134+
135+ Crate {
136+ version : commit. clone ( ) ,
137+ name : name. clone ( ) ,
138+ path : repo_path,
139+ }
140+ } ,
109141 }
110142 }
111143}
@@ -175,14 +207,30 @@ fn read_crates() -> Vec<CrateSource> {
175207 // multiple Cratesources)
176208 let mut crate_sources = Vec :: new ( ) ;
177209 tomlcrates. into_iter ( ) . for_each ( |tk| {
210+ // if we have multiple versions, save each one
178211 if let Some ( ref versions) = tk. versions {
179212 versions. iter ( ) . for_each ( |ver| {
180- crate_sources. push ( CrateSource {
213+ crate_sources. push ( CrateSource :: CratesIo {
181214 name : tk. name . clone ( ) ,
182215 version : ver. to_string ( ) ,
183216 } ) ;
184217 } )
185218 }
219+ // otherwise, we should have a git source
220+ if tk. git_url . is_some ( ) && tk. git_hash . is_some ( ) {
221+ crate_sources. push ( CrateSource :: Git {
222+ name : tk. name . clone ( ) ,
223+ url : tk. git_url . clone ( ) . unwrap ( ) ,
224+ commit : tk. git_hash . clone ( ) . unwrap ( ) ,
225+ } ) ;
226+ }
227+ // if we have a version as well as a git data OR only one git data, something is funky
228+ if tk. versions . is_some ( ) && ( tk. git_url . is_some ( ) || tk. git_hash . is_some ( ) )
229+ || tk. git_hash . is_some ( ) != tk. git_url . is_some ( )
230+ {
231+ dbg ! ( tk) ;
232+ unreachable ! ( "Failed to translate TomlCrate into CrateSource!" ) ;
233+ }
186234 } ) ;
187235 crate_sources
188236}
@@ -239,13 +287,13 @@ pub fn run(clap_config: &ArgMatches) {
239287
240288 let clippy_warnings: Vec < ClippyWarning > = if let Some ( only_one_crate) = clap_config. value_of ( "only" ) {
241289 // if we don't have the specified crated in the .toml, throw an error
242- if !crates. iter ( ) . any ( |krate| krate. name == only_one_crate) {
290+ /* if !crates.iter().any(|krate| krate.name == only_one_crate) {
243291 eprintln!(
244292 "ERROR: could not find crate '{}' in clippy_dev/lintcheck_crates.toml",
245293 only_one_crate
246294 );
247295 std::process::exit(1);
248- }
296+ } */ //@FIXME
249297
250298 // only check a single crate that was passed via cmdline
251299 crates
0 commit comments