cmd/go: stamp Fossil VCS status into binaries
For #37475
Change-Id: I09fa1344051088ce37727176d9ec6b38891d1a9f
Reviewed-on: https://go-review.googlesource.com/c/go/+/357955
Trust: Ian Lance Taylor <iant@golang.org>
Trust: Bryan C. Mills <bcmills@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go
index 990e1d4..6d2996e 100644
--- a/src/cmd/go/internal/vcs/vcs.go
+++ b/src/cmd/go/internal/vcs/vcs.go
@@ -455,6 +455,7 @@
Scheme: []string{"https", "http"},
RemoteRepo: fossilRemoteRepo,
+ Status: fossilStatus,
}
func fossilRemoteRepo(vcsFossil *Cmd, rootDir string) (remoteRepo string, err error) {
@@ -465,6 +466,60 @@
return strings.TrimSpace(string(out)), nil
}
+var errFossilInfo = errors.New("unable to parse output of fossil info")
+
+func fossilStatus(vcsFossil *Cmd, rootDir string) (Status, error) {
+ outb, err := vcsFossil.runOutputVerboseOnly(rootDir, "info")
+ if err != nil {
+ return Status{}, err
+ }
+ out := string(outb)
+
+ // Expect:
+ // ...
+ // checkout: 91ed71f22c77be0c3e250920f47bfd4e1f9024d2 2021-09-21 12:00:00 UTC
+ // ...
+
+ // Extract revision and commit time.
+ // Ensure line ends with UTC (known timezone offset).
+ const prefix = "\ncheckout:"
+ const suffix = " UTC"
+ i := strings.Index(out, prefix)
+ if i < 0 {
+ return Status{}, errFossilInfo
+ }
+ checkout := out[i+len(prefix):]
+ i = strings.Index(checkout, suffix)
+ if i < 0 {
+ return Status{}, errFossilInfo
+ }
+ checkout = strings.TrimSpace(checkout[:i])
+
+ i = strings.IndexByte(checkout, ' ')
+ if i < 0 {
+ return Status{}, errFossilInfo
+ }
+ rev := checkout[:i]
+
+ commitTime, err := time.ParseInLocation("2006-01-02 15:04:05", checkout[i+1:], time.UTC)
+ if err != nil {
+ return Status{}, fmt.Errorf("%v: %v", errFossilInfo, err)
+ }
+
+ // Also look for untracked changes.
+ outb, err = vcsFossil.runOutputVerboseOnly(rootDir, "changes --differ")
+ if err != nil {
+ return Status{}, err
+ }
+ uncommitted := len(outb) > 0
+
+ return Status{
+ Revision: rev,
+ CommitTime: commitTime,
+ Uncommitted: uncommitted,
+ }, nil
+}
+
func (v *Cmd) String() string {
return v.Name
}
diff --git a/src/cmd/go/testdata/script/version_buildvcs_fossil.txt b/src/cmd/go/testdata/script/version_buildvcs_fossil.txt
new file mode 100644
index 0000000..3a4bde8
--- /dev/null
+++ b/src/cmd/go/testdata/script/version_buildvcs_fossil.txt
@@ -0,0 +1,90 @@
+# This test checks that VCS information is stamped into Go binaries by default,
+# controlled with -buildvcs. This test focuses on Fossil specifics.
+# The Git test covers common functionality.
+
+# "fossil" is the Fossil file server on Plan 9.
+[plan9] skip
+[!exec:fossil] skip
+[short] skip
+env GOBIN=$WORK/gopath/bin
+env oldpath=$PATH
+env HOME=$WORK
+env USER=gopher
+[!windows] env fslckout=.fslckout
+[windows] env fslckout=_FOSSIL_
+exec pwd
+exec fossil init repo.fossil
+cd repo/a
+
+# If there's no local repository, there's no VCS info.
+go install
+go version -m $GOBIN/a$GOEXE
+! stdout fossilrevision
+rm $GOBIN/a$GOEXE
+
+# If there is a repository, but it can't be used for some reason,
+# there should be an error. It should hint about -buildvcs=false.
+cd ..
+mkdir $fslckout
+env PATH=$WORK${/}fakebin${:}$oldpath
+chmod 0755 $WORK/fakebin/fossil
+! exec fossil help
+cd a
+! go install
+stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$'
+rm $GOBIN/a$GOEXE
+cd ..
+env PATH=$oldpath
+rm $fslckout
+
+# Revision and commit time are tagged for repositories with commits.
+exec fossil open ../repo.fossil -f
+exec fossil add a README
+exec fossil commit -m 'initial commit'
+cd a
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tfossilrevision\t'
+stdout '^\tbuild\tfossilcommittime\t'
+stdout '^\tbuild\tfossiluncommitted\tfalse$'
+rm $GOBIN/a$GOEXE
+
+# Building with -buildvcs=false suppresses the info.
+go install -buildvcs=false
+go version -m $GOBIN/a$GOEXE
+! stdout fossilrevision
+rm $GOBIN/a$GOEXE
+
+# An untracked file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt .
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tfossiluncommitted\ttrue$'
+rm empty.txt
+rm $GOBIN/a$GOEXE
+
+# An edited file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt ../README
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tfossiluncommitted\ttrue$'
+exec fossil revert ../README
+rm $GOBIN/a$GOEXE
+
+-- $WORK/fakebin/fossil --
+#!/bin/sh
+exit 1
+-- $WORK/fakebin/fossil.bat --
+exit 1
+-- repo/README --
+Far out in the uncharted backwaters of the unfashionable end of the western
+spiral arm of the Galaxy lies a small, unregarded yellow sun.
+-- repo/a/go.mod --
+module example.com/a
+
+go 1.18
+-- repo/a/a.go --
+package main
+
+func main() {}
+-- outside/empty.txt --