Skip to content

Commit 4320916

Browse files
committed
Add command for downloading a new benchmark
1 parent 5dd19f3 commit 4320916

File tree

4 files changed

+159
-2
lines changed

4 files changed

+159
-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: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,31 @@ 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+
/// Overwrite the benchmark directory if it already exists.
863+
#[clap(long, global = true)]
864+
overwrite: bool,
865+
866+
#[clap(subcommand)]
867+
command: DownloadSubcommand,
868+
}
869+
870+
#[derive(Debug, clap::Parser)]
871+
enum DownloadSubcommand {
872+
/// Download a crate from a git repository.
873+
Git { url: String },
874+
/// Download a crate from crates.io.
875+
Crate { krate: String, version: String },
851876
}
852877

853878
fn main_result() -> anyhow::Result<i32> {
@@ -1141,9 +1166,102 @@ fn main_result() -> anyhow::Result<i32> {
11411166

11421167
Ok(0)
11431168
}
1169+
Commands::Download(cmd) => {
1170+
let target_dir = get_downloaded_crate_target(&benchmark_dir, &cmd);
1171+
check_target_dir(&target_dir, cmd.overwrite)?;
1172+
1173+
match cmd.command {
1174+
DownloadSubcommand::Git { url } => download_from_git(&target_dir, &url)?,
1175+
DownloadSubcommand::Crate { krate, version } => {
1176+
download_from_crates_io(&target_dir, &krate, &version)?
1177+
}
1178+
};
1179+
println!("Benchmark stored at {}", target_dir.display());
1180+
Ok(0)
1181+
}
11441182
}
11451183
}
11461184

1185+
fn check_target_dir(target_dir: &Path, overwrite: bool) -> anyhow::Result<()> {
1186+
if target_dir.exists() {
1187+
if overwrite {
1188+
std::fs::remove_dir_all(&target_dir).expect(&format!(
1189+
"Cannot remove previous directory at {}",
1190+
target_dir.display()
1191+
));
1192+
} else {
1193+
return Err(anyhow::anyhow!(
1194+
"Directory {} already exists",
1195+
target_dir.display()
1196+
));
1197+
}
1198+
}
1199+
Ok(())
1200+
}
1201+
1202+
fn get_downloaded_crate_target(benchmark_dir: &Path, cmd: &DownloadCommand) -> PathBuf {
1203+
let name = cmd.name.clone().unwrap_or_else(|| match &cmd.command {
1204+
DownloadSubcommand::Git { url } => url
1205+
.trim_end_matches("/")
1206+
.trim_end_matches(".git")
1207+
.split("/")
1208+
.last()
1209+
.expect("Crate name could not be determined from git URL")
1210+
.to_string(),
1211+
DownloadSubcommand::Crate { krate, version } => format!("{krate}-{version}"),
1212+
});
1213+
PathBuf::from(benchmark_dir).join(name)
1214+
}
1215+
1216+
fn download_from_git(target: &Path, url: &str) -> anyhow::Result<()> {
1217+
let tmpdir = tempfile::TempDir::new().unwrap();
1218+
Command::new("git")
1219+
.arg("clone")
1220+
.arg(url)
1221+
.arg(tmpdir.path())
1222+
.status()
1223+
.expect("Git clone failed");
1224+
generate_lockfile(tmpdir.path());
1225+
execute::rename(&tmpdir, &target)?;
1226+
Ok(())
1227+
}
1228+
1229+
fn download_from_crates_io(target_dir: &Path, krate: &str, version: &str) -> anyhow::Result<()> {
1230+
let url = format!("https://crates.io/api/v1/crates/{krate}/{version}/download");
1231+
let response = reqwest::blocking::get(url)
1232+
.expect("Cannot download crate")
1233+
.error_for_status()?;
1234+
1235+
let data = flate2::read::GzDecoder::new(response);
1236+
let mut archive = tar::Archive::new(data);
1237+
1238+
let tmpdir = tempfile::TempDir::new().unwrap();
1239+
archive.unpack(&tmpdir)?;
1240+
1241+
// The content of the crate is not at the package root, it should be nested
1242+
// under <crate-name>-<version> directory.
1243+
let unpacked_dir = tmpdir.path().join(format!("{krate}-{version}"));
1244+
generate_lockfile(&unpacked_dir);
1245+
execute::rename(&unpacked_dir, &target_dir)?;
1246+
1247+
Ok(())
1248+
}
1249+
1250+
fn generate_lockfile(directory: &Path) {
1251+
let manifest_path = directory.join("Cargo.toml");
1252+
1253+
// Cargo metadata should do nothing if there is already a lockfile present.
1254+
// Otherwise it will generate a lockfile.
1255+
Command::new("cargo")
1256+
.arg("metadata")
1257+
.arg("--format-version")
1258+
.arg("1")
1259+
.current_dir(manifest_path.parent().unwrap())
1260+
.stdout(std::process::Stdio::null())
1261+
.status()
1262+
.expect("Cannot generate lock file");
1263+
}
1264+
11471265
pub fn get_commit_or_fake_it(sha: &str) -> anyhow::Result<Commit> {
11481266
let rt = tokio::runtime::Runtime::new().unwrap();
11491267
Ok(rt

0 commit comments

Comments
 (0)