@@ -848,6 +848,27 @@ enum Commands {
848
848
849
849
/// Installs the next commit for perf.rust-lang.org
850
850
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 } ,
851
872
}
852
873
853
874
fn main_result ( ) -> anyhow:: Result < i32 > {
@@ -1141,9 +1162,100 @@ fn main_result() -> anyhow::Result<i32> {
1141
1162
1142
1163
Ok ( 0 )
1143
1164
}
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
+ }
1144
1177
}
1145
1178
}
1146
1179
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
+
1147
1259
pub fn get_commit_or_fake_it ( sha : & str ) -> anyhow:: Result < Commit > {
1148
1260
let rt = tokio:: runtime:: Runtime :: new ( ) . unwrap ( ) ;
1149
1261
Ok ( rt
0 commit comments