Skip to content

Commit 10fbafa

Browse files
committed
implement the download_and_extract() step for git sources
1 parent 64982cc commit 10fbafa

File tree

1 file changed

+88
-40
lines changed

1 file changed

+88
-40
lines changed

clippy_dev/src/lintcheck.rs

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use std::{fmt, fs::write, path::PathBuf};
1616
use clap::ArgMatches;
1717
use serde::{Deserialize, Serialize};
1818
use 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)]
4547
struct Crate {
4648
version: String,
@@ -72,40 +74,70 @@ impl std::fmt::Display for ClippyWarning {
7274

7375
impl 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

Comments
 (0)