mirror of
https://github.com/golang/go
synced 2024-11-18 00:54:45 -07:00
cmd/go: stamp VCS commit time into binaries
Only Git and Mercurial are supported for now. This CL also: - Skips tagging "revision" and "committime" for empty repositories. - Stores the full Mercurial changeset ID instead of the short form. Fixes #37475 Change-Id: I62ab7a986d1ddb2a0e7166a6404b5aa80c2ee387 Reviewed-on: https://go-review.googlesource.com/c/go/+/356251 Reviewed-by: Bryan C. Mills <bcmills@google.com> Trust: Bryan C. Mills <bcmills@google.com> Trust: Michael Matloob <matloob@golang.org> Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
1b2362bb83
commit
76cef81bcf
@ -25,6 +25,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@ -2364,10 +2365,14 @@ func (p *Package) setBuildInfo() {
|
|||||||
setVCSError(err)
|
setVCSError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
info.Settings = append(info.Settings, []debug.BuildSetting{
|
if st.Revision != "" {
|
||||||
{Key: vcsCmd.Cmd + "revision", Value: st.Revision},
|
appendSetting(vcsCmd.Cmd+"revision", st.Revision)
|
||||||
{Key: vcsCmd.Cmd + "uncommitted", Value: strconv.FormatBool(st.Uncommitted)},
|
}
|
||||||
}...)
|
if !st.CommitTime.IsZero() {
|
||||||
|
stamp := st.CommitTime.UTC().Format(time.RFC3339Nano)
|
||||||
|
appendSetting(vcsCmd.Cmd+"committime", stamp)
|
||||||
|
}
|
||||||
|
appendSetting(vcsCmd.Cmd+"uncommitted", strconv.FormatBool(st.Uncommitted))
|
||||||
}
|
}
|
||||||
|
|
||||||
text, err := info.MarshalText()
|
text, err := info.MarshalText()
|
||||||
|
@ -18,8 +18,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
@ -54,8 +56,9 @@ type Cmd struct {
|
|||||||
|
|
||||||
// Status is the current state of a local repository.
|
// Status is the current state of a local repository.
|
||||||
type Status struct {
|
type Status struct {
|
||||||
Revision string
|
Revision string // Optional.
|
||||||
Uncommitted bool
|
CommitTime time.Time // Optional.
|
||||||
|
Uncommitted bool // Required.
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultSecureScheme = map[string]bool{
|
var defaultSecureScheme = map[string]bool{
|
||||||
@ -159,24 +162,52 @@ func hgRemoteRepo(vcsHg *Cmd, rootDir string) (remoteRepo string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) {
|
func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) {
|
||||||
out, err := vcsHg.runOutputVerboseOnly(rootDir, "identify -i")
|
// Output changeset ID and seconds since epoch.
|
||||||
|
out, err := vcsHg.runOutputVerboseOnly(rootDir, `log -l1 -T {node}:{date(date,"%s")}`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Status{}, err
|
return Status{}, err
|
||||||
}
|
}
|
||||||
rev := strings.TrimSpace(string(out))
|
|
||||||
uncommitted := strings.HasSuffix(rev, "+")
|
// Successful execution without output indicates an empty repo (no commits).
|
||||||
if uncommitted {
|
var rev string
|
||||||
// "+" means a tracked file is edited.
|
var commitTime time.Time
|
||||||
rev = rev[:len(rev)-len("+")]
|
if len(out) > 0 {
|
||||||
} else {
|
rev, commitTime, err = parseRevTime(out)
|
||||||
// Also look for untracked files.
|
|
||||||
out, err = vcsHg.runOutputVerboseOnly(rootDir, "status -u")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Status{}, err
|
return Status{}, err
|
||||||
}
|
}
|
||||||
uncommitted = len(out) > 0
|
|
||||||
}
|
}
|
||||||
return Status{Revision: rev, Uncommitted: uncommitted}, nil
|
|
||||||
|
// Also look for untracked files.
|
||||||
|
out, err = vcsHg.runOutputVerboseOnly(rootDir, "status")
|
||||||
|
if err != nil {
|
||||||
|
return Status{}, err
|
||||||
|
}
|
||||||
|
uncommitted := len(out) > 0
|
||||||
|
|
||||||
|
return Status{
|
||||||
|
Revision: rev,
|
||||||
|
CommitTime: commitTime,
|
||||||
|
Uncommitted: uncommitted,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseRevTime parses commit details in "revision:seconds" format.
|
||||||
|
func parseRevTime(out []byte) (string, time.Time, error) {
|
||||||
|
buf := string(bytes.TrimSpace(out))
|
||||||
|
|
||||||
|
i := strings.IndexByte(buf, ':')
|
||||||
|
if i < 1 {
|
||||||
|
return "", time.Time{}, errors.New("unrecognized VCS tool output")
|
||||||
|
}
|
||||||
|
rev := buf[:i]
|
||||||
|
|
||||||
|
secs, err := strconv.ParseInt(string(buf[i+1:]), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return "", time.Time{}, fmt.Errorf("unrecognized VCS tool output: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rev, time.Unix(secs, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// vcsGit describes how to use Git.
|
// vcsGit describes how to use Git.
|
||||||
@ -263,18 +294,33 @@ func gitRemoteRepo(vcsGit *Cmd, rootDir string) (remoteRepo string, err error) {
|
|||||||
return "", errParse
|
return "", errParse
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitStatus(cmd *Cmd, repoDir string) (Status, error) {
|
func gitStatus(vcsGit *Cmd, rootDir string) (Status, error) {
|
||||||
out, err := cmd.runOutputVerboseOnly(repoDir, "rev-parse HEAD")
|
out, err := vcsGit.runOutputVerboseOnly(rootDir, "status --porcelain")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Status{}, err
|
return Status{}, err
|
||||||
}
|
}
|
||||||
rev := string(bytes.TrimSpace(out))
|
uncommitted := len(out) > 0
|
||||||
out, err = cmd.runOutputVerboseOnly(repoDir, "status --porcelain")
|
|
||||||
if err != nil {
|
// "git status" works for empty repositories, but "git show" does not.
|
||||||
|
// Assume there are no commits in the repo when "git show" fails with
|
||||||
|
// uncommitted files and skip tagging revision / committime.
|
||||||
|
var rev string
|
||||||
|
var commitTime time.Time
|
||||||
|
out, err = vcsGit.runOutputVerboseOnly(rootDir, "show -s --format=%H:%ct")
|
||||||
|
if err != nil && !uncommitted {
|
||||||
return Status{}, err
|
return Status{}, err
|
||||||
|
} else if err == nil {
|
||||||
|
rev, commitTime, err = parseRevTime(out)
|
||||||
|
if err != nil {
|
||||||
|
return Status{}, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
uncommitted := len(out) != 0
|
|
||||||
return Status{Revision: rev, Uncommitted: uncommitted}, nil
|
return Status{
|
||||||
|
Revision: rev,
|
||||||
|
CommitTime: commitTime,
|
||||||
|
Uncommitted: uncommitted,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// vcsBzr describes how to use Bazaar.
|
// vcsBzr describes how to use Bazaar.
|
||||||
|
@ -28,16 +28,25 @@ cd ..
|
|||||||
env PATH=$oldpath
|
env PATH=$oldpath
|
||||||
rm .git
|
rm .git
|
||||||
|
|
||||||
# If there is a repository in a parent directory, there should be VCS info.
|
# If there is an empty repository in a parent directory, only "uncommitted" is tagged.
|
||||||
exec git init
|
exec git init
|
||||||
exec git config user.email gopher@golang.org
|
exec git config user.email gopher@golang.org
|
||||||
exec git config user.name 'J.R. Gopher'
|
exec git config user.name 'J.R. Gopher'
|
||||||
exec git add -A
|
|
||||||
exec git commit -m 'initial commit'
|
|
||||||
cd a
|
cd a
|
||||||
go install
|
go install
|
||||||
go version -m $GOBIN/a$GOEXE
|
go version -m $GOBIN/a$GOEXE
|
||||||
|
! stdout gitrevision
|
||||||
|
! stdout gitcommittime
|
||||||
|
stdout '^\tbuild\tgituncommitted\ttrue$'
|
||||||
|
rm $GOBIN/a$GOEXE
|
||||||
|
|
||||||
|
# Revision and commit time are tagged for repositories with commits.
|
||||||
|
exec git add -A
|
||||||
|
exec git commit -m 'initial commit'
|
||||||
|
go install
|
||||||
|
go version -m $GOBIN/a$GOEXE
|
||||||
stdout '^\tbuild\tgitrevision\t'
|
stdout '^\tbuild\tgitrevision\t'
|
||||||
|
stdout '^\tbuild\tgitcommittime\t'
|
||||||
stdout '^\tbuild\tgituncommitted\tfalse$'
|
stdout '^\tbuild\tgituncommitted\tfalse$'
|
||||||
rm $GOBIN/a$GOEXE
|
rm $GOBIN/a$GOEXE
|
||||||
|
|
||||||
|
@ -29,14 +29,24 @@ cd ..
|
|||||||
env PATH=$oldpath
|
env PATH=$oldpath
|
||||||
rm .hg
|
rm .hg
|
||||||
|
|
||||||
# If there is a repository in a parent directory, there should be VCS info.
|
# If there is an empty repository in a parent directory, only "uncommitted" is tagged.
|
||||||
exec hg init
|
exec hg init
|
||||||
|
cd a
|
||||||
|
go install
|
||||||
|
go version -m $GOBIN/a$GOEXE
|
||||||
|
! stdout hgrevision
|
||||||
|
! stdout hgcommittime
|
||||||
|
stdout '^\tbuild\thguncommitted\ttrue$'
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Revision and commit time are tagged for repositories with commits.
|
||||||
exec hg add a README
|
exec hg add a README
|
||||||
exec hg commit -m 'initial commit'
|
exec hg commit -m 'initial commit'
|
||||||
cd a
|
cd a
|
||||||
go install
|
go install
|
||||||
go version -m $GOBIN/a$GOEXE
|
go version -m $GOBIN/a$GOEXE
|
||||||
stdout '^\tbuild\thgrevision\t'
|
stdout '^\tbuild\thgrevision\t'
|
||||||
|
stdout '^\tbuild\thgcommittime\t'
|
||||||
stdout '^\tbuild\thguncommitted\tfalse$'
|
stdout '^\tbuild\thguncommitted\tfalse$'
|
||||||
rm $GOBIN/a$GOEXE
|
rm $GOBIN/a$GOEXE
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user