Skip to content

Commit e989dbc

Browse files
committed
Add command for downloading a new benchmark
1 parent 17f20a6 commit e989dbc

File tree

4 files changed

+153
-2
lines changed

4 files changed

+153
-2
lines changed

Cargo.lock

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

collector/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ crossbeam-utils = "0.8"
3131
snap = "1"
3232
filetime = "0.2.14"
3333
walkdir = "2"
34+
flate2 = { version = "1.0.22", features = ["rust_backend"] }
3435

3536
[target.'cfg(windows)'.dependencies]
3637
miow = "0.3"

collector/src/execute.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use tokio::runtime::Runtime;
2525
mod rustc;
2626

2727
#[cfg(windows)]
28-
fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> anyhow::Result<()> {
28+
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> anyhow::Result<()> {
2929
let (from, to) = (from.as_ref(), to.as_ref());
3030

3131
let ctx = format!("renaming file {:?} to {:?}", from, to);
@@ -38,7 +38,7 @@ fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> anyhow::Result<()>
3838
}
3939

4040
#[cfg(unix)]
41-
fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> anyhow::Result<()> {
41+
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> anyhow::Result<()> {
4242
let (from, to) = (from.as_ref(), to.as_ref());
4343
if fs::rename(from, to).is_err() {
4444
// This is necessary if from and to are on different

collector/src/main.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,27 @@ enum Commands {
848848

849849
/// Installs the next commit for perf.rust-lang.org
850850
InstallNext,
851+
852+
/// Download a crate into collector/benchmarks.
853+
Download(DownloadCommand),
854+
}
855+
856+
#[derive(Debug, clap::Parser)]
857+
struct DownloadCommand {
858+
/// Name of the benchmark created directory
859+
#[clap(long, global = true)]
860+
name: Option<String>,
861+
862+
#[clap(subcommand)]
863+
command: DownloadSubcommand,
864+
}
865+
866+
#[derive(Debug, clap::Parser)]
867+
enum DownloadSubcommand {
868+
/// Download a crate from a git repository.
869+
Git { url: String },
870+
/// Download a crate from crates.io.
871+
Crate { krate: String, version: String },
851872
}
852873

853874
fn main_result() -> anyhow::Result<i32> {
@@ -1141,9 +1162,100 @@ fn main_result() -> anyhow::Result<i32> {
11411162

11421163
Ok(0)
11431164
}
1165+
Commands::Download(opts) => {
1166+
let path = match opts.command {
1167+
DownloadSubcommand::Git { url } => {
1168+
download_from_git(&benchmark_dir, opts.name.as_deref(), &url)?
1169+
}
1170+
DownloadSubcommand::Crate { krate, version } => {
1171+
download_from_crates_io(&benchmark_dir, &krate, &version, opts.name.as_deref())?
1172+
}
1173+
};
1174+
println!("Benchmark stored at {}", path.display());
1175+
Ok(0)
1176+
}
11441177
}
11451178
}
11461179

1180+
fn download_from_git(
1181+
benchmark_dir: &Path,
1182+
name: Option<&str>,
1183+
url: &str,
1184+
) -> anyhow::Result<PathBuf> {
1185+
let target = PathBuf::from(benchmark_dir);
1186+
let crate_name = match name {
1187+
Some(name) => name,
1188+
None => url
1189+
.trim_end_matches("/")
1190+
.trim_end_matches(".git")
1191+
.split("/")
1192+
.last()
1193+
.expect("Crate name could not be determined from git URL"),
1194+
};
1195+
let target = target.join(crate_name);
1196+
if target.exists() {
1197+
return Err(anyhow::anyhow!(
1198+
"Directory {} already exists",
1199+
target.display()
1200+
));
1201+
}
1202+
1203+
let tmpdir = tempfile::TempDir::new().unwrap();
1204+
Command::new("git")
1205+
.arg("clone")
1206+
.arg(url)
1207+
.arg(tmpdir.path())
1208+
.output()
1209+
.expect("Git clone failed");
1210+
generate_lockfile(tmpdir.path());
1211+
execute::rename(&tmpdir, &target)?;
1212+
Ok(target)
1213+
}
1214+
1215+
fn download_from_crates_io(
1216+
benchmark_dir: &Path,
1217+
krate: &str,
1218+
version: &str,
1219+
name: Option<&str>,
1220+
) -> anyhow::Result<PathBuf> {
1221+
let full_name = format!("{krate}-{version}");
1222+
let name = name.unwrap_or(&full_name);
1223+
let target = PathBuf::from(benchmark_dir).join(name);
1224+
if target.exists() {
1225+
return Err(anyhow::anyhow!(
1226+
"Directory {} already exists",
1227+
target.display()
1228+
));
1229+
}
1230+
1231+
let url = format!("https://crates.io/api/v1/crates/{krate}/{version}/download");
1232+
let body = reqwest::blocking::get(url).expect("Cannot download crate");
1233+
let data = flate2::read::GzDecoder::new(body);
1234+
let mut archive = tar::Archive::new(data);
1235+
1236+
let tmpdir = tempfile::TempDir::new().unwrap();
1237+
archive.unpack(&tmpdir)?;
1238+
let unpacked_dir = std::fs::read_dir(&tmpdir.path())
1239+
.unwrap()
1240+
.next()
1241+
.unwrap()
1242+
.unwrap()
1243+
.path();
1244+
generate_lockfile(&unpacked_dir);
1245+
execute::rename(&unpacked_dir, &target)?;
1246+
1247+
Ok(target)
1248+
}
1249+
1250+
fn generate_lockfile(directory: &Path) {
1251+
let manifest_path = directory.join("Cargo.toml");
1252+
Command::new("cargo")
1253+
.arg("generate-lockfile")
1254+
.current_dir(manifest_path.parent().unwrap())
1255+
.status()
1256+
.expect("Cannot generate lock file");
1257+
}
1258+
11471259
pub fn get_commit_or_fake_it(sha: &str) -> anyhow::Result<Commit> {
11481260
let rt = tokio::runtime::Runtime::new().unwrap();
11491261
Ok(rt

0 commit comments

Comments
 (0)