diff options
| author | Deepak Rathore <deeratho@cisco.com> | 2026-02-11 21:01:50 -0800 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2026-02-27 17:45:06 +0000 |
| commit | c13443407a5d7d6fe566677aecae19a749c291c3 (patch) | |
| tree | 7695746c7e44c6bd7f7961a3bf82fd0b2aca5ee2 /meta | |
| parent | a231c49abc399af64185f7bc8ca1cded0191dd8b (diff) | |
| download | poky-c13443407a5d7d6fe566677aecae19a749c291c3.tar.gz | |
go 1.22.12: Fix CVE-2025-68119
Upstream Repository: https://github.com/golang/go.git
Bug details: https://nvd.nist.gov/vuln/detail/CVE-2025-68119
Type: Security Fix
CVE: CVE-2025-68119
Score: 7.0
Patch:
[1] https://github.com/golang/go/commit/62452bed4801
[2] https://github.com/golang/go/commit/73fe85f0ea1b
Note:
- First commit [1] is a dependent patch which is required additionally
in original fix [2] to define ENV variable changes in
src/cmd/go/internal/vcs/vcs.go file.
(From OE-Core rev: ef995146623cf65c2e30f37b09847883ca7481bb)
Signed-off-by: Deepak Rathore <deeratho@cisco.com>
Signed-off-by: Yoann Congal <yoann.congal@smile.fr>
Signed-off-by: Paul Barker <paul@pbarker.dev>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
| -rw-r--r-- | meta/recipes-devtools/go/go-1.22.12.inc | 2 | ||||
| -rw-r--r-- | meta/recipes-devtools/go/go/CVE-2025-68119-dependent.patch | 175 | ||||
| -rw-r--r-- | meta/recipes-devtools/go/go/CVE-2025-68119.patch | 828 |
3 files changed, 1005 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index 82019f25dd..ca0f05f7c8 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc | |||
| @@ -35,6 +35,8 @@ SRC_URI += "\ | |||
| 35 | file://CVE-2025-61726.patch \ | 35 | file://CVE-2025-61726.patch \ |
| 36 | file://CVE-2025-61728.patch \ | 36 | file://CVE-2025-61728.patch \ |
| 37 | file://CVE-2025-61731.patch \ | 37 | file://CVE-2025-61731.patch \ |
| 38 | file://CVE-2025-68119-dependent.patch \ | ||
| 39 | file://CVE-2025-68119.patch \ | ||
| 38 | " | 40 | " |
| 39 | SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" | 41 | SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" |
| 40 | 42 | ||
diff --git a/meta/recipes-devtools/go/go/CVE-2025-68119-dependent.patch b/meta/recipes-devtools/go/go/CVE-2025-68119-dependent.patch new file mode 100644 index 0000000000..5875d129cc --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-68119-dependent.patch | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | From 121b6cb231b5d904c03739495fcda69152d83f88 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Matt Harbison <mharbison72@gmail.com> | ||
| 3 | Date: Sat, 3 Aug 2024 00:06:30 +0000 | ||
| 4 | Subject: [PATCH] cmd/go: fix the accuracy of Mercurial vcs.* stamped data | ||
| 5 | |||
| 6 | There were a few Mercurial command line uses that could cause the wrong | ||
| 7 | data to be used: | ||
| 8 | |||
| 9 | * The log command needs '-r.' to specify the currently checked out commit | ||
| 10 | * HGPLAIN is needed to disable optional output on commands | ||
| 11 | * '-S' is needed to for the 'status' command to recurse into any subrepos | ||
| 12 | |||
| 13 | The most likely issue to be seen here was the use of '-l1' instead of | ||
| 14 | '-r.', which prints the most recent commit instead of the current checkout. | ||
| 15 | Since tagging in Mercurial creates a new commit, this basically means the | ||
| 16 | data was wrong for every tagged build. | ||
| 17 | |||
| 18 | This also adds an hgrc config file to the test, with config options to | ||
| 19 | keep the time and author values fixed. It's what's used in the Mercurial | ||
| 20 | test harness to keep the commit hashes stable, and allows the tests here to | ||
| 21 | also match the time and the revision ID, to prevent regressing. | ||
| 22 | |||
| 23 | Fixes #63532 | ||
| 24 | |||
| 25 | CVE: CVE-2025-68119 | ||
| 26 | Upstream-Status: Backport [https://github.com/golang/go/commit/62452bed4801] | ||
| 27 | |||
| 28 | Change-Id: I5b9971ce87c83431ec77e4a002bdc33fcf393856 | ||
| 29 | GitHub-Last-Rev: 62c9db0a28fee5881d0fe49f7bbb6e1653c7ff60 | ||
| 30 | GitHub-Pull-Request: golang/go#63557 | ||
| 31 | Reviewed-on: https://go-review.googlesource.com/c/go/+/535377 | ||
| 32 | Reviewed-by: Bryan Mills <bcmills@google.com> | ||
| 33 | LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> | ||
| 34 | Reviewed-by: Sam Thanawalla <samthanawalla@google.com> | ||
| 35 | Auto-Submit: Sam Thanawalla <samthanawalla@google.com> | ||
| 36 | Reviewed-by: Michael Matloob <matloob@golang.org> | ||
| 37 | (cherry picked from commit 62452bed480108623910feace4a5cea5448e6822) | ||
| 38 | Signed-off-by: Deepak Rathore <deeratho@cisco.com> | ||
| 39 | --- | ||
| 40 | src/cmd/go/internal/vcs/vcs.go | 13 +++++-- | ||
| 41 | .../testdata/script/version_buildvcs_hg.txt | 39 ++++++++++++++++--- | ||
| 42 | 2 files changed, 43 insertions(+), 9 deletions(-) | ||
| 43 | |||
| 44 | diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go | ||
| 45 | index 89d9f0e94e..60f76d77cf 100644 | ||
| 46 | --- a/src/cmd/go/internal/vcs/vcs.go | ||
| 47 | +++ b/src/cmd/go/internal/vcs/vcs.go | ||
| 48 | @@ -37,6 +37,7 @@ import ( | ||
| 49 | type Cmd struct { | ||
| 50 | Name string | ||
| 51 | Cmd string // name of binary to invoke command | ||
| 52 | + Env []string // any environment values to set/override | ||
| 53 | RootNames []rootName // filename and mode indicating the root of a checkout directory | ||
| 54 | |||
| 55 | CreateCmd []string // commands to download a fresh copy of a repository | ||
| 56 | @@ -154,6 +155,10 @@ func vcsByCmd(cmd string) *Cmd { | ||
| 57 | var vcsHg = &Cmd{ | ||
| 58 | Name: "Mercurial", | ||
| 59 | Cmd: "hg", | ||
| 60 | + | ||
| 61 | + // HGPLAIN=1 turns off additional output that a user may have enabled via | ||
| 62 | + // config options or certain extensions. | ||
| 63 | + Env: []string{"HGPLAIN=1"}, | ||
| 64 | RootNames: []rootName{ | ||
| 65 | {filename: ".hg", isDir: true}, | ||
| 66 | }, | ||
| 67 | @@ -189,12 +194,11 @@ func hgRemoteRepo(vcsHg *Cmd, rootDir string) (remoteRepo string, err error) { | ||
| 68 | |||
| 69 | func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) { | ||
| 70 | // Output changeset ID and seconds since epoch. | ||
| 71 | - out, err := vcsHg.runOutputVerboseOnly(rootDir, `log -l1 -T {node}:{date|hgdate}`) | ||
| 72 | + out, err := vcsHg.runOutputVerboseOnly(rootDir, `log -r. -T {node}:{date|hgdate}`) | ||
| 73 | if err != nil { | ||
| 74 | return Status{}, err | ||
| 75 | } | ||
| 76 | |||
| 77 | - // Successful execution without output indicates an empty repo (no commits). | ||
| 78 | var rev string | ||
| 79 | var commitTime time.Time | ||
| 80 | if len(out) > 0 { | ||
| 81 | @@ -209,7 +213,7 @@ func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) { | ||
| 82 | } | ||
| 83 | |||
| 84 | // Also look for untracked files. | ||
| 85 | - out, err = vcsHg.runOutputVerboseOnly(rootDir, "status") | ||
| 86 | + out, err = vcsHg.runOutputVerboseOnly(rootDir, "status -S") | ||
| 87 | if err != nil { | ||
| 88 | return Status{}, err | ||
| 89 | } | ||
| 90 | @@ -689,6 +693,9 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([ | ||
| 91 | |||
| 92 | cmd := exec.Command(v.Cmd, args...) | ||
| 93 | cmd.Dir = dir | ||
| 94 | + if v.Env != nil { | ||
| 95 | + cmd.Env = append(cmd.Environ(), v.Env...) | ||
| 96 | + } | ||
| 97 | if cfg.BuildX { | ||
| 98 | fmt.Fprintf(os.Stderr, "cd %s\n", dir) | ||
| 99 | fmt.Fprintf(os.Stderr, "%s %s\n", v.Cmd, strings.Join(args, " ")) | ||
| 100 | diff --git a/src/cmd/go/testdata/script/version_buildvcs_hg.txt b/src/cmd/go/testdata/script/version_buildvcs_hg.txt | ||
| 101 | index fbbd886102..13904fae12 100644 | ||
| 102 | --- a/src/cmd/go/testdata/script/version_buildvcs_hg.txt | ||
| 103 | +++ b/src/cmd/go/testdata/script/version_buildvcs_hg.txt | ||
| 104 | @@ -6,6 +6,8 @@ | ||
| 105 | [short] skip | ||
| 106 | env GOBIN=$WORK/gopath/bin | ||
| 107 | env oldpath=$PATH | ||
| 108 | +env TZ=GMT | ||
| 109 | +env HGRCPATH=$WORK/hgrc | ||
| 110 | cd repo/a | ||
| 111 | |||
| 112 | # If there's no local repository, there's no VCS info. | ||
| 113 | @@ -29,24 +31,43 @@ cd .. | ||
| 114 | env PATH=$oldpath | ||
| 115 | rm .hg | ||
| 116 | |||
| 117 | -# If there is an empty repository in a parent directory, only "uncommitted" is tagged. | ||
| 118 | +# An empty repository or one explicitly updated to null uses the null cset ID, | ||
| 119 | +# and the time is hard set to 1/1/70, regardless of the current time. | ||
| 120 | exec hg init | ||
| 121 | cd a | ||
| 122 | go install | ||
| 123 | go version -m $GOBIN/a$GOEXE | ||
| 124 | -! stdout vcs.revision | ||
| 125 | -! stdout vcs.time | ||
| 126 | +stdout '^\tbuild\tvcs.revision=0000000000000000000000000000000000000000$' | ||
| 127 | +stdout '^\tbuild\tvcs.time=1970-01-01T00:00:00Z$' | ||
| 128 | stdout '^\tbuild\tvcs.modified=true$' | ||
| 129 | cd .. | ||
| 130 | |||
| 131 | # Revision and commit time are tagged for repositories with commits. | ||
| 132 | exec hg add a README | ||
| 133 | -exec hg commit -m 'initial commit' | ||
| 134 | +exec hg commit -m 'initial commit' --user test-user --date '2024-07-31T01:21:27+00:00' | ||
| 135 | cd a | ||
| 136 | go install | ||
| 137 | go version -m $GOBIN/a$GOEXE | ||
| 138 | -stdout '^\tbuild\tvcs.revision=' | ||
| 139 | -stdout '^\tbuild\tvcs.time=' | ||
| 140 | +stdout '^\tbuild\tvcs.revision=71eaed52daeaafea83cb604f75b0a0336ef2c345$' | ||
| 141 | +stdout '^\tbuild\tvcs.time=2024-07-31T01:21:27Z$' | ||
| 142 | +stdout '^\tbuild\tvcs.modified=false$' | ||
| 143 | +rm $GOBIN/a$GOEXE | ||
| 144 | + | ||
| 145 | +# Add an extra commit and then back off of it to show that the hash is | ||
| 146 | +# from the checked out revision, not the tip revision. | ||
| 147 | +cp ../../outside/empty.txt . | ||
| 148 | +exec hg ci -Am 'another commit' --user test-user --date '2024-08-01T19:24:38+00:00' | ||
| 149 | +exec hg update --clean -r '.^' | ||
| 150 | + | ||
| 151 | +# Modified state is not thrown off by extra status output | ||
| 152 | +exec hg bisect -v -g . | ||
| 153 | +exec hg bisect -v -b '.^^' | ||
| 154 | +exec hg status | ||
| 155 | +stdout '^.+' | ||
| 156 | +go install | ||
| 157 | +go version -m $GOBIN/a$GOEXE | ||
| 158 | +stdout '^\tbuild\tvcs.revision=71eaed52daeaafea83cb604f75b0a0336ef2c345$' | ||
| 159 | +stdout '^\tbuild\tvcs.time=2024-07-31T01:21:27Z$' | ||
| 160 | stdout '^\tbuild\tvcs.modified=false$' | ||
| 161 | rm $GOBIN/a$GOEXE | ||
| 162 | |||
| 163 | @@ -88,4 +109,10 @@ go 1.18 | ||
| 164 | package main | ||
| 165 | |||
| 166 | func main() {} | ||
| 167 | +-- $WORK/hgrc -- | ||
| 168 | +[ui] | ||
| 169 | +# tweakdefaults is an opt-in that may print extra output in commands like | ||
| 170 | +# status. That can be disabled by setting HGPLAIN=1. | ||
| 171 | +tweakdefaults = 1 | ||
| 172 | + | ||
| 173 | -- outside/empty.txt -- | ||
| 174 | -- | ||
| 175 | 2.35.6 | ||
diff --git a/meta/recipes-devtools/go/go/CVE-2025-68119.patch b/meta/recipes-devtools/go/go/CVE-2025-68119.patch new file mode 100644 index 0000000000..d3f1724453 --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-68119.patch | |||
| @@ -0,0 +1,828 @@ | |||
| 1 | From 204e2fdacfbdb72a0b85fb526c8599128e430e94 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Roland Shoemaker <bracewell@google.com> | ||
| 3 | Date: Wed, 10 Dec 2025 08:13:07 -0500 | ||
| 4 | Subject: [PATCH] [release-branch.go1.24] cmd/go: update VCS commands to use | ||
| 5 | safer flag/argument syntax | ||
| 6 | |||
| 7 | In various situations, the toolchain invokes VCS commands. Some of these | ||
| 8 | commands take arbitrary input, either provided by users or fetched from | ||
| 9 | external sources. To prevent potential command injection vulnerabilities | ||
| 10 | or misinterpretation of arguments as flags, this change updates the VCS | ||
| 11 | commands to use various techniques to separate flags from positional | ||
| 12 | arguments, and to directly associate flags with their values. | ||
| 13 | |||
| 14 | Additionally, we update the environment variable for Mercurial to use | ||
| 15 | `HGPLAIN=+strictflags`, which is the more explicit way to disable user | ||
| 16 | configurations (intended or otherwise) that might interfere with command | ||
| 17 | execution. | ||
| 18 | |||
| 19 | We also now disallow version strings from being prefixed with '-' or | ||
| 20 | '/', as doing so opens us up to making the same mistake again in the | ||
| 21 | future. As far as we know there are currently ~0 public modules affected | ||
| 22 | by this. | ||
| 23 | |||
| 24 | While I was working on cmd/go/internal/vcs, I also noticed that a | ||
| 25 | significant portion of the commands being implemented were dead code. | ||
| 26 | In order to reduce the maintenance burden and surface area for potential | ||
| 27 | issues, I removed the dead code for unused commands. | ||
| 28 | |||
| 29 | We should probably follow up with a more structured change to make it | ||
| 30 | harder to accidentally re-introduce these issues in the future, but for | ||
| 31 | now this addresses the issue at hand. | ||
| 32 | |||
| 33 | Thanks to splitline (@splitline) from DEVCORE Research Team for | ||
| 34 | reporting this issue. | ||
| 35 | |||
| 36 | Fixes CVE-2025-68119 | ||
| 37 | Updates #77099 | ||
| 38 | Fixes #77103 | ||
| 39 | |||
| 40 | CVE: CVE-2025-68119 | ||
| 41 | Upstream-Status: Backport [https://github.com/golang/go/commit/73fe85f0ea1b] | ||
| 42 | |||
| 43 | Backport Changes: | ||
| 44 | - In file src/cmd/go/internal/modfetch/codehost/git.go, Replaced the | ||
| 45 | function call runGIT with RUN. This changes is not present in current | ||
| 46 | version v1.22.12 and this changes were introduced in version v1.24 by | ||
| 47 | this commit https://github.com/golang/go/commit/8aa2eed8fb90 | ||
| 48 | |||
| 49 | Change-Id: I9d9f4ee05b95be49fe14edf71a1b8e6c0784378e | ||
| 50 | Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3260 | ||
| 51 | Reviewed-by: Damien Neil <dneil@google.com> | ||
| 52 | Reviewed-by: Nicholas Husin <husin@google.com> | ||
| 53 | Reviewed-on: https://go-review.googlesource.com/c/go/+/736710 | ||
| 54 | Auto-Submit: Michael Pratt <mpratt@google.com> | ||
| 55 | Reviewed-by: Junyang Shao <shaojunyang@google.com> | ||
| 56 | LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> | ||
| 57 | (cherry picked from commit 94a1296a457387d1fd6eca1a9bcd44e89bdd9d55) | ||
| 58 | Reviewed-on: https://go-review.googlesource.com/c/go/+/739421 | ||
| 59 | Auto-Submit: Dmitri Shuralyov <dmitshur@google.com> | ||
| 60 | (cherry picked from commit 73fe85f0ea1bf2cec8e9a89bf5645de06ecaa0a6) | ||
| 61 | Signed-off-by: Deepak Rathore <deeratho@cisco.com> | ||
| 62 | --- | ||
| 63 | src/cmd/go/internal/modcmd/edit.go | 10 +- | ||
| 64 | src/cmd/go/internal/modfetch/codehost/git.go | 20 +- | ||
| 65 | src/cmd/go/internal/modfetch/codehost/vcs.go | 20 +- | ||
| 66 | src/cmd/go/internal/modget/query.go | 5 +- | ||
| 67 | src/cmd/go/internal/modload/build.go | 12 +- | ||
| 68 | src/cmd/go/internal/modload/list.go | 30 +- | ||
| 69 | src/cmd/go/internal/toolchain/select.go | 7 +- | ||
| 70 | src/cmd/go/internal/vcs/vcs.go | 331 +------------------ | ||
| 71 | src/cmd/go/internal/workcmd/edit.go | 5 +- | ||
| 72 | 9 files changed, 96 insertions(+), 344 deletions(-) | ||
| 73 | |||
| 74 | diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go | ||
| 75 | index db131b0881..330603fe32 100644 | ||
| 76 | --- a/src/cmd/go/internal/modcmd/edit.go | ||
| 77 | +++ b/src/cmd/go/internal/modcmd/edit.go | ||
| 78 | @@ -284,7 +284,10 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) { | ||
| 79 | |||
| 80 | // parsePathVersion parses -flag=arg expecting arg to be path@version. | ||
| 81 | func parsePathVersion(flag, arg string) (path, version string) { | ||
| 82 | - before, after, found := strings.Cut(arg, "@") | ||
| 83 | + before, after, found, err := modload.ParsePathVersion(arg) | ||
| 84 | + if err != nil { | ||
| 85 | + base.Fatalf("go: -%s=%s: %v", flag, arg, err) | ||
| 86 | + } | ||
| 87 | if !found { | ||
| 88 | base.Fatalf("go: -%s=%s: need path@version", flag, arg) | ||
| 89 | } | ||
| 90 | @@ -318,7 +321,10 @@ func parsePathVersionOptional(adj, arg string, allowDirPath bool) (path, version | ||
| 91 | if allowDirPath && modfile.IsDirectoryPath(arg) { | ||
| 92 | return arg, "", nil | ||
| 93 | } | ||
| 94 | - before, after, found := strings.Cut(arg, "@") | ||
| 95 | + before, after, found, err := modload.ParsePathVersion(arg) | ||
| 96 | + if err != nil { | ||
| 97 | + return "", "", err | ||
| 98 | + } | ||
| 99 | if !found { | ||
| 100 | path = arg | ||
| 101 | } else { | ||
| 102 | diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go | ||
| 103 | index 9996be7af7..45727ae3fb 100644 | ||
| 104 | --- a/src/cmd/go/internal/modfetch/codehost/git.go | ||
| 105 | +++ b/src/cmd/go/internal/modfetch/codehost/git.go | ||
| 106 | @@ -246,7 +246,7 @@ func (r *gitRepo) loadRefs(ctx context.Context) (map[string]string, error) { | ||
| 107 | r.refsErr = err | ||
| 108 | return | ||
| 109 | } | ||
| 110 | - out, gitErr := Run(ctx, r.dir, "git", "ls-remote", "-q", r.remote) | ||
| 111 | + out, gitErr := Run(ctx, r.dir, "git", "ls-remote", "-q","--end-of-options", r.remote) | ||
| 112 | release() | ||
| 113 | |||
| 114 | if gitErr != nil { | ||
| 115 | @@ -509,7 +509,7 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro | ||
| 116 | if fromTag && !slices.Contains(info.Tags, tag) { | ||
| 117 | // The local repo includes the commit hash we want, but it is missing | ||
| 118 | // the corresponding tag. Add that tag and try again. | ||
| 119 | - _, err := Run(ctx, r.dir, "git", "tag", tag, hash) | ||
| 120 | + _, err := Run(ctx, r.dir, "git", "tag","--end-of-options", tag, hash) | ||
| 121 | if err != nil { | ||
| 122 | return nil, err | ||
| 123 | } | ||
| 124 | @@ -554,7 +554,7 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro | ||
| 125 | // an apparent Git bug introduced in Git 2.21 (commit 61c771), | ||
| 126 | // which causes the handler for protocol version 1 to sometimes miss | ||
| 127 | // tags that point to the requested commit (see https://go.dev/issue/56881). | ||
| 128 | - _, err = Run(ctx, r.dir, "git", "-c", "protocol.version=2", "fetch", "-f", "--depth=1", r.remote, refspec) | ||
| 129 | + _, err = Run(ctx, r.dir, "git", "-c", "protocol.version=2", "fetch", "-f", "--depth=1","--end-of-options", r.remote, refspec) | ||
| 130 | release() | ||
| 131 | |||
| 132 | if err == nil { | ||
| 133 | @@ -597,12 +597,12 @@ func (r *gitRepo) fetchRefsLocked(ctx context.Context) error { | ||
| 134 | } | ||
| 135 | defer release() | ||
| 136 | |||
| 137 | - if _, err := Run(ctx, r.dir, "git", "fetch", "-f", r.remote, "refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { | ||
| 138 | + if _, err := Run(ctx, r.dir, "git", "fetch", "-f","--end-of-options", r.remote, "refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { | ||
| 139 | return err | ||
| 140 | } | ||
| 141 | |||
| 142 | if _, err := os.Stat(filepath.Join(r.dir, "shallow")); err == nil { | ||
| 143 | - if _, err := Run(ctx, r.dir, "git", "fetch", "--unshallow", "-f", r.remote); err != nil { | ||
| 144 | + if _, err := Run(ctx, r.dir, "git", "fetch", "--unshallow", "-f", "--end-of-options",r.remote); err != nil { | ||
| 145 | return err | ||
| 146 | } | ||
| 147 | } | ||
| 148 | @@ -615,7 +615,7 @@ func (r *gitRepo) fetchRefsLocked(ctx context.Context) error { | ||
| 149 | // statLocal returns a new RevInfo describing rev in the local git repository. | ||
| 150 | // It uses version as info.Version. | ||
| 151 | func (r *gitRepo) statLocal(ctx context.Context, version, rev string) (*RevInfo, error) { | ||
| 152 | - out, err := Run(ctx, r.dir, "git", "-c", "log.showsignature=false", "log", "--no-decorate", "-n1", "--format=format:%H %ct %D", rev, "--") | ||
| 153 | + out, err := Run(ctx, r.dir, "git", "-c", "log.showsignature=false", "log", "--no-decorate", "-n1", "--format=format:%H %ct %D","--end-of-options", rev, "--") | ||
| 154 | if err != nil { | ||
| 155 | // Return info with Origin.RepoSum if possible to allow caching of negative lookup. | ||
| 156 | var info *RevInfo | ||
| 157 | @@ -705,7 +705,7 @@ func (r *gitRepo) ReadFile(ctx context.Context, rev, file string, maxSize int64) | ||
| 158 | if err != nil { | ||
| 159 | return nil, err | ||
| 160 | } | ||
| 161 | - out, err := Run(ctx, r.dir, "git", "cat-file", "blob", info.Name+":"+file) | ||
| 162 | + out, err := Run(ctx, r.dir, "git", "cat-file","--end-of-options", "blob", info.Name+":"+file) | ||
| 163 | if err != nil { | ||
| 164 | return nil, fs.ErrNotExist | ||
| 165 | } | ||
| 166 | @@ -723,7 +723,7 @@ func (r *gitRepo) RecentTag(ctx context.Context, rev, prefix string, allowed fun | ||
| 167 | // result is definitive. | ||
| 168 | describe := func() (definitive bool) { | ||
| 169 | var out []byte | ||
| 170 | - out, err = Run(ctx, r.dir, "git", "for-each-ref", "--format", "%(refname)", "refs/tags", "--merged", rev) | ||
| 171 | + out, err = Run(ctx, r.dir, "git", "for-each-ref", "--format=%(refname)", "--merged="+rev) | ||
| 172 | if err != nil { | ||
| 173 | return true | ||
| 174 | } | ||
| 175 | @@ -865,7 +865,7 @@ func (r *gitRepo) ReadZip(ctx context.Context, rev, subdir string, maxSize int64 | ||
| 176 | // TODO: Use maxSize or drop it. | ||
| 177 | args := []string{} | ||
| 178 | if subdir != "" { | ||
| 179 | - args = append(args, "--", subdir) | ||
| 180 | + args = append(args, subdir) | ||
| 181 | } | ||
| 182 | info, err := r.Stat(ctx, rev) // download rev into local git repo | ||
| 183 | if err != nil { | ||
| 184 | @@ -887,7 +887,7 @@ func (r *gitRepo) ReadZip(ctx context.Context, rev, subdir string, maxSize int64 | ||
| 185 | // text file line endings. Setting -c core.autocrlf=input means only | ||
| 186 | // translate files on the way into the repo, not on the way out (archive). | ||
| 187 | // The -c core.eol=lf should be unnecessary but set it anyway. | ||
| 188 | - archive, err := Run(ctx, r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", info.Name, args) | ||
| 189 | + archive, err := Run(ctx, r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", "--end-of-options", info.Name, args) | ||
| 190 | if err != nil { | ||
| 191 | if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) { | ||
| 192 | return nil, fs.ErrNotExist | ||
| 193 | diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go | ||
| 194 | index 5bd100556b..425f61269f 100644 | ||
| 195 | --- a/src/cmd/go/internal/modfetch/codehost/vcs.go | ||
| 196 | +++ b/src/cmd/go/internal/modfetch/codehost/vcs.go | ||
| 197 | @@ -162,20 +162,20 @@ var vcsCmds = map[string]*vcsCmd{ | ||
| 198 | branchRE: re(`(?m)^[^\n]+$`), | ||
| 199 | badLocalRevRE: re(`(?m)^(tip)$`), | ||
| 200 | statLocal: func(rev, remote string) []string { | ||
| 201 | - return []string{"hg", "log", "-l1", "-r", rev, "--template", "{node} {date|hgdate} {tags}"} | ||
| 202 | + return []string{"hg", "log", "-l1", fmt.Sprintf("--rev=%s", rev), "--template", "{node} {date|hgdate} {tags}"} | ||
| 203 | }, | ||
| 204 | parseStat: hgParseStat, | ||
| 205 | fetch: []string{"hg", "pull", "-f"}, | ||
| 206 | latest: "tip", | ||
| 207 | readFile: func(rev, file, remote string) []string { | ||
| 208 | - return []string{"hg", "cat", "-r", rev, file} | ||
| 209 | + return []string{"hg", "cat", fmt.Sprintf("--rev=%s", rev), "--", file} | ||
| 210 | }, | ||
| 211 | readZip: func(rev, subdir, remote, target string) []string { | ||
| 212 | pattern := []string{} | ||
| 213 | if subdir != "" { | ||
| 214 | - pattern = []string{"-I", subdir + "/**"} | ||
| 215 | + pattern = []string{fmt.Sprintf("--include=%s", subdir+"/**")} | ||
| 216 | } | ||
| 217 | - return str.StringList("hg", "archive", "-t", "zip", "--no-decode", "-r", rev, "--prefix=prefix/", pattern, "--", target) | ||
| 218 | + return str.StringList("hg", "archive", "-t", "zip", "--no-decode", fmt.Sprintf("--rev=%s", rev), "--prefix=prefix/", pattern, "--", target) | ||
| 219 | }, | ||
| 220 | }, | ||
| 221 | |||
| 222 | @@ -215,19 +215,19 @@ var vcsCmds = map[string]*vcsCmd{ | ||
| 223 | tagRE: re(`(?m)^\S+`), | ||
| 224 | badLocalRevRE: re(`^revno:-`), | ||
| 225 | statLocal: func(rev, remote string) []string { | ||
| 226 | - return []string{"bzr", "log", "-l1", "--long", "--show-ids", "-r", rev} | ||
| 227 | + return []string{"bzr", "log", "-l1", "--long", "--show-ids", fmt.Sprintf("--revision=%s", rev)} | ||
| 228 | }, | ||
| 229 | parseStat: bzrParseStat, | ||
| 230 | latest: "revno:-1", | ||
| 231 | readFile: func(rev, file, remote string) []string { | ||
| 232 | - return []string{"bzr", "cat", "-r", rev, file} | ||
| 233 | + return []string{"bzr", "cat", fmt.Sprintf("--revision=%s", rev), "--", file} | ||
| 234 | }, | ||
| 235 | readZip: func(rev, subdir, remote, target string) []string { | ||
| 236 | extra := []string{} | ||
| 237 | if subdir != "" { | ||
| 238 | extra = []string{"./" + subdir} | ||
| 239 | } | ||
| 240 | - return str.StringList("bzr", "export", "--format=zip", "-r", rev, "--root=prefix/", "--", target, extra) | ||
| 241 | + return str.StringList("bzr", "export", "--format=zip", fmt.Sprintf("--revision=%s", rev), "--root=prefix/", "--", target, extra) | ||
| 242 | }, | ||
| 243 | }, | ||
| 244 | |||
| 245 | @@ -242,17 +242,17 @@ var vcsCmds = map[string]*vcsCmd{ | ||
| 246 | }, | ||
| 247 | tagRE: re(`XXXTODO`), | ||
| 248 | statLocal: func(rev, remote string) []string { | ||
| 249 | - return []string{"fossil", "info", "-R", ".fossil", rev} | ||
| 250 | + return []string{"fossil", "info", "-R", ".fossil", "--", rev} | ||
| 251 | }, | ||
| 252 | parseStat: fossilParseStat, | ||
| 253 | latest: "trunk", | ||
| 254 | readFile: func(rev, file, remote string) []string { | ||
| 255 | - return []string{"fossil", "cat", "-R", ".fossil", "-r", rev, file} | ||
| 256 | + return []string{"fossil", "cat", "-R", ".fossil", fmt.Sprintf("-r=%s", rev), "--", file} | ||
| 257 | }, | ||
| 258 | readZip: func(rev, subdir, remote, target string) []string { | ||
| 259 | extra := []string{} | ||
| 260 | if subdir != "" && !strings.ContainsAny(subdir, "*?[],") { | ||
| 261 | - extra = []string{"--include", subdir} | ||
| 262 | + extra = []string{fmt.Sprintf("--include=%s", subdir)} | ||
| 263 | } | ||
| 264 | // Note that vcsRepo.ReadZip below rewrites this command | ||
| 265 | // to run in a different directory, to work around a fossil bug. | ||
| 266 | diff --git a/src/cmd/go/internal/modget/query.go b/src/cmd/go/internal/modget/query.go | ||
| 267 | index 498ba6c2ff..0d33a52677 100644 | ||
| 268 | --- a/src/cmd/go/internal/modget/query.go | ||
| 269 | +++ b/src/cmd/go/internal/modget/query.go | ||
| 270 | @@ -139,7 +139,10 @@ func errSet(err error) pathSet { return pathSet{err: err} } | ||
| 271 | // newQuery returns a new query parsed from the raw argument, | ||
| 272 | // which must be either path or path@version. | ||
| 273 | func newQuery(raw string) (*query, error) { | ||
| 274 | - pattern, rawVers, found := strings.Cut(raw, "@") | ||
| 275 | + pattern, rawVers, found, err := modload.ParsePathVersion(raw) | ||
| 276 | + if err != nil { | ||
| 277 | + return nil, err | ||
| 278 | + } | ||
| 279 | if found && (strings.Contains(rawVers, "@") || rawVers == "") { | ||
| 280 | return nil, fmt.Errorf("invalid module version syntax %q", raw) | ||
| 281 | } | ||
| 282 | diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go | ||
| 283 | index 5cf1487c3e..08acf3aa2b 100644 | ||
| 284 | --- a/src/cmd/go/internal/modload/build.go | ||
| 285 | +++ b/src/cmd/go/internal/modload/build.go | ||
| 286 | @@ -12,7 +12,6 @@ import ( | ||
| 287 | "io/fs" | ||
| 288 | "os" | ||
| 289 | "path/filepath" | ||
| 290 | - "strings" | ||
| 291 | |||
| 292 | "cmd/go/internal/base" | ||
| 293 | "cmd/go/internal/cfg" | ||
| 294 | @@ -88,7 +87,16 @@ func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic { | ||
| 295 | return nil | ||
| 296 | } | ||
| 297 | |||
| 298 | - if path, vers, found := strings.Cut(path, "@"); found { | ||
| 299 | + path, vers, found, err := ParsePathVersion(path) | ||
| 300 | + if err != nil { | ||
| 301 | + return &modinfo.ModulePublic{ | ||
| 302 | + Path: path, | ||
| 303 | + Error: &modinfo.ModuleError{ | ||
| 304 | + Err: err.Error(), | ||
| 305 | + }, | ||
| 306 | + } | ||
| 307 | + } | ||
| 308 | + if found { | ||
| 309 | m := module.Version{Path: path, Version: vers} | ||
| 310 | return moduleInfo(ctx, nil, m, 0, nil) | ||
| 311 | } | ||
| 312 | diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go | ||
| 313 | index ef93c25121..e9efb1918e 100644 | ||
| 314 | --- a/src/cmd/go/internal/modload/list.go | ||
| 315 | +++ b/src/cmd/go/internal/modload/list.go | ||
| 316 | @@ -149,7 +149,11 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List | ||
| 317 | } | ||
| 318 | continue | ||
| 319 | } | ||
| 320 | - if path, vers, found := strings.Cut(arg, "@"); found { | ||
| 321 | + path, vers, found, err := ParsePathVersion(arg) | ||
| 322 | + if err != nil { | ||
| 323 | + base.Fatalf("go: %v", err) | ||
| 324 | + } | ||
| 325 | + if found { | ||
| 326 | if vers == "upgrade" || vers == "patch" { | ||
| 327 | if _, ok := rs.rootSelected(path); !ok || rs.pruning == unpruned { | ||
| 328 | needFullGraph = true | ||
| 329 | @@ -175,7 +179,11 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List | ||
| 330 | |||
| 331 | matchedModule := map[module.Version]bool{} | ||
| 332 | for _, arg := range args { | ||
| 333 | - if path, vers, found := strings.Cut(arg, "@"); found { | ||
| 334 | + path, vers, found, err := ParsePathVersion(arg) | ||
| 335 | + if err != nil { | ||
| 336 | + base.Fatalf("go: %v", err) | ||
| 337 | + } | ||
| 338 | + if found { | ||
| 339 | var current string | ||
| 340 | if mg == nil { | ||
| 341 | current, _ = rs.rootSelected(path) | ||
| 342 | @@ -308,3 +316,21 @@ func modinfoError(path, vers string, err error) *modinfo.ModuleError { | ||
| 343 | |||
| 344 | return &modinfo.ModuleError{Err: err.Error()} | ||
| 345 | } | ||
| 346 | + | ||
| 347 | +// ParsePathVersion parses arg expecting arg to be path@version. If there is no | ||
| 348 | +// '@' in arg, found is false, vers is "", and path is arg. This mirrors the | ||
| 349 | +// typical usage of strings.Cut. ParsePathVersion is meant to be a general | ||
| 350 | +// replacement for strings.Cut in module version parsing. If the version is | ||
| 351 | +// invalid, an error is returned. The version is considered invalid if it is | ||
| 352 | +// prefixed with '-' or '/', which can cause security problems when constructing | ||
| 353 | +// commands to execute that use the version. | ||
| 354 | +func ParsePathVersion(arg string) (path, vers string, found bool, err error) { | ||
| 355 | + path, vers, found = strings.Cut(arg, "@") | ||
| 356 | + if !found { | ||
| 357 | + return arg, "", false, nil | ||
| 358 | + } | ||
| 359 | + if len(vers) > 0 && (vers[0] == '-' || vers[0] == '/') { | ||
| 360 | + return "", "", false, fmt.Errorf("invalid module version %q", vers) | ||
| 361 | + } | ||
| 362 | + return path, vers, true, nil | ||
| 363 | +} | ||
| 364 | diff --git a/src/cmd/go/internal/toolchain/select.go b/src/cmd/go/internal/toolchain/select.go | ||
| 365 | index 14a8d3c21d..838ebae6a7 100644 | ||
| 366 | --- a/src/cmd/go/internal/toolchain/select.go | ||
| 367 | +++ b/src/cmd/go/internal/toolchain/select.go | ||
| 368 | @@ -614,7 +614,10 @@ func goInstallVersion() bool { | ||
| 369 | if !strings.Contains(pkgArg, "@") || build.IsLocalImport(pkgArg) || filepath.IsAbs(pkgArg) { | ||
| 370 | return false | ||
| 371 | } | ||
| 372 | - path, version, _ := strings.Cut(pkgArg, "@") | ||
| 373 | + path, version, _, err := modload.ParsePathVersion(pkgArg) | ||
| 374 | + if err != nil { | ||
| 375 | + base.Fatalf("go: %v", err) | ||
| 376 | + } | ||
| 377 | if path == "" || version == "" || gover.IsToolchain(path) { | ||
| 378 | return false | ||
| 379 | } | ||
| 380 | @@ -650,7 +653,7 @@ func goInstallVersion() bool { | ||
| 381 | allowed = nil | ||
| 382 | } | ||
| 383 | noneSelected := func(path string) (version string) { return "none" } | ||
| 384 | - _, err := modload.QueryPackages(ctx, path, version, noneSelected, allowed) | ||
| 385 | + _, err = modload.QueryPackages(ctx, path, version, noneSelected, allowed) | ||
| 386 | if errors.Is(err, gover.ErrTooNew) { | ||
| 387 | // Run early switch, same one go install or go run would eventually do, | ||
| 388 | // if it understood all the command-line flags. | ||
| 389 | diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go | ||
| 390 | index 60f76d77cf..55bf25ff62 100644 | ||
| 391 | --- a/src/cmd/go/internal/vcs/vcs.go | ||
| 392 | +++ b/src/cmd/go/internal/vcs/vcs.go | ||
| 393 | @@ -17,7 +17,6 @@ import ( | ||
| 394 | "os" | ||
| 395 | "os/exec" | ||
| 396 | "path/filepath" | ||
| 397 | - "regexp" | ||
| 398 | "strconv" | ||
| 399 | "strings" | ||
| 400 | "sync" | ||
| 401 | @@ -40,20 +39,10 @@ type Cmd struct { | ||
| 402 | Env []string // any environment values to set/override | ||
| 403 | RootNames []rootName // filename and mode indicating the root of a checkout directory | ||
| 404 | |||
| 405 | - CreateCmd []string // commands to download a fresh copy of a repository | ||
| 406 | - DownloadCmd []string // commands to download updates into an existing repository | ||
| 407 | - | ||
| 408 | - TagCmd []tagCmd // commands to list tags | ||
| 409 | - TagLookupCmd []tagCmd // commands to lookup tags before running tagSyncCmd | ||
| 410 | - TagSyncCmd []string // commands to sync to specific tag | ||
| 411 | - TagSyncDefault []string // commands to sync to default tag | ||
| 412 | - | ||
| 413 | Scheme []string | ||
| 414 | PingCmd string | ||
| 415 | |||
| 416 | - RemoteRepo func(v *Cmd, rootDir string) (remoteRepo string, err error) | ||
| 417 | - ResolveRepo func(v *Cmd, rootDir, remoteRepo string) (realRepo string, err error) | ||
| 418 | - Status func(v *Cmd, rootDir string) (Status, error) | ||
| 419 | + Status func(v *Cmd, rootDir string) (Status, error) | ||
| 420 | } | ||
| 421 | |||
| 422 | // Status is the current state of a local repository. | ||
| 423 | @@ -156,40 +145,16 @@ var vcsHg = &Cmd{ | ||
| 424 | Name: "Mercurial", | ||
| 425 | Cmd: "hg", | ||
| 426 | |||
| 427 | - // HGPLAIN=1 turns off additional output that a user may have enabled via | ||
| 428 | - // config options or certain extensions. | ||
| 429 | - Env: []string{"HGPLAIN=1"}, | ||
| 430 | + // HGPLAIN=+strictflags turns off additional output that a user may have | ||
| 431 | + // enabled via config options or certain extensions. | ||
| 432 | + Env: []string{"HGPLAIN=+strictflags"}, | ||
| 433 | RootNames: []rootName{ | ||
| 434 | {filename: ".hg", isDir: true}, | ||
| 435 | }, | ||
| 436 | |||
| 437 | - CreateCmd: []string{"clone -U -- {repo} {dir}"}, | ||
| 438 | - DownloadCmd: []string{"pull"}, | ||
| 439 | - | ||
| 440 | - // We allow both tag and branch names as 'tags' | ||
| 441 | - // for selecting a version. This lets people have | ||
| 442 | - // a go.release.r60 branch and a go1 branch | ||
| 443 | - // and make changes in both, without constantly | ||
| 444 | - // editing .hgtags. | ||
| 445 | - TagCmd: []tagCmd{ | ||
| 446 | - {"tags", `^(\S+)`}, | ||
| 447 | - {"branches", `^(\S+)`}, | ||
| 448 | - }, | ||
| 449 | - TagSyncCmd: []string{"update -r {tag}"}, | ||
| 450 | - TagSyncDefault: []string{"update default"}, | ||
| 451 | - | ||
| 452 | - Scheme: []string{"https", "http", "ssh"}, | ||
| 453 | - PingCmd: "identify -- {scheme}://{repo}", | ||
| 454 | - RemoteRepo: hgRemoteRepo, | ||
| 455 | - Status: hgStatus, | ||
| 456 | -} | ||
| 457 | - | ||
| 458 | -func hgRemoteRepo(vcsHg *Cmd, rootDir string) (remoteRepo string, err error) { | ||
| 459 | - out, err := vcsHg.runOutput(rootDir, "paths default") | ||
| 460 | - if err != nil { | ||
| 461 | - return "", err | ||
| 462 | - } | ||
| 463 | - return strings.TrimSpace(string(out)), nil | ||
| 464 | + Scheme: []string{"https", "http", "ssh"}, | ||
| 465 | + PingCmd: "identify -- {scheme}://{repo}", | ||
| 466 | + Status: hgStatus, | ||
| 467 | } | ||
| 468 | |||
| 469 | func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) { | ||
| 470 | @@ -252,25 +217,6 @@ var vcsGit = &Cmd{ | ||
| 471 | {filename: ".git", isDir: true}, | ||
| 472 | }, | ||
| 473 | |||
| 474 | - CreateCmd: []string{"clone -- {repo} {dir}", "-go-internal-cd {dir} submodule update --init --recursive"}, | ||
| 475 | - DownloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"}, | ||
| 476 | - | ||
| 477 | - TagCmd: []tagCmd{ | ||
| 478 | - // tags/xxx matches a git tag named xxx | ||
| 479 | - // origin/xxx matches a git branch named xxx on the default remote repository | ||
| 480 | - {"show-ref", `(?:tags|origin)/(\S+)$`}, | ||
| 481 | - }, | ||
| 482 | - TagLookupCmd: []tagCmd{ | ||
| 483 | - {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`}, | ||
| 484 | - }, | ||
| 485 | - TagSyncCmd: []string{"checkout {tag}", "submodule update --init --recursive"}, | ||
| 486 | - // both createCmd and downloadCmd update the working dir. | ||
| 487 | - // No need to do more here. We used to 'checkout master' | ||
| 488 | - // but that doesn't work if the default branch is not named master. | ||
| 489 | - // DO NOT add 'checkout master' here. | ||
| 490 | - // See golang.org/issue/9032. | ||
| 491 | - TagSyncDefault: []string{"submodule update --init --recursive"}, | ||
| 492 | - | ||
| 493 | Scheme: []string{"git", "https", "http", "git+ssh", "ssh"}, | ||
| 494 | |||
| 495 | // Leave out the '--' separator in the ls-remote command: git 2.7.4 does not | ||
| 496 | @@ -279,54 +225,7 @@ var vcsGit = &Cmd{ | ||
| 497 | // See golang.org/issue/33836. | ||
| 498 | PingCmd: "ls-remote {scheme}://{repo}", | ||
| 499 | |||
| 500 | - RemoteRepo: gitRemoteRepo, | ||
| 501 | - Status: gitStatus, | ||
| 502 | -} | ||
| 503 | - | ||
| 504 | -// scpSyntaxRe matches the SCP-like addresses used by Git to access | ||
| 505 | -// repositories by SSH. | ||
| 506 | -var scpSyntaxRe = lazyregexp.New(`^(\w+)@([\w.-]+):(.*)$`) | ||
| 507 | - | ||
| 508 | -func gitRemoteRepo(vcsGit *Cmd, rootDir string) (remoteRepo string, err error) { | ||
| 509 | - const cmd = "config remote.origin.url" | ||
| 510 | - outb, err := vcsGit.run1(rootDir, cmd, nil, false) | ||
| 511 | - if err != nil { | ||
| 512 | - // if it doesn't output any message, it means the config argument is correct, | ||
| 513 | - // but the config value itself doesn't exist | ||
| 514 | - if outb != nil && len(outb) == 0 { | ||
| 515 | - return "", errors.New("remote origin not found") | ||
| 516 | - } | ||
| 517 | - return "", err | ||
| 518 | - } | ||
| 519 | - out := strings.TrimSpace(string(outb)) | ||
| 520 | - | ||
| 521 | - var repoURL *urlpkg.URL | ||
| 522 | - if m := scpSyntaxRe.FindStringSubmatch(out); m != nil { | ||
| 523 | - // Match SCP-like syntax and convert it to a URL. | ||
| 524 | - // Eg, "git@github.com:user/repo" becomes | ||
| 525 | - // "ssh://git@github.com/user/repo". | ||
| 526 | - repoURL = &urlpkg.URL{ | ||
| 527 | - Scheme: "ssh", | ||
| 528 | - User: urlpkg.User(m[1]), | ||
| 529 | - Host: m[2], | ||
| 530 | - Path: m[3], | ||
| 531 | - } | ||
| 532 | - } else { | ||
| 533 | - repoURL, err = urlpkg.Parse(out) | ||
| 534 | - if err != nil { | ||
| 535 | - return "", err | ||
| 536 | - } | ||
| 537 | - } | ||
| 538 | - | ||
| 539 | - // Iterate over insecure schemes too, because this function simply | ||
| 540 | - // reports the state of the repo. If we can't see insecure schemes then | ||
| 541 | - // we can't report the actual repo URL. | ||
| 542 | - for _, s := range vcsGit.Scheme { | ||
| 543 | - if repoURL.Scheme == s { | ||
| 544 | - return repoURL.String(), nil | ||
| 545 | - } | ||
| 546 | - } | ||
| 547 | - return "", errors.New("unable to parse output of git " + cmd) | ||
| 548 | + Status: gitStatus, | ||
| 549 | } | ||
| 550 | |||
| 551 | func gitStatus(vcsGit *Cmd, rootDir string) (Status, error) { | ||
| 552 | @@ -366,62 +265,9 @@ var vcsBzr = &Cmd{ | ||
| 553 | {filename: ".bzr", isDir: true}, | ||
| 554 | }, | ||
| 555 | |||
| 556 | - CreateCmd: []string{"branch -- {repo} {dir}"}, | ||
| 557 | - | ||
| 558 | - // Without --overwrite bzr will not pull tags that changed. | ||
| 559 | - // Replace by --overwrite-tags after http://pad.lv/681792 goes in. | ||
| 560 | - DownloadCmd: []string{"pull --overwrite"}, | ||
| 561 | - | ||
| 562 | - TagCmd: []tagCmd{{"tags", `^(\S+)`}}, | ||
| 563 | - TagSyncCmd: []string{"update -r {tag}"}, | ||
| 564 | - TagSyncDefault: []string{"update -r revno:-1"}, | ||
| 565 | - | ||
| 566 | - Scheme: []string{"https", "http", "bzr", "bzr+ssh"}, | ||
| 567 | - PingCmd: "info -- {scheme}://{repo}", | ||
| 568 | - RemoteRepo: bzrRemoteRepo, | ||
| 569 | - ResolveRepo: bzrResolveRepo, | ||
| 570 | - Status: bzrStatus, | ||
| 571 | -} | ||
| 572 | - | ||
| 573 | -func bzrRemoteRepo(vcsBzr *Cmd, rootDir string) (remoteRepo string, err error) { | ||
| 574 | - outb, err := vcsBzr.runOutput(rootDir, "config parent_location") | ||
| 575 | - if err != nil { | ||
| 576 | - return "", err | ||
| 577 | - } | ||
| 578 | - return strings.TrimSpace(string(outb)), nil | ||
| 579 | -} | ||
| 580 | - | ||
| 581 | -func bzrResolveRepo(vcsBzr *Cmd, rootDir, remoteRepo string) (realRepo string, err error) { | ||
| 582 | - outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo) | ||
| 583 | - if err != nil { | ||
| 584 | - return "", err | ||
| 585 | - } | ||
| 586 | - out := string(outb) | ||
| 587 | - | ||
| 588 | - // Expect: | ||
| 589 | - // ... | ||
| 590 | - // (branch root|repository branch): <URL> | ||
| 591 | - // ... | ||
| 592 | - | ||
| 593 | - found := false | ||
| 594 | - for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} { | ||
| 595 | - i := strings.Index(out, prefix) | ||
| 596 | - if i >= 0 { | ||
| 597 | - out = out[i+len(prefix):] | ||
| 598 | - found = true | ||
| 599 | - break | ||
| 600 | - } | ||
| 601 | - } | ||
| 602 | - if !found { | ||
| 603 | - return "", fmt.Errorf("unable to parse output of bzr info") | ||
| 604 | - } | ||
| 605 | - | ||
| 606 | - i := strings.Index(out, "\n") | ||
| 607 | - if i < 0 { | ||
| 608 | - return "", fmt.Errorf("unable to parse output of bzr info") | ||
| 609 | - } | ||
| 610 | - out = out[:i] | ||
| 611 | - return strings.TrimSpace(out), nil | ||
| 612 | + Scheme: []string{"https", "http", "bzr", "bzr+ssh"}, | ||
| 613 | + PingCmd: "info -- {scheme}://{repo}", | ||
| 614 | + Status: bzrStatus, | ||
| 615 | } | ||
| 616 | |||
| 617 | func bzrStatus(vcsBzr *Cmd, rootDir string) (Status, error) { | ||
| 618 | @@ -489,45 +335,11 @@ var vcsSvn = &Cmd{ | ||
| 619 | {filename: ".svn", isDir: true}, | ||
| 620 | }, | ||
| 621 | |||
| 622 | - CreateCmd: []string{"checkout -- {repo} {dir}"}, | ||
| 623 | - DownloadCmd: []string{"update"}, | ||
| 624 | - | ||
| 625 | // There is no tag command in subversion. | ||
| 626 | // The branch information is all in the path names. | ||
| 627 | |||
| 628 | - Scheme: []string{"https", "http", "svn", "svn+ssh"}, | ||
| 629 | - PingCmd: "info -- {scheme}://{repo}", | ||
| 630 | - RemoteRepo: svnRemoteRepo, | ||
| 631 | -} | ||
| 632 | - | ||
| 633 | -func svnRemoteRepo(vcsSvn *Cmd, rootDir string) (remoteRepo string, err error) { | ||
| 634 | - outb, err := vcsSvn.runOutput(rootDir, "info") | ||
| 635 | - if err != nil { | ||
| 636 | - return "", err | ||
| 637 | - } | ||
| 638 | - out := string(outb) | ||
| 639 | - | ||
| 640 | - // Expect: | ||
| 641 | - // | ||
| 642 | - // ... | ||
| 643 | - // URL: <URL> | ||
| 644 | - // ... | ||
| 645 | - // | ||
| 646 | - // Note that we're not using the Repository Root line, | ||
| 647 | - // because svn allows checking out subtrees. | ||
| 648 | - // The URL will be the URL of the subtree (what we used with 'svn co') | ||
| 649 | - // while the Repository Root may be a much higher parent. | ||
| 650 | - i := strings.Index(out, "\nURL: ") | ||
| 651 | - if i < 0 { | ||
| 652 | - return "", fmt.Errorf("unable to parse output of svn info") | ||
| 653 | - } | ||
| 654 | - out = out[i+len("\nURL: "):] | ||
| 655 | - i = strings.Index(out, "\n") | ||
| 656 | - if i < 0 { | ||
| 657 | - return "", fmt.Errorf("unable to parse output of svn info") | ||
| 658 | - } | ||
| 659 | - out = out[:i] | ||
| 660 | - return strings.TrimSpace(out), nil | ||
| 661 | + Scheme: []string{"https", "http", "svn", "svn+ssh"}, | ||
| 662 | + PingCmd: "info -- {scheme}://{repo}", | ||
| 663 | } | ||
| 664 | |||
| 665 | // fossilRepoName is the name go get associates with a fossil repository. In the | ||
| 666 | @@ -543,24 +355,8 @@ var vcsFossil = &Cmd{ | ||
| 667 | {filename: "_FOSSIL_", isDir: false}, | ||
| 668 | }, | ||
| 669 | |||
| 670 | - CreateCmd: []string{"-go-internal-mkdir {dir} clone -- {repo} " + filepath.Join("{dir}", fossilRepoName), "-go-internal-cd {dir} open .fossil"}, | ||
| 671 | - DownloadCmd: []string{"up"}, | ||
| 672 | - | ||
| 673 | - TagCmd: []tagCmd{{"tag ls", `(.*)`}}, | ||
| 674 | - TagSyncCmd: []string{"up tag:{tag}"}, | ||
| 675 | - TagSyncDefault: []string{"up trunk"}, | ||
| 676 | - | ||
| 677 | - Scheme: []string{"https", "http"}, | ||
| 678 | - RemoteRepo: fossilRemoteRepo, | ||
| 679 | - Status: fossilStatus, | ||
| 680 | -} | ||
| 681 | - | ||
| 682 | -func fossilRemoteRepo(vcsFossil *Cmd, rootDir string) (remoteRepo string, err error) { | ||
| 683 | - out, err := vcsFossil.runOutput(rootDir, "remote-url") | ||
| 684 | - if err != nil { | ||
| 685 | - return "", err | ||
| 686 | - } | ||
| 687 | - return strings.TrimSpace(string(out)), nil | ||
| 688 | + Scheme: []string{"https", "http"}, | ||
| 689 | + Status: fossilStatus, | ||
| 690 | } | ||
| 691 | |||
| 692 | var errFossilInfo = errors.New("unable to parse output of fossil info") | ||
| 693 | @@ -661,7 +457,7 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([ | ||
| 694 | args[i] = expand(m, arg) | ||
| 695 | } | ||
| 696 | |||
| 697 | - if len(args) >= 2 && args[0] == "-go-internal-mkdir" { | ||
| 698 | + if len(args) >= 2 && args[0] == "--go-internal-mkdir" { | ||
| 699 | var err error | ||
| 700 | if filepath.IsAbs(args[1]) { | ||
| 701 | err = os.Mkdir(args[1], fs.ModePerm) | ||
| 702 | @@ -674,7 +470,7 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([ | ||
| 703 | args = args[2:] | ||
| 704 | } | ||
| 705 | |||
| 706 | - if len(args) >= 2 && args[0] == "-go-internal-cd" { | ||
| 707 | + if len(args) >= 2 && args[0] == "--go-internal-cd" { | ||
| 708 | if filepath.IsAbs(args[1]) { | ||
| 709 | dir = args[1] | ||
| 710 | } else { | ||
| 711 | @@ -735,99 +531,6 @@ func (v *Cmd) Ping(scheme, repo string) error { | ||
| 712 | return v.runVerboseOnly(dir, v.PingCmd, "scheme", scheme, "repo", repo) | ||
| 713 | } | ||
| 714 | |||
| 715 | -// Create creates a new copy of repo in dir. | ||
| 716 | -// The parent of dir must exist; dir must not. | ||
| 717 | -func (v *Cmd) Create(dir, repo string) error { | ||
| 718 | - release, err := base.AcquireNet() | ||
| 719 | - if err != nil { | ||
| 720 | - return err | ||
| 721 | - } | ||
| 722 | - defer release() | ||
| 723 | - | ||
| 724 | - for _, cmd := range v.CreateCmd { | ||
| 725 | - if err := v.run(filepath.Dir(dir), cmd, "dir", dir, "repo", repo); err != nil { | ||
| 726 | - return err | ||
| 727 | - } | ||
| 728 | - } | ||
| 729 | - return nil | ||
| 730 | -} | ||
| 731 | - | ||
| 732 | -// Download downloads any new changes for the repo in dir. | ||
| 733 | -func (v *Cmd) Download(dir string) error { | ||
| 734 | - release, err := base.AcquireNet() | ||
| 735 | - if err != nil { | ||
| 736 | - return err | ||
| 737 | - } | ||
| 738 | - defer release() | ||
| 739 | - | ||
| 740 | - for _, cmd := range v.DownloadCmd { | ||
| 741 | - if err := v.run(dir, cmd); err != nil { | ||
| 742 | - return err | ||
| 743 | - } | ||
| 744 | - } | ||
| 745 | - return nil | ||
| 746 | -} | ||
| 747 | - | ||
| 748 | -// Tags returns the list of available tags for the repo in dir. | ||
| 749 | -func (v *Cmd) Tags(dir string) ([]string, error) { | ||
| 750 | - var tags []string | ||
| 751 | - for _, tc := range v.TagCmd { | ||
| 752 | - out, err := v.runOutput(dir, tc.cmd) | ||
| 753 | - if err != nil { | ||
| 754 | - return nil, err | ||
| 755 | - } | ||
| 756 | - re := regexp.MustCompile(`(?m-s)` + tc.pattern) | ||
| 757 | - for _, m := range re.FindAllStringSubmatch(string(out), -1) { | ||
| 758 | - tags = append(tags, m[1]) | ||
| 759 | - } | ||
| 760 | - } | ||
| 761 | - return tags, nil | ||
| 762 | -} | ||
| 763 | - | ||
| 764 | -// TagSync syncs the repo in dir to the named tag, | ||
| 765 | -// which either is a tag returned by tags or is v.tagDefault. | ||
| 766 | -func (v *Cmd) TagSync(dir, tag string) error { | ||
| 767 | - if v.TagSyncCmd == nil { | ||
| 768 | - return nil | ||
| 769 | - } | ||
| 770 | - if tag != "" { | ||
| 771 | - for _, tc := range v.TagLookupCmd { | ||
| 772 | - out, err := v.runOutput(dir, tc.cmd, "tag", tag) | ||
| 773 | - if err != nil { | ||
| 774 | - return err | ||
| 775 | - } | ||
| 776 | - re := regexp.MustCompile(`(?m-s)` + tc.pattern) | ||
| 777 | - m := re.FindStringSubmatch(string(out)) | ||
| 778 | - if len(m) > 1 { | ||
| 779 | - tag = m[1] | ||
| 780 | - break | ||
| 781 | - } | ||
| 782 | - } | ||
| 783 | - } | ||
| 784 | - | ||
| 785 | - release, err := base.AcquireNet() | ||
| 786 | - if err != nil { | ||
| 787 | - return err | ||
| 788 | - } | ||
| 789 | - defer release() | ||
| 790 | - | ||
| 791 | - if tag == "" && v.TagSyncDefault != nil { | ||
| 792 | - for _, cmd := range v.TagSyncDefault { | ||
| 793 | - if err := v.run(dir, cmd); err != nil { | ||
| 794 | - return err | ||
| 795 | - } | ||
| 796 | - } | ||
| 797 | - return nil | ||
| 798 | - } | ||
| 799 | - | ||
| 800 | - for _, cmd := range v.TagSyncCmd { | ||
| 801 | - if err := v.run(dir, cmd, "tag", tag); err != nil { | ||
| 802 | - return err | ||
| 803 | - } | ||
| 804 | - } | ||
| 805 | - return nil | ||
| 806 | -} | ||
| 807 | - | ||
| 808 | // A vcsPath describes how to convert an import path into a | ||
| 809 | // version control system and repository name. | ||
| 810 | type vcsPath struct { | ||
| 811 | diff --git a/src/cmd/go/internal/workcmd/edit.go b/src/cmd/go/internal/workcmd/edit.go | ||
| 812 | index 8d975b0b3d..c1252cc95e 100644 | ||
| 813 | --- a/src/cmd/go/internal/workcmd/edit.go | ||
| 814 | +++ b/src/cmd/go/internal/workcmd/edit.go | ||
| 815 | @@ -242,7 +242,10 @@ func allowedVersionArg(arg string) bool { | ||
| 816 | // parsePathVersionOptional parses path[@version], using adj to | ||
| 817 | // describe any errors. | ||
| 818 | func parsePathVersionOptional(adj, arg string, allowDirPath bool) (path, version string, err error) { | ||
| 819 | - before, after, found := strings.Cut(arg, "@") | ||
| 820 | + before, after, found, err := modload.ParsePathVersion(arg) | ||
| 821 | + if err != nil { | ||
| 822 | + return "", "", err | ||
| 823 | + } | ||
| 824 | if !found { | ||
| 825 | path = arg | ||
| 826 | } else { | ||
| 827 | -- | ||
| 828 | 2.35.6 | ||
