Skip to content

Commit 44eefc0

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

File tree

4 files changed

+156
-2
lines changed

4 files changed

+156
-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: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use database::{ArtifactId, Commit};
66
use log::debug;
77
use std::collections::HashSet;
88
use std::fs;
9+
use std::fs::File;
910
use std::path::{Path, PathBuf};
1011
use std::process;
1112
use std::process::{Command, Stdio};
@@ -16,6 +17,7 @@ mod execute;
1617
mod sysroot;
1718

1819
use execute::{BenchProcessor, Benchmark, BenchmarkName, ProfileProcessor, Profiler};
20+
use std::io::Write;
1921
use sysroot::Sysroot;
2022

2123
#[derive(Debug, Copy, Clone)]
@@ -848,6 +850,27 @@ enum Commands {
848850

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

853876
fn main_result() -> anyhow::Result<i32> {
@@ -1141,7 +1164,99 @@ fn main_result() -> anyhow::Result<i32> {
11411164

11421165
Ok(0)
11431166
}
1167+
Commands::Download(opts) => {
1168+
let crate_path = match opts.command {
1169+
DownloadSubcommand::Git { url } => {
1170+
download_from_git(&benchmark_dir, opts.name.as_deref(), &url)?
1171+
}
1172+
DownloadSubcommand::Crate { krate, version } => {
1173+
download_from_crates_io(&benchmark_dir, &krate, &version, opts.name.as_deref())?
1174+
}
1175+
};
1176+
prepare_downloaded_benchmark(&crate_path);
1177+
Ok(0)
1178+
}
1179+
}
1180+
}
1181+
1182+
fn download_from_git(
1183+
benchmark_dir: &Path,
1184+
name: Option<&str>,
1185+
url: &str,
1186+
) -> anyhow::Result<PathBuf> {
1187+
let target = PathBuf::from(benchmark_dir);
1188+
let crate_name = match name {
1189+
Some(name) => name,
1190+
None => url
1191+
.trim_end_matches("/")
1192+
.trim_end_matches(".git")
1193+
.split("/")
1194+
.last()
1195+
.expect("Crate name could not be determined from git URL"),
1196+
};
1197+
let target = target.join(crate_name);
1198+
if target.exists() {
1199+
return Err(anyhow::anyhow!(
1200+
"Directory {} already exists",
1201+
target.display()
1202+
));
1203+
}
1204+
1205+
Command::new("git")
1206+
.arg("clone")
1207+
.arg(url)
1208+
.arg(&target)
1209+
.output()
1210+
.expect("Git clone failed");
1211+
Ok(target)
1212+
}
1213+
1214+
fn download_from_crates_io(
1215+
benchmark_dir: &Path,
1216+
krate: &str,
1217+
version: &str,
1218+
name: Option<&str>,
1219+
) -> anyhow::Result<PathBuf> {
1220+
let full_name = format!("{krate}-{version}");
1221+
let name = name.unwrap_or(&full_name);
1222+
let target = PathBuf::from(benchmark_dir).join(name);
1223+
if target.exists() {
1224+
return Err(anyhow::anyhow!(
1225+
"Directory {} already exists",
1226+
target.display()
1227+
));
1228+
}
1229+
1230+
let url = format!("https://crates.io/api/v1/crates/{krate}/{version}/download");
1231+
let body = reqwest::blocking::get(url).expect("Cannot download crate");
1232+
let data = flate2::read::GzDecoder::new(body);
1233+
let mut archive = tar::Archive::new(data);
1234+
1235+
let tmpdir = tempfile::TempDir::new().unwrap();
1236+
archive.unpack(&tmpdir)?;
1237+
let unpacked_dir = std::fs::read_dir(&tmpdir.path())
1238+
.unwrap()
1239+
.next()
1240+
.unwrap()
1241+
.unwrap()
1242+
.path();
1243+
execute::rename(&unpacked_dir, &target)?;
1244+
1245+
Ok(target)
1246+
}
1247+
1248+
fn prepare_downloaded_benchmark(path: &Path) {
1249+
let manifest_path = path.join("Cargo.toml");
1250+
let manifest = std::fs::read_to_string(&manifest_path).expect("Cannot open Cargo.toml");
1251+
if !manifest.contains("[workspace]") {
1252+
let mut file = File::options().append(true).open(&manifest_path).unwrap();
1253+
writeln!(file, "[workspace]").expect("Cannot append workspace to Cargo.toml");
11441254
}
1255+
Command::new("cargo")
1256+
.arg("generate-lockfile")
1257+
.current_dir(manifest_path.parent().unwrap())
1258+
.status()
1259+
.expect("Cannot generate lock file");
11451260
}
11461261

11471262
pub fn get_commit_or_fake_it(sha: &str) -> anyhow::Result<Commit> {

0 commit comments

Comments
 (0)