@@ -42,21 +42,18 @@ struct SourceIdInner {
4242
4343/// The possible kinds of code source. Along with `SourceIdInner`, this fully defines the
4444/// source.
45- #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
45+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
4646enum 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.
5150 Path ,
5251 /// A remote registry.
5352 Registry ,
5453 /// A local filesystem-based registry.
5554 LocalRegistry ,
5655 /// A directory-based registry.
5756 Directory ,
58- /// A git repository.
59- Git ( GitReference ) ,
6057}
6158
6259/// Information to find a specific commit in a Git repository.
@@ -486,6 +483,110 @@ impl Hash for SourceId {
486483 }
487484}
488485
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+
489590/// A `Display`able view into a `SourceId` that will write it as a url
490591pub struct SourceIdAsUrl < ' a > {
491592 inner : & ' a SourceIdInner ,
0 commit comments