@@ -42,21 +42,18 @@ struct SourceIdInner {
42
42
43
43
/// The possible kinds of code source. Along with `SourceIdInner`, this fully defines the
44
44
/// source.
45
- #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
45
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
46
46
enum SourceKind {
47
- // Note that the ordering here is important for how it affects the `Ord`
48
- // implementation, notably how this affects the ordering of serialized
49
- // packages into lock files.
50
- /// A local path..
47
+ /// A git repository.
48
+ Git ( GitReference ) ,
49
+ /// A local path.
51
50
Path ,
52
51
/// A remote registry.
53
52
Registry ,
54
53
/// A local filesystem-based registry.
55
54
LocalRegistry ,
56
55
/// A directory-based registry.
57
56
Directory ,
58
- /// A git repository.
59
- Git ( GitReference ) ,
60
57
}
61
58
62
59
/// Information to find a specific commit in a Git repository.
@@ -486,6 +483,110 @@ impl Hash for SourceId {
486
483
}
487
484
}
488
485
486
+ // forward to `Ord`
487
+ impl PartialOrd for SourceKind {
488
+ fn partial_cmp ( & self , other : & SourceKind ) -> Option < Ordering > {
489
+ Some ( self . cmp ( other) )
490
+ }
491
+ }
492
+
493
+ // Note that this is specifically not derived on `SourceKind` although the
494
+ // implementation here is very similar to what it might look like if it were
495
+ // otherwise derived.
496
+ //
497
+ // The reason for this is somewhat obtuse. First of all the hash value of
498
+ // `SourceKind` makes its way into `~/.cargo/registry/index/github.com-XXXX`
499
+ // which means that changes to the hash means that all Rust users need to
500
+ // redownload the crates.io index and all their crates. If possible we strive to
501
+ // not change this to make this redownloading behavior happen as little as
502
+ // possible. How is this connected to `Ord` you might ask? That's a good
503
+ // question!
504
+ //
505
+ // Since the beginning of time `SourceKind` has had `#[derive(Hash)]`. It for
506
+ // the longest time *also* derived the `Ord` and `PartialOrd` traits. In #8522,
507
+ // however, the implementation of `Ord` changed. This handwritten implementation
508
+ // forgot to sync itself with the originally derived implementation, namely
509
+ // placing git dependencies as sorted after all other dependencies instead of
510
+ // first as before.
511
+ //
512
+ // This regression in #8522 (Rust 1.47) went unnoticed. When we switched back
513
+ // to a derived implementation in #9133 (Rust 1.52 beta) we only then ironically
514
+ // saw an issue (#9334). In #9334 it was observed that stable Rust at the time
515
+ // (1.51) was sorting git dependencies last, whereas Rust 1.52 beta would sort
516
+ // git dependencies first. This is because the `PartialOrd` implementation in
517
+ // 1.51 used #8522, the buggy implementation, which put git deps last. In 1.52
518
+ // it was (unknowingly) restored to the pre-1.47 behavior with git dependencies
519
+ // first.
520
+ //
521
+ // Because the breakage was only witnessed after the original breakage, this
522
+ // trait implementation is preserving the "broken" behavior. Put a different way:
523
+ //
524
+ // * Rust pre-1.47 sorted git deps first.
525
+ // * Rust 1.47 to Rust 1.51 sorted git deps last, a breaking change (#8522) that
526
+ // was never noticed.
527
+ // * Rust 1.52 restored the pre-1.47 behavior (#9133, without knowing it did
528
+ // so), and breakage was witnessed by actual users due to difference with
529
+ // 1.51.
530
+ // * Rust 1.52 (the source as it lives now) was fixed to match the 1.47-1.51
531
+ // behavior (#9383), which is now considered intentionally breaking from the
532
+ // pre-1.47 behavior.
533
+ //
534
+ // Note that this was all discovered when Rust 1.53 was in nightly and 1.52 was
535
+ // in beta. #9133 was in both beta and nightly at the time of discovery. For
536
+ // 1.52 #9383 reverted #9133, meaning 1.52 is the same as 1.51. On nightly
537
+ // (1.53) #9397 was created to fix the regression introduced by #9133 relative
538
+ // to the current stable (1.51).
539
+ //
540
+ // That's all a long winded way of saying "it's wierd that git deps hash first
541
+ // and are sorted last, but it's the way it is right now". The author of this
542
+ // comment chose to handwrite the `Ord` implementation instead of the `Hash`
543
+ // implementation, but it's only required that at most one of them is
544
+ // hand-written because the other can be derived. Perhaps one day in
545
+ // the future someone can figure out how to remove this behavior.
546
+ impl Ord for SourceKind {
547
+ fn cmp ( & self , other : & SourceKind ) -> Ordering {
548
+ match ( self , other) {
549
+ ( SourceKind :: Path , SourceKind :: Path ) => Ordering :: Equal ,
550
+ ( SourceKind :: Path , _) => Ordering :: Less ,
551
+ ( _, SourceKind :: Path ) => Ordering :: Greater ,
552
+
553
+ ( SourceKind :: Registry , SourceKind :: Registry ) => Ordering :: Equal ,
554
+ ( SourceKind :: Registry , _) => Ordering :: Less ,
555
+ ( _, SourceKind :: Registry ) => Ordering :: Greater ,
556
+
557
+ ( SourceKind :: LocalRegistry , SourceKind :: LocalRegistry ) => Ordering :: Equal ,
558
+ ( SourceKind :: LocalRegistry , _) => Ordering :: Less ,
559
+ ( _, SourceKind :: LocalRegistry ) => Ordering :: Greater ,
560
+
561
+ ( SourceKind :: Directory , SourceKind :: Directory ) => Ordering :: Equal ,
562
+ ( SourceKind :: Directory , _) => Ordering :: Less ,
563
+ ( _, SourceKind :: Directory ) => Ordering :: Greater ,
564
+
565
+ ( SourceKind :: Git ( a) , SourceKind :: Git ( b) ) => a. cmp ( b) ,
566
+ }
567
+ }
568
+ }
569
+
570
+ // This is a test that the hash of the `SourceId` for crates.io is a well-known
571
+ // value.
572
+ //
573
+ // Note that the hash value matches what the crates.io source id has hashed
574
+ // since long before Rust 1.30. We strive to keep this value the same across
575
+ // versions of Cargo because changing it means that users will need to
576
+ // redownload the index and all crates they use when using a new Cargo version.
577
+ //
578
+ // This isn't to say that this hash can *never* change, only that when changing
579
+ // this it should be explicitly done. If this hash changes accidentally and
580
+ // you're able to restore the hash to its original value, please do so!
581
+ // Otherwise please just leave a comment in your PR as to why the hash value is
582
+ // changing and why the old value can't be easily preserved.
583
+ #[ test]
584
+ fn test_cratesio_hash ( ) {
585
+ let config = Config :: default ( ) . unwrap ( ) ;
586
+ let crates_io = SourceId :: crates_io ( & config) . unwrap ( ) ;
587
+ assert_eq ! ( crate :: util:: hex:: short_hash( & crates_io) , "1ecc6299db9ec823" ) ;
588
+ }
589
+
489
590
/// A `Display`able view into a `SourceId` that will write it as a url
490
591
pub struct SourceIdAsUrl < ' a > {
491
592
inner : & ' a SourceIdInner ,
0 commit comments