cmd/release: build race detector, godoc, cover, and vet

Change-Id: Iec3edcfdadedee882866c7747e84bb119d5ab591
Reviewed-on: https://go-review.googlesource.com/3881
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Andrew Gerrand 2015-02-04 16:04:07 +00:00
Родитель 84aecb26fb
Коммит 319667fbcf
1 изменённых файлов: 193 добавлений и 45 удалений

Просмотреть файл

@ -13,7 +13,9 @@ import (
"io"
"log"
"os"
"path"
"path/filepath"
"strings"
"sync"
"time"
@ -25,23 +27,61 @@ import (
)
var (
revision = flag.String("rev", "", "Go revision to build")
rev = flag.String("rev", "", "Go revision to build")
toolsRev = flag.String("tools", "", "Tools revision to build")
project = flag.String("project", "symbolic-datum-552", "Google Cloud Project")
zone = flag.String("zone", "us-central1-a", "Compute Engine zone")
target = flag.String("target", "", "If specified, build specific target platform")
)
var builders = []string{
"darwin-386",
"darwin-amd64",
"freebsd-386",
"freebsd-amd64",
"linux-386",
"linux-amd64",
"windows-386",
"windows-amd64",
const timeout = time.Hour
type Build struct {
OS, Arch string
Race bool // Build race detector.
Static bool // Statically-link binaries.
Builder string // Key for dashboard.Builders.
}
const timeout = time.Hour
func (b *Build) String() string {
return fmt.Sprintf("%v-%v", b.OS, b.Arch)
}
var builds = []*Build{
{
OS: "linux",
Arch: "386",
Builder: "linux-amd64",
},
{
OS: "linux",
Arch: "amd64",
Race: true,
Static: true,
Builder: "linux-amd64",
},
{
OS: "freebsd",
Arch: "386",
Builder: "freebsd-386-gce101",
},
{
OS: "freebsd",
Arch: "amd64",
Race: true,
Builder: "freebsd-amd64-gce101",
},
}
const toolsRepo = "golang.org/x/tools"
var toolPaths = []string{
"golang.org/x/tools/cmd/cover",
"golang.org/x/tools/cmd/godoc",
"golang.org/x/tools/cmd/vet",
}
var preBuildCleanFiles = []string{
".gitattributes",
@ -58,31 +98,37 @@ var postBuildCleanFiles = []string{
func main() {
flag.Parse()
if *revision == "" {
if *rev == "" {
log.Fatal("must specify -rev flag")
}
if *toolsRev == "" {
log.Fatal("must specify -tools flag")
}
var wg sync.WaitGroup
for _, name := range builders {
b, ok := dashboard.Builders[name]
if !ok {
log.Printf("unknown builder %q", name)
for _, b := range builds {
b := b
if *target != "" && b.String() != *target {
continue
}
wg.Add(1)
go func() {
defer wg.Done()
if err := makeRelease(b); err != nil {
log.Printf("makeRelease(%q): %v", b.Name, err)
}
b.make() // error logged by make function
}()
}
// TODO(adg): show progress of running builders
wg.Wait()
}
func makeRelease(bc dashboard.BuildConfig) (err error) {
func (b *Build) make() (err error) {
bc, ok := dashboard.Builders[b.Builder]
if !ok {
return fmt.Errorf("unknown builder: %v", bc)
}
// Start VM
log.Printf("%v: Starting VM.", b)
keypair, err := buildlet.NewKeyPair()
if err != nil {
return err
@ -95,44 +141,80 @@ func makeRelease(bc dashboard.BuildConfig) (err error) {
DeleteIn: timeout,
Description: fmt.Sprintf("release buildlet for %s", os.Getenv("USER")),
OnInstanceRequested: func() {
log.Printf("%v: Sent create request. Waiting for operation.", instance)
log.Printf("%v: Sent create request. Waiting for operation.", b)
},
OnInstanceCreated: func() {
log.Printf("%v: Instance created.", instance)
log.Printf("%v: Instance created.", b)
},
})
if err != nil {
return err
}
log.Printf("%v: Instance up.", instance)
log.Printf("%v: Instance %v up.", b, instance)
defer func() {
log.Printf("%v: Destroying VM.", instance)
if err != nil {
log.Printf("%v: %v", b, err)
}
log.Printf("%v: Destroying VM.", b)
err := client.DestroyVM(projTokenSource(), *project, *zone, instance)
if err != nil {
log.Printf("%v: Destroying VM: %v", instance, err)
log.Printf("%v: Destroying VM: %v", b, err)
}
}()
// Push source to VM
const dir = "go"
tar := "https://go.googlesource.com/go/+archive/" + *revision + ".tar.gz"
if err := client.PutTarFromURL(tar, dir); err != nil {
work, err := client.WorkDir()
if err != nil {
return err
}
log.Printf("%v: Pushed source to VM.", instance)
if err := client.RemoveAll(preBuildCleanFiles...); err != nil {
const (
goDir = "go"
goPath = "gopath"
toolsDir = goPath + "/src/" + toolsRepo
)
// Push source to VM
log.Printf("%v: Pushing source to VM.", b)
tar := "https://go.googlesource.com/go/+archive/" + *rev + ".tar.gz"
if err := client.PutTarFromURL(tar, goDir); err != nil {
return err
}
log.Printf("%v: Cleaned repo (pre-build).", instance)
tar = "https://go.googlesource.com/tools/+archive/" + *toolsRev + ".tar.gz"
if err := client.PutTarFromURL(tar, toolsDir); err != nil {
return err
}
log.Printf("%v: Cleaning goroot (pre-build).", b)
if err := client.RemoveAll(addPrefix(goDir, preBuildCleanFiles)...); err != nil {
return err
}
// Set up build environment.
sep := "/"
if b.OS == "windows" {
sep = "\\"
}
env := []string{
"GOOS=" + b.OS,
"GOARCH=" + b.Arch,
"GOHOSTOS=" + b.OS,
"GOHOSTARCH=" + b.Arch,
"GOROOT_FINAL=" + bc.GorootFinal(),
"GOROOT=" + work + sep + goDir,
"GOPATH=" + work + sep + goPath,
}
if b.Static {
env = append(env, "GO_DISTFLAGS=-s")
}
// Execute build
log.Printf("%v: Building.", b)
out := new(bytes.Buffer)
mk := filepath.Join(dir, bc.MakeScript())
mk := filepath.Join(goDir, bc.MakeScript())
remoteErr, err := client.Exec(mk, buildlet.ExecOpts{
Output: out,
ExtraEnv: []string{"GOROOT_FINAL=" + bc.GorootFinal()},
ExtraEnv: env,
})
if err != nil {
return err
@ -141,27 +223,85 @@ func makeRelease(bc dashboard.BuildConfig) (err error) {
// TODO(adg): write log to file instead?
return fmt.Errorf("Build failed: %v\nOutput:\n%v", remoteErr, out)
}
log.Printf("%v: Build complete.", instance)
// TODO: build race-enabled tool chain
goCmd := path.Join(goDir, "bin/go")
if b.OS == "windows" {
goCmd += ".exe"
}
runGo := func(args ...string) error {
out := new(bytes.Buffer)
remoteErr, err := client.Exec(goCmd, buildlet.ExecOpts{
Output: out,
Args: args,
ExtraEnv: env,
})
if err != nil {
return err
}
if remoteErr != nil {
return fmt.Errorf("go %v: %v\n%s", strings.Join(args, " "), remoteErr, out)
}
return nil
}
// TODO: check out tools
// TODO: build godoc, vet, cover
if b.Race {
log.Printf("%v: Building race detector.", b)
// TODO: check out blog, add to misc
// TODO: check out tour, add to misc
// Because on release branches, go install -a std is a NOP,
// we have to resort to delete pkg/$GOOS_$GOARCH, install -race,
// and then reinstall std so that we're not left with a slower,
// race-enabled cmd/go, etc.
if err := client.RemoveAll(path.Join(goDir, "pkg", b.OS+"_"+b.Arch)); err != nil {
return err
}
if err := runGo("tool", "dist", "install", "runtime"); err != nil {
return err
}
if err := runGo("install", "-race", "std"); err != nil {
return err
}
if err := runGo("install", "std"); err != nil {
return err
}
// Re-building go command leaves old versions of go.exe as go.exe~ on windows.
// See (*builder).copyFile in $GOROOT/src/cmd/go/build.go for details.
// Remove it manually.
if b.OS == "windows" {
if err := client.RemoveAll(goCmd + "~"); err != nil {
return err
}
}
}
if err := client.RemoveAll(postBuildCleanFiles...); err != nil {
for _, p := range toolPaths {
log.Printf("%v: Building %v.", b, p)
if err := runGo("install", p); err != nil {
return err
}
}
// TODO(adg): check out blog, add to misc
// TODO(adg): check out tour, add to misc
log.Printf("%v: Cleaning goroot (post-build).", b)
// Need to delete everything except the final "go" directory,
// as we make the tarball relative to workdir.
cleanFiles := append(addPrefix(goDir, postBuildCleanFiles), goPath)
if err := client.RemoveAll(cleanFiles...); err != nil {
return err
}
log.Printf("%v: Cleaned repo (post-build).", instance)
// TODO(adg): build msi files on windows and pkg files on osx
// Download tarball
tgz, err := client.GetTar(dir)
log.Printf("%v: Downloading tarball", b)
tgz, err := client.GetTar(".")
if err != nil {
return err
}
filename := "go-version-" + bc.Name + ".tar.gz"
// TODO(adg): deduce actual version
version := "VERSION"
filename := "go." + version + "." + b.String() + ".tar.gz"
f, err := os.Create(filename)
if err != nil {
return err
@ -173,7 +313,7 @@ func makeRelease(bc dashboard.BuildConfig) (err error) {
if err := f.Close(); err != nil {
return err
}
log.Printf("%v: Wrote %q.", instance, filename)
log.Printf("%v: Wrote %q.", b, filename)
return nil
}
@ -194,3 +334,11 @@ func randHex(n int) string {
}
return fmt.Sprintf("%x", buf)
}
func addPrefix(prefix string, in []string) []string {
var out []string
for _, s := range in {
out = append(out, path.Join(prefix, s))
}
return out
}