@@ -23,55 +23,99 @@ import (
23
23
type codeRepo struct {
24
24
modPath string
25
25
26
- code codehost.Repo
26
+ // code is the repository containing this module.
27
+ code codehost.Repo
28
+ // codeRoot is the import path at the root of code.
27
29
codeRoot string
28
- codeDir string
30
+ // codeDir is the directory (relative to root) at which we expect to find the module.
31
+ // If pathMajor is non-empty and codeRoot is not the full modPath,
32
+ // then we look in both codeDir and codeDir+modPath
33
+ codeDir string
29
34
30
- path string
31
- pathPrefix string
32
- pathMajor string
35
+ // pathMajor is the suffix of modPath that indicates its major version,
36
+ // or the empty string if modPath is at major version 0 or 1.
37
+ //
38
+ // pathMajor is typically of the form "/vN", but possibly ".vN", or
39
+ // ".vN-unstable" for modules resolved using gopkg.in.
40
+ pathMajor string
41
+ // pathPrefix is the prefix of modPath that excludes pathMajor.
42
+ // It is used only for logging.
43
+ pathPrefix string
44
+
45
+ // pseudoMajor is the major version prefix to use when generating
46
+ // pseudo-versions for this module, derived from the module path.
47
+ //
48
+ // TODO(golang.org/issue/29262): We can't distinguish v0 from v1 using the
49
+ // path alone: we have to compute it by examining the tags at a particular
50
+ // revision.
33
51
pseudoMajor string
34
52
}
35
53
36
- func newCodeRepo (code codehost.Repo , root , path string ) (Repo , error ) {
37
- if ! hasPathPrefix (path , root ) {
38
- return nil , fmt .Errorf ("mismatched repo: found %s for %s" , root , path )
54
+ // newCodeRepo returns a Repo that reads the source code for the module with the
55
+ // given path, from the repo stored in code, with the root of the repo
56
+ // containing the path given by codeRoot.
57
+ func newCodeRepo (code codehost.Repo , codeRoot , path string ) (Repo , error ) {
58
+ if ! hasPathPrefix (path , codeRoot ) {
59
+ return nil , fmt .Errorf ("mismatched repo: found %s for %s" , codeRoot , path )
39
60
}
40
61
pathPrefix , pathMajor , ok := module .SplitPathVersion (path )
41
62
if ! ok {
42
63
return nil , fmt .Errorf ("invalid module path %q" , path )
43
64
}
65
+ if codeRoot == path {
66
+ pathPrefix = path
67
+ }
44
68
pseudoMajor := "v0"
45
69
if pathMajor != "" {
46
70
pseudoMajor = pathMajor [1 :]
47
71
}
48
72
73
+ // Compute codeDir = bar, the subdirectory within the repo
74
+ // corresponding to the module root.
75
+ //
49
76
// At this point we might have:
50
- // codeRoot = github.com/rsc/foo
51
77
// path = github.com/rsc/foo/bar/v2
78
+ // codeRoot = github.com/rsc/foo
52
79
// pathPrefix = github.com/rsc/foo/bar
53
80
// pathMajor = /v2
54
81
// pseudoMajor = v2
55
82
//
56
- // Compute codeDir = bar, the subdirectory within the repo
57
- // corresponding to the module root.
58
- codeDir := strings .Trim (strings .TrimPrefix (pathPrefix , root ), "/" )
59
- if strings .HasPrefix (path , "gopkg.in/" ) {
60
- // But gopkg.in is a special legacy case, in which pathPrefix does not start with codeRoot.
61
- // For example we might have:
62
- // codeRoot = gopkg.in/yaml.v2
63
- // pathPrefix = gopkg.in/yaml
64
- // pathMajor = .v2
65
- // pseudoMajor = v2
66
- // codeDir = pathPrefix (because codeRoot is not a prefix of pathPrefix)
67
- // Clear codeDir - the module root is the repo root for gopkg.in repos.
68
- codeDir = ""
83
+ // which gives
84
+ // codeDir = bar
85
+ //
86
+ // We know that pathPrefix is a prefix of path, and codeRoot is a prefix of
87
+ // path, but codeRoot may or may not be a prefix of pathPrefix, because
88
+ // codeRoot may be the entire path (in which case codeDir should be empty).
89
+ // That occurs in two situations.
90
+ //
91
+ // One is when a go-import meta tag resolves the complete module path,
92
+ // including the pathMajor suffix:
93
+ // path = nanomsg.org/go/mangos/v2
94
+ // codeRoot = nanomsg.org/go/mangos/v2
95
+ // pathPrefix = nanomsg.org/go/mangos
96
+ // pathMajor = /v2
97
+ // pseudoMajor = v2
98
+ //
99
+ // The other is similar: for gopkg.in only, the major version is encoded
100
+ // with a dot rather than a slash, and thus can't be in a subdirectory.
101
+ // path = gopkg.in/yaml.v2
102
+ // codeRoot = gopkg.in/yaml.v2
103
+ // pathPrefix = gopkg.in/yaml
104
+ // pathMajor = .v2
105
+ // pseudoMajor = v2
106
+ //
107
+ codeDir := ""
108
+ if codeRoot != path {
109
+ if ! hasPathPrefix (pathPrefix , codeRoot ) {
110
+ return nil , fmt .Errorf ("repository rooted at %s cannot contain module %s" , codeRoot , path )
111
+ }
112
+ codeDir = strings .Trim (pathPrefix [len (codeRoot ):], "/" )
69
113
}
70
114
71
115
r := & codeRepo {
72
116
modPath : path ,
73
117
code : code ,
74
- codeRoot : root ,
118
+ codeRoot : codeRoot ,
75
119
codeDir : codeDir ,
76
120
pathPrefix : pathPrefix ,
77
121
pathMajor : pathMajor ,
@@ -149,9 +193,6 @@ func (r *codeRepo) Stat(rev string) (*RevInfo, error) {
149
193
return r .Latest ()
150
194
}
151
195
codeRev := r .revToRev (rev )
152
- if semver .IsValid (codeRev ) && r .codeDir != "" {
153
- codeRev = r .codeDir + "/" + codeRev
154
- }
155
196
info , err := r .code .Stat (codeRev )
156
197
if err != nil {
157
198
return nil , err
@@ -290,14 +331,17 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
290
331
found1 := err1 == nil && isMajor (mpath1 , r .pathMajor )
291
332
292
333
var file2 string
293
- if r .pathMajor != "" && ! strings .HasPrefix (r .pathMajor , "." ) {
334
+ if r .pathMajor != "" && r . codeRoot != r . modPath && ! strings .HasPrefix (r .pathMajor , "." ) {
294
335
// Suppose pathMajor is "/v2".
295
336
// Either go.mod should claim v2 and v2/go.mod should not exist,
296
337
// or v2/go.mod should exist and claim v2. Not both.
297
338
// Note that we don't check the full path, just the major suffix,
298
339
// because of replacement modules. This might be a fork of
299
340
// the real module, found at a different path, usable only in
300
341
// a replace directive.
342
+ //
343
+ // TODO(bcmills): This doesn't seem right. Investigate futher.
344
+ // (Notably: why can't we replace foo/v2 with fork-of-foo/v3?)
301
345
dir2 := path .Join (r .codeDir , r .pathMajor [1 :])
302
346
file2 = path .Join (dir2 , "go.mod" )
303
347
gomod2 , err2 := r .code .ReadFile (rev , file2 , codehost .MaxGoMod )
@@ -418,7 +462,7 @@ func (r *codeRepo) Zip(dst io.Writer, version string) error {
418
462
}
419
463
defer dl .Close ()
420
464
if actualDir != "" && ! hasPathPrefix (dir , actualDir ) {
421
- return fmt .Errorf ("internal error: downloading %v %v: dir=%q but actualDir=%q" , r .path , rev , dir , actualDir )
465
+ return fmt .Errorf ("internal error: downloading %v %v: dir=%q but actualDir=%q" , r .modPath , rev , dir , actualDir )
422
466
}
423
467
subdir := strings .Trim (strings .TrimPrefix (dir , actualDir ), "/" )
424
468
0 commit comments