@@ -719,9 +719,6 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
719
719
// because of replacement modules. This might be a fork of
720
720
// the real module, found at a different path, usable only in
721
721
// a replace directive.
722
- //
723
- // TODO(bcmills): This doesn't seem right. Investigate further.
724
- // (Notably: why can't we replace foo/v2 with fork-of-foo/v3?)
725
722
dir2 := path .Join (r .codeDir , r .pathMajor [1 :])
726
723
file2 = path .Join (dir2 , "go.mod" )
727
724
gomod2 , err2 := r .code .ReadFile (rev , file2 , codehost .MaxGoMod )
@@ -747,11 +744,11 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
747
744
748
745
// Not v2/go.mod, so it's either go.mod or nothing. Which is it?
749
746
if found1 {
750
- // Explicit go.mod with matching module path OK .
747
+ // Explicit go.mod with matching major version ok .
751
748
return rev , r .codeDir , gomod1 , nil
752
749
}
753
750
if err1 == nil {
754
- // Explicit go.mod with non-matching module path disallowed.
751
+ // Explicit go.mod with non-matching major version disallowed.
755
752
suffix := ""
756
753
if file2 != "" {
757
754
suffix = fmt .Sprintf (" (and ...%s/go.mod does not exist)" , r .pathMajor )
@@ -762,6 +759,9 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
762
759
if r .pathMajor != "" { // ".v1", ".v2" for gopkg.in
763
760
return "" , "" , nil , fmt .Errorf ("%s has non-...%s module path %q%s at revision %s" , file1 , r .pathMajor , mpath1 , suffix , rev )
764
761
}
762
+ if _ , _ , ok := module .SplitPathVersion (mpath1 ); ! ok {
763
+ return "" , "" , nil , fmt .Errorf ("%s has malformed module path %q%s at revision %s" , file1 , mpath1 , suffix , rev )
764
+ }
765
765
return "" , "" , nil , fmt .Errorf ("%s has post-%s module path %q%s at revision %s" , file1 , semver .Major (version ), mpath1 , suffix , rev )
766
766
}
767
767
@@ -778,24 +778,43 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
778
778
return "" , "" , nil , fmt .Errorf ("missing %s/go.mod at revision %s" , r .pathPrefix , rev )
779
779
}
780
780
781
+ // isMajor reports whether the versions allowed for mpath are compatible with
782
+ // the major version(s) implied by pathMajor, or false if mpath has an invalid
783
+ // version suffix.
781
784
func isMajor (mpath , pathMajor string ) bool {
782
785
if mpath == "" {
786
+ // If we don't have a path, we don't know what version(s) it is compatible with.
787
+ return false
788
+ }
789
+ _ , mpathMajor , ok := module .SplitPathVersion (mpath )
790
+ if ! ok {
791
+ // An invalid module path is not compatible with any version.
783
792
return false
784
793
}
785
794
if pathMajor == "" {
786
- // mpath must NOT have version suffix.
787
- i := len ( mpath )
788
- for i > 0 && '0' <= mpath [ i - 1 ] && mpath [ i - 1 ] <= '9' {
789
- i --
790
- }
791
- if i < len ( mpath ) && i >= 2 && mpath [ i - 1 ] == 'v' && mpath [ i - 2 ] == '/' {
792
- // Found valid suffix.
795
+ // All of the valid versions for a gopkg.in module that requires major
796
+ // version v0 or v1 are compatible with the "v0 or v1" implied by an empty
797
+ // pathMajor.
798
+ switch module . PathMajorPrefix ( mpathMajor ) {
799
+ case "" , "v0" , "v1" :
800
+ return true
801
+ default :
793
802
return false
794
803
}
795
- return true
796
804
}
797
- // Otherwise pathMajor is ".v1", ".v2" (gopkg.in), or "/v2", "/v3" etc.
798
- return strings .HasSuffix (mpath , pathMajor )
805
+ if mpathMajor == "" {
806
+ // Even if pathMajor is ".v0" or ".v1", we can't be sure that a module
807
+ // without a suffix is tagged appropriately. Besides, we don't expect clones
808
+ // of non-gopkg.in modules to have gopkg.in paths, so a non-empty,
809
+ // non-gopkg.in mpath is probably the wrong module for any such pathMajor
810
+ // anyway.
811
+ return false
812
+ }
813
+ // If both pathMajor and mpathMajor are non-empty, then we only care that they
814
+ // have the same major-version validation rules. A clone fetched via a /v2
815
+ // path might replace a module with path gopkg.in/foo.v2-unstable, and that's
816
+ // ok.
817
+ return pathMajor [1 :] == mpathMajor [1 :]
799
818
}
800
819
801
820
func (r * codeRepo ) GoMod (version string ) (data []byte , err error ) {
0 commit comments