Skip to content

Commit 2750f95

Browse files
rscgopherbot
authored andcommitted
cmd/go: implement accurate pseudo-versions for Mercurial
This is CL 124515 (which only did Git) but for Mercurial, quite a few years late. I'm not sure why we didn't do it at the time - probably Mercurial blindness. Do it now. Change-Id: I28f448a19143f7ce3de337cd1891bae86023b499 Reviewed-on: https://go-review.googlesource.com/c/go/+/718502 Reviewed-by: Michael Matloob <[email protected]> Reviewed-by: Michael Matloob <[email protected]> Auto-Submit: Russ Cox <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent b709a3e commit 2750f95

File tree

7 files changed

+407
-44
lines changed

7 files changed

+407
-44
lines changed

src/cmd/go/internal/modfetch/codehost/git.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,15 +794,18 @@ func (r *gitRepo) RecentTag(ctx context.Context, rev, prefix string, allowed fun
794794
// There are plausible tags, but we don't know if rev is a descendent of any of them.
795795
// Fetch the history to find out.
796796

797+
// Note: do not use defer unlock, because describe calls allowed,
798+
// which uses retracted, which calls ReadFile, which may end up
799+
// back at a method that acquires r.mu.
797800
unlock, err := r.mu.Lock()
798801
if err != nil {
799802
return "", err
800803
}
801-
defer unlock()
802-
803804
if err := r.fetchRefsLocked(ctx); err != nil {
805+
unlock()
804806
return "", err
805807
}
808+
unlock()
806809

807810
// If we've reached this point, we have all of the commits that are reachable
808811
// from all heads and tags.

src/cmd/go/internal/modfetch/codehost/vcs.go

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"cmd/go/internal/lockedfile"
2626
"cmd/go/internal/str"
2727
"cmd/internal/par"
28+
29+
"golang.org/x/mod/semver"
2830
)
2931

3032
// A VCSError indicates an error using a version control system.
@@ -167,6 +169,8 @@ type vcsCmd struct {
167169
parseStat func(rev, out string) (*RevInfo, error) // func to parse output of statLocal
168170
fetch []string // cmd to fetch everything from remote
169171
latest string // name of latest commit on remote (tip, HEAD, etc)
172+
descendsFrom func(rev, tag string) []string // cmd to check whether rev descends from tag
173+
recentTags func(rev string) []string // cmd to print tag ancestors of rev
170174
readFile func(rev, file, remote string) []string // cmd to read rev's file
171175
readZip func(rev, subdir, remote, target string) []string // cmd to read rev's subdir as zip file
172176

@@ -217,6 +221,12 @@ var vcsCmds = map[string]*vcsCmd{
217221
parseStat: hgParseStat,
218222
fetch: []string{"hg", "pull", "-f"},
219223
latest: "tip",
224+
descendsFrom: func(rev, tag string) []string {
225+
return []string{"hg", "log", "-r", "ancestors(" + rev + ") and " + tag}
226+
},
227+
recentTags: func(rev string) []string {
228+
return []string{"hg", "log", "-r", "ancestors(" + rev + ") and tag()", "--template", "{tags}\n"}
229+
},
220230
readFile: func(rev, file, remote string) []string {
221231
return []string{"hg", "cat", "-r", rev, file}
222232
},
@@ -558,16 +568,37 @@ func (r *vcsRepo) ReadFile(ctx context.Context, rev, file string, maxSize int64)
558568
}
559569

560570
func (r *vcsRepo) RecentTag(ctx context.Context, rev, prefix string, allowed func(string) bool) (tag string, err error) {
561-
// We don't technically need to lock here since we're returning an error
562-
// unconditionally, but doing so anyway will help to avoid baking in
563-
// lock-inversion bugs.
571+
// Only lock for the subprocess execution, not for the tag scan.
572+
// allowed may call other methods that acquire the lock.
564573
unlock, err := r.mu.Lock()
565574
if err != nil {
566575
return "", err
567576
}
568-
defer unlock()
569577

570-
return "", vcsErrorf("vcs %s: RecentTag: %w", r.cmd.vcs, errors.ErrUnsupported)
578+
if r.cmd.recentTags == nil {
579+
unlock()
580+
return "", vcsErrorf("vcs %s: RecentTag: %w", r.cmd.vcs, errors.ErrUnsupported)
581+
}
582+
out, err := Run(ctx, r.dir, r.cmd.recentTags(rev))
583+
unlock()
584+
if err != nil {
585+
return "", err
586+
}
587+
588+
highest := ""
589+
for _, tag := range strings.Fields(string(out)) {
590+
if !strings.HasPrefix(tag, prefix) || !allowed(tag) {
591+
continue
592+
}
593+
semtag := tag[len(prefix):]
594+
if semver.Compare(semtag, highest) > 0 {
595+
highest = semtag
596+
}
597+
}
598+
if highest != "" {
599+
return prefix + highest, nil
600+
}
601+
return "", nil
571602
}
572603

573604
func (r *vcsRepo) DescendsFrom(ctx context.Context, rev, tag string) (bool, error) {
@@ -577,7 +608,15 @@ func (r *vcsRepo) DescendsFrom(ctx context.Context, rev, tag string) (bool, erro
577608
}
578609
defer unlock()
579610

580-
return false, vcsErrorf("vcs %s: DescendsFrom: %w", r.cmd.vcs, errors.ErrUnsupported)
611+
if r.cmd.descendsFrom == nil {
612+
return false, vcsErrorf("vcs %s: DescendsFrom: %w", r.cmd.vcs, errors.ErrUnsupported)
613+
}
614+
615+
out, err := Run(ctx, r.dir, r.cmd.descendsFrom(rev, tag))
616+
if err != nil {
617+
return false, err
618+
}
619+
return strings.TrimSpace(string(out)) != "", nil
581620
}
582621

583622
func (r *vcsRepo) ReadZip(ctx context.Context, rev, subdir string, maxSize int64) (zip io.ReadCloser, err error) {
Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,83 @@
11
env GO111MODULE=on
22

3-
# Testing git->module converter's generation of +incompatible tags; turn off proxy.
4-
[!net:github.com] skip
53
[!git] skip
4+
[short] skip
5+
6+
# Testing git->module converter's generation of +incompatible tags; turn off proxy.
67
env GOPROXY=direct
78
env GOSUMDB=off
89

910
# We can resolve the @master branch without unshallowing the local repository
1011
# (even with older gits), so try that before we do anything else.
1112
# (This replicates https://golang.org/issue/26713 with git 2.7.4.)
12-
go get github.com/rsc/legacytest@master
13+
go get vcs-test.golang.org/git/legacytest.git@master
1314
go list -m all
14-
stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$'
15+
stdout '^vcs-test.golang.org/git/legacytest.git v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$'
1516

1617
# get should include incompatible tags in "latest" calculation.
17-
go mod edit -droprequire github.com/rsc/legacytest
18-
go get github.com/rsc/legacytest@latest
18+
go mod edit -droprequire vcs-test.golang.org/git/legacytest.git
19+
go get vcs-test.golang.org/git/legacytest.git@latest
1920
go list
2021
go list -m all
21-
stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
22+
stdout '^vcs-test.golang.org/git/legacytest.git v2\.0\.0\+incompatible$'
2223

2324
# v2.0.1-0.pseudo+incompatible
24-
go get ...test@7303f77
25+
go get ...test.git@7303f77
2526
go list -m all
26-
stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$'
27+
stdout '^vcs-test.golang.org/git/legacytest.git v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$'
2728

2829
# v2.0.0+incompatible by tag+incompatible
29-
go get [email protected]+incompatible
30+
go get ...test.git@v2.0.0+incompatible
3031
go list -m all
31-
stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
32+
stdout '^vcs-test.golang.org/git/legacytest.git v2\.0\.0\+incompatible$'
3233

3334
# v2.0.0+incompatible by tag
34-
35+
go get ...test.git@v2.0.0
3536
go list -m all
36-
stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
37+
stdout '^vcs-test.golang.org/git/legacytest.git v2\.0\.0\+incompatible$'
3738

3839
# v2.0.0+incompatible by hash (back on master)
39-
go get ...test@d7ae1e4
40+
go get ...test.git@d7ae1e4
4041
go list -m all
41-
stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
42+
stdout '^vcs-test.golang.org/git/legacytest.git v2\.0\.0\+incompatible$'
4243

4344
# v1.2.1-0.pseudo
44-
go get ...test@d2d4c3e
45+
go get ...test.git@d2d4c3e
4546
go list -m all
46-
stdout '^github.com/rsc/legacytest v1\.2\.1-0\.\d{14}-d2d4c3ea6623$'
47+
stdout '^vcs-test.golang.org/git/legacytest.git v1\.2\.1-0\.\d{14}-d2d4c3ea6623$'
4748

4849
# v1.2.0
49-
go get ...test@9f6f860
50+
go get ...test.git@9f6f860
5051
go list -m all
51-
stdout '^github.com/rsc/legacytest v1\.2\.0$'
52+
stdout '^vcs-test.golang.org/git/legacytest.git v1\.2\.0$'
5253

5354
# v1.1.0-pre.0.pseudo
54-
go get ...test@fb3c628
55+
go get ...test.git@fb3c628
5556
go list -m all
56-
stdout '^github.com/rsc/legacytest v1\.1\.0-pre\.0\.\d{14}-fb3c628075e3$'
57+
stdout '^vcs-test.golang.org/git/legacytest.git v1\.1\.0-pre\.0\.\d{14}-fb3c628075e3$'
5758

5859
# v1.1.0-pre (no longer on master)
59-
go get ...test@731e3b1
60+
go get ...test.git@731e3b1
6061
go list -m all
61-
stdout '^github.com/rsc/legacytest v1\.1\.0-pre$'
62+
stdout '^vcs-test.golang.org/git/legacytest.git v1\.1\.0-pre$'
6263

6364
# v1.0.1-0.pseudo
64-
go get ...test@fa4f5d6
65+
go get ...test.git@fa4f5d6
6566
go list -m all
66-
stdout '^github.com/rsc/legacytest v1\.0\.1-0\.\d{14}-fa4f5d6a71c6$'
67+
stdout '^vcs-test.golang.org/git/legacytest.git v1\.0\.1-0\.\d{14}-fa4f5d6a71c6$'
6768

6869
# v1.0.0
69-
go get ...test@7fff7f3
70+
go get ...test.git@7fff7f3
7071
go list -m all
71-
stdout '^github.com/rsc/legacytest v1\.0\.0$'
72+
stdout '^vcs-test.golang.org/git/legacytest.git v1\.0\.0$'
7273

7374
# v0.0.0-pseudo
74-
go get ...test@52853eb
75+
go get ...test.git@52853eb
7576
go list -m all
76-
stdout '^github.com/rsc/legacytest v0\.0\.0-\d{14}-52853eb7b552$'
77+
stdout '^vcs-test.golang.org/git/legacytest.git v0\.0\.0-\d{14}-52853eb7b552$'
7778

7879
-- go.mod --
7980
module x
8081
-- x.go --
8182
package x
82-
import "github.com/rsc/legacytest"
83+
import "vcs-test.golang.org/git/legacytest.git"
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
env GO111MODULE=on
2+
3+
[!exec:hg] skip
4+
[short] skip
5+
6+
# Testing hg->module converter's generation of +incompatible tags; turn off proxy.
7+
env GOPROXY=direct
8+
env GOSUMDB=off
9+
10+
# get default
11+
go get vcs-test.golang.org/hg/legacytest.hg@default
12+
go list -m all
13+
stdout '^vcs-test.golang.org/hg/legacytest.hg v1\.2\.1-0\.20180717164942-2840708d1294$'
14+
15+
# get should include incompatible tags in "latest" calculation.
16+
go mod edit -droprequire vcs-test.golang.org/hg/legacytest.hg
17+
go get vcs-test.golang.org/hg/legacytest.hg@latest
18+
go list
19+
go list -m all
20+
stdout '^vcs-test.golang.org/hg/legacytest.hg v2\.0\.0\+incompatible$'
21+
22+
# v2.0.1-0.pseudo+incompatible
23+
go get ...test.hg@d6ad6040
24+
go list -m all
25+
stdout '^vcs-test.golang.org/hg/legacytest.hg v2\.0\.1-0\.\d{14}-d6ad604046f6\+incompatible$'
26+
27+
# v2.0.0+incompatible by tag+incompatible
28+
go get [email protected]+incompatible
29+
go list -m all
30+
stdout '^vcs-test.golang.org/hg/legacytest.hg v2\.0\.0\+incompatible$'
31+
32+
# v2.0.0+incompatible by tag
33+
34+
go list -m all
35+
stdout '^vcs-test.golang.org/hg/legacytest.hg v2\.0\.0\+incompatible$'
36+
37+
# v2.0.0+incompatible by hash (back on master)
38+
go get ...test.hg@e64782f
39+
go list -m all
40+
stdout '^vcs-test.golang.org/hg/legacytest.hg v2\.0\.0\+incompatible$'
41+
42+
# v1.2.1-0.pseudo
43+
go get ...test.hg@ed9a22e
44+
go list -m all
45+
stdout '^vcs-test.golang.org/hg/legacytest.hg v1\.2\.1-0\.\d{14}-ed9a22ebb8a1$'
46+
47+
# v1.2.0
48+
go get ...test.hg@07462d
49+
go list -m all
50+
stdout '^vcs-test.golang.org/hg/legacytest.hg v1\.2\.0$'
51+
52+
# v1.1.0-pre.0.pseudo
53+
go get ...test.hg@accb16
54+
go list -m all
55+
stdout '^vcs-test.golang.org/hg/legacytest.hg v1\.1\.0-pre\.0\.\d{14}-accb169a3696$'
56+
57+
# v1.1.0-pre (no longer on master)
58+
go get ...test.hg@90da67a9
59+
go list -m all
60+
stdout '^vcs-test.golang.org/hg/legacytest.hg v1\.1\.0-pre$'
61+
62+
# v1.0.1-0.pseudo
63+
go get ...test.hg@c6260a
64+
go list -m all
65+
stdout '^vcs-test.golang.org/hg/legacytest.hg v1\.0\.1-0\.\d{14}-c6260ab8dc3e$'
66+
67+
# v1.0.0
68+
go get ...test.hg@d6ad17
69+
go list -m all
70+
stdout '^vcs-test.golang.org/hg/legacytest.hg v1\.0\.0$'
71+
72+
# v0.0.0-pseudo
73+
go get ...test.hg@ee0106d
74+
go list -m all
75+
stdout '^vcs-test.golang.org/hg/legacytest.hg v0\.0\.0-\d{14}-ee0106da3c7c$'
76+
77+
-- go.mod --
78+
module x
79+
-- x.go --
80+
package x
81+
import "vcs-test.golang.org/hg/legacytest.hg"

src/cmd/go/testdata/script/reuse_hg.txt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ stdout '"Hash": "1e531550e864b16f25013cfbbf2d8e7cf07a0374"'
128128
# go mod download vcstest/tagtests@default needs a RepoSum again
129129
go mod download -x -json vcs-test.golang.org/hg/tagtests.hg@default
130130
cp stdout tagtestsdefault.json
131-
stdout '"Version": "v0.0.0-20190509225625-8d0b18b816df"'
131+
stdout '"Version": "v0.2.3-0.20190509225625-8d0b18b816df"'
132132
stdout '"Query": "default"'
133133
stdout '"VCS": "hg"'
134134
stdout '"URL": ".*/hg/tagtests"'
@@ -292,10 +292,7 @@ go clean -modcache
292292
go mod download -reuse=tagtestsdefault.json -x -json vcs-test.golang.org/hg/tagtests.hg@default
293293
! stderr 'hg( .*)* pull'
294294
stdout '"Reuse": true'
295-
# NOTE: Strictly speaking this should be v0.2.3-... but we never
296-
# implemented Mercurial support for finding ancestor tags to
297-
# create pseudo-versions.
298-
stdout '"Version": "v0.0.0-20190509225625-8d0b18b816df"'
295+
stdout '"Version": "v0.2.3-0.20190509225625-8d0b18b816df"'
299296
stdout '"Query": "default"'
300297
stdout '"VCS": "hg"'
301298
stdout '"URL": ".*/hg/tagtests"'
@@ -310,7 +307,7 @@ go clean -modcache
310307
go mod download -reuse=all.json -x -json vcs-test.golang.org/hg/tagtests.hg@default
311308
! stderr 'hg( .*)* pull'
312309
stdout '"Reuse": true'
313-
stdout '"Version": "v0.0.0-20190509225625-8d0b18b816df"'
310+
stdout '"Version": "v0.2.3-0.20190509225625-8d0b18b816df"'
314311
stdout '"Query": "default"'
315312
stdout '"VCS": "hg"'
316313
stdout '"URL": ".*/hg/tagtests"'

0 commit comments

Comments
 (0)