1
1
use std:: collections:: HashMap ;
2
- use std:: fs:: { self , OpenOptions } ;
3
- use std:: io:: prelude:: * ;
4
2
use std:: path:: { Path , PathBuf } ;
5
3
6
- use chrono:: Utc ;
7
4
use swirl:: PerformError ;
8
5
use tempfile:: TempDir ;
9
6
use url:: Url ;
10
7
11
- use crate :: background_jobs:: Environment ;
12
- use crate :: models:: { DependencyKind , Version } ;
13
- use crate :: schema:: versions;
8
+ use crate :: models:: DependencyKind ;
14
9
15
10
static DEFAULT_GIT_SSH_USERNAME : & str = "git" ;
16
11
@@ -142,9 +137,9 @@ impl RepositoryConfig {
142
137
}
143
138
144
139
pub struct Repository {
145
- checkout_path : TempDir ,
140
+ pub checkout_path : TempDir ,
146
141
repository : git2:: Repository ,
147
- credentials : Credentials ,
142
+ pub credentials : Credentials ,
148
143
}
149
144
150
145
impl Repository {
@@ -179,13 +174,13 @@ impl Repository {
179
174
} )
180
175
}
181
176
182
- fn index_file ( & self , name : & str ) -> PathBuf {
177
+ pub fn index_file ( & self , name : & str ) -> PathBuf {
183
178
self . checkout_path
184
179
. path ( )
185
180
. join ( self . relative_index_file ( name) )
186
181
}
187
182
188
- fn relative_index_file ( & self , name : & str ) -> PathBuf {
183
+ pub fn relative_index_file ( & self , name : & str ) -> PathBuf {
189
184
let name = name. to_lowercase ( ) ;
190
185
match name. len ( ) {
191
186
1 => Path :: new ( "1" ) . join ( & name) ,
@@ -195,7 +190,7 @@ impl Repository {
195
190
}
196
191
}
197
192
198
- fn head_oid ( & self ) -> Result < git2:: Oid , PerformError > {
193
+ pub fn head_oid ( & self ) -> Result < git2:: Oid , PerformError > {
199
194
Ok ( self . repository . head ( ) ?. target ( ) . unwrap ( ) )
200
195
}
201
196
@@ -246,7 +241,7 @@ impl Repository {
246
241
ref_status
247
242
}
248
243
249
- fn commit_and_push ( & self , message : & str , modified_file : & Path ) -> Result < ( ) , PerformError > {
244
+ pub fn commit_and_push ( & self , message : & str , modified_file : & Path ) -> Result < ( ) , PerformError > {
250
245
println ! ( "Committing and pushing \" {}\" " , message) ;
251
246
252
247
self . perform_commit_and_push ( message, modified_file)
@@ -291,7 +286,7 @@ impl Repository {
291
286
}
292
287
293
288
/// Reset `HEAD` to a single commit with all the index contents, but no parent
294
- fn squash_to_single_commit ( & self , msg : & str ) -> Result < ( ) , PerformError > {
289
+ pub fn squash_to_single_commit ( & self , msg : & str ) -> Result < ( ) , PerformError > {
295
290
let tree = self . repository . find_commit ( self . head_oid ( ) ?) ?. tree ( ) ?;
296
291
let sig = self . repository . signature ( ) ?;
297
292
@@ -308,154 +303,3 @@ impl Repository {
308
303
Ok ( ( ) )
309
304
}
310
305
}
311
-
312
- #[ swirl:: background_job]
313
- pub fn add_crate ( env : & Environment , krate : Crate ) -> Result < ( ) , PerformError > {
314
- use std:: io:: prelude:: * ;
315
-
316
- let repo = env. lock_index ( ) ?;
317
- let dst = repo. index_file ( & krate. name ) ;
318
-
319
- // Add the crate to its relevant file
320
- fs:: create_dir_all ( dst. parent ( ) . unwrap ( ) ) ?;
321
- let mut file = OpenOptions :: new ( ) . append ( true ) . create ( true ) . open ( & dst) ?;
322
- serde_json:: to_writer ( & mut file, & krate) ?;
323
- file. write_all ( b"\n " ) ?;
324
-
325
- let message: String = format ! ( "Updating crate `{}#{}`" , krate. name, krate. vers) ;
326
-
327
- repo. commit_and_push ( & message, & repo. relative_index_file ( & krate. name ) )
328
- }
329
-
330
- /// Yanks or unyanks a crate version. This requires finding the index
331
- /// file, deserlialise the crate from JSON, change the yank boolean to
332
- /// `true` or `false`, write all the lines back out, and commit and
333
- /// push the changes.
334
- #[ swirl:: background_job]
335
- pub fn yank (
336
- conn : & PgConnection ,
337
- env : & Environment ,
338
- krate : String ,
339
- version : Version ,
340
- yanked : bool ,
341
- ) -> Result < ( ) , PerformError > {
342
- use diesel:: prelude:: * ;
343
-
344
- let repo = env. lock_index ( ) ?;
345
- let dst = repo. index_file ( & krate) ;
346
-
347
- conn. transaction ( || {
348
- let yanked_in_db: bool = versions:: table
349
- . find ( version. id )
350
- . select ( versions:: yanked)
351
- . for_update ( )
352
- . first ( & * conn) ?;
353
-
354
- if yanked_in_db == yanked {
355
- // The crate is alread in the state requested, nothing to do
356
- return Ok ( ( ) ) ;
357
- }
358
-
359
- let prev = fs:: read_to_string ( & dst) ?;
360
- let new = prev
361
- . lines ( )
362
- . map ( |line| {
363
- let mut git_crate = serde_json:: from_str :: < Crate > ( line)
364
- . map_err ( |_| format ! ( "couldn't decode: `{}`" , line) ) ?;
365
- if git_crate. name != krate || git_crate. vers != version. num {
366
- return Ok ( line. to_string ( ) ) ;
367
- }
368
- git_crate. yanked = Some ( yanked) ;
369
- Ok ( serde_json:: to_string ( & git_crate) ?)
370
- } )
371
- . collect :: < Result < Vec < _ > , PerformError > > ( ) ;
372
- let new = new?. join ( "\n " ) + "\n " ;
373
- fs:: write ( & dst, new. as_bytes ( ) ) ?;
374
-
375
- let message: String = format ! (
376
- "{} crate `{}#{}`" ,
377
- if yanked { "Yanking" } else { "Unyanking" } ,
378
- krate,
379
- version. num
380
- ) ;
381
-
382
- repo. commit_and_push ( & message, & repo. relative_index_file ( & krate) ) ?;
383
-
384
- diesel:: update ( & version)
385
- . set ( versions:: yanked. eq ( yanked) )
386
- . execute ( & * conn) ?;
387
-
388
- Ok ( ( ) )
389
- } )
390
- }
391
-
392
- /// Collapse the index into a single commit, archiving the current history in a snapshot branch.
393
- #[ swirl:: background_job]
394
- pub fn squash_index ( env : & Environment ) -> Result < ( ) , PerformError > {
395
- let repo = env. lock_index ( ) ?;
396
- println ! ( "Squashing the index into a single commit." ) ;
397
-
398
- let now = Utc :: now ( ) . format ( "%Y-%m-%d" ) ;
399
- let original_head = repo. head_oid ( ) ?. to_string ( ) ;
400
- let msg = format ! ( "Collapse index into one commit\n \n \
401
- Previous HEAD was {}, now on the `snapshot-{}` branch\n \n \
402
- More information about this change can be found [online] and on [this issue].\n \n \
403
- [online]: https://internals.rust-lang.org/t/cargos-crate-index-upcoming-squash-into-one-commit/8440\n \
404
- [this issue]: https://github.com/rust-lang/crates-io-cargo-teams/issues/47", original_head, now) ;
405
-
406
- repo. squash_to_single_commit ( & msg) ?;
407
-
408
- // Shell out to git because libgit2 does not currently support push leases
409
-
410
- let key = match & repo. credentials {
411
- Credentials :: Ssh { key } => key,
412
- Credentials :: Http { .. } => {
413
- return Err ( String :: from ( "squash_index: Password auth not supported" ) . into ( ) )
414
- }
415
- _ => return Err ( String :: from ( "squash_index: Could not determine credentials" ) . into ( ) ) ,
416
- } ;
417
-
418
- // When running on production, ensure the file is created in tmpfs and not persisted to disk
419
- #[ cfg( target_os = "linux" ) ]
420
- let mut temp_key_file = tempfile:: Builder :: new ( ) . tempfile_in ( "/dev/shm" ) ?;
421
-
422
- // For other platforms, default to std::env::tempdir()
423
- #[ cfg( not( target_os = "linux" ) ) ]
424
- let mut temp_key_file = tempfile:: Builder :: new ( ) . tempfile ( ) ?;
425
-
426
- temp_key_file. write_all ( key. as_bytes ( ) ) ?;
427
-
428
- let checkout_path = repo. checkout_path . path ( ) ;
429
- let output = std:: process:: Command :: new ( "git" )
430
- . current_dir ( checkout_path)
431
- . env (
432
- "GIT_SSH_COMMAND" ,
433
- format ! (
434
- "ssh -o StrictHostKeyChecking=accept-new -i {}" ,
435
- temp_key_file. path( ) . display( )
436
- ) ,
437
- )
438
- . args ( & [
439
- "push" ,
440
- // Both updates should succeed or fail together
441
- "--atomic" ,
442
- "origin" ,
443
- // Overwrite master, but only if it server matches the expected value
444
- & format ! ( "--force-with-lease=refs/heads/master:{}" , original_head) ,
445
- // The new squashed commit is pushed to master
446
- "HEAD:refs/heads/master" ,
447
- // The previous value of HEAD is pushed to a snapshot branch
448
- & format ! ( "{}:refs/heads/snapshot-{}" , original_head, now) ,
449
- ] )
450
- . output ( ) ?;
451
-
452
- if !output. status . success ( ) {
453
- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
454
- let message = format ! ( "Running git command failed with: {}" , stderr) ;
455
- return Err ( message. into ( ) ) ;
456
- }
457
-
458
- println ! ( "The index has been successfully squashed." ) ;
459
-
460
- Ok ( ( ) )
461
- }
0 commit comments