build: improve debian packaging

This commit tweaks the debian packaging tool:

* All build environment metadata can now be overriden on the command
  line. This allows testing the CI build behaviour locally.
* -unstable packages now actually contain the binaries (oops)
* packages use Go 1.7 to build
* archiving is skipped for PR builds
This commit is contained in:
Felix Lange 2016-09-30 22:03:08 +02:00
parent d8715fba1a
commit 4f7627972e
9 changed files with 250 additions and 132 deletions

@ -27,7 +27,7 @@ matrix:
- debhelper - debhelper
- dput - dput
script: script:
- go run build/ci.go travis-debsrc - go run build/ci.go debsrc -signer "Felix Lange (Geth CI Testing Key) <fjl@twurst.com>" -upload ppa:lp-fjl/geth-ci-testing
install: install:
- go get golang.org/x/tools/cmd/cover - go get golang.org/x/tools/cmd/cover

@ -42,12 +42,12 @@ geth-linux: geth-linux-386 geth-linux-amd64 geth-linux-arm geth-linux-mips64 get
@ls -ld $(GOBIN)/geth-linux-* @ls -ld $(GOBIN)/geth-linux-*
geth-linux-386: geth-linux-386:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/386 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/386 -v ./cmd/geth
@echo "Linux 386 cross compilation done:" @echo "Linux 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep 386 @ls -ld $(GOBIN)/geth-linux-* | grep 386
geth-linux-amd64: geth-linux-amd64:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/amd64 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/amd64 -v ./cmd/geth
@echo "Linux amd64 cross compilation done:" @echo "Linux amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep amd64 @ls -ld $(GOBIN)/geth-linux-* | grep amd64
@ -56,32 +56,32 @@ geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-ar
@ls -ld $(GOBIN)/geth-linux-* | grep arm @ls -ld $(GOBIN)/geth-linux-* | grep arm
geth-linux-arm-5: geth-linux-arm-5:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-5 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-5 -v ./cmd/geth
@echo "Linux ARMv5 cross compilation done:" @echo "Linux ARMv5 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-5 @ls -ld $(GOBIN)/geth-linux-* | grep arm-5
geth-linux-arm-6: geth-linux-arm-6:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-6 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-6 -v ./cmd/geth
@echo "Linux ARMv6 cross compilation done:" @echo "Linux ARMv6 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-6 @ls -ld $(GOBIN)/geth-linux-* | grep arm-6
geth-linux-arm-7: geth-linux-arm-7:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-7 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-7 -v ./cmd/geth
@echo "Linux ARMv7 cross compilation done:" @echo "Linux ARMv7 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-7 @ls -ld $(GOBIN)/geth-linux-* | grep arm-7
geth-linux-arm64: geth-linux-arm64:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm64 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm64 -v ./cmd/geth
@echo "Linux ARM64 cross compilation done:" @echo "Linux ARM64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm64 @ls -ld $(GOBIN)/geth-linux-* | grep arm64
geth-linux-mips64: geth-linux-mips64:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/mips64 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/mips64 -v ./cmd/geth
@echo "Linux MIPS64 cross compilation done:" @echo "Linux MIPS64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips64 @ls -ld $(GOBIN)/geth-linux-* | grep mips64
geth-linux-mips64le: geth-linux-mips64le:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/mips64le -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/mips64le -v ./cmd/geth
@echo "Linux MIPS64le cross compilation done:" @echo "Linux MIPS64le cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips64le @ls -ld $(GOBIN)/geth-linux-* | grep mips64le
@ -90,12 +90,12 @@ geth-darwin: geth-darwin-386 geth-darwin-amd64
@ls -ld $(GOBIN)/geth-darwin-* @ls -ld $(GOBIN)/geth-darwin-*
geth-darwin-386: geth-darwin-386:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=darwin/386 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=darwin/386 -v ./cmd/geth
@echo "Darwin 386 cross compilation done:" @echo "Darwin 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-* | grep 386 @ls -ld $(GOBIN)/geth-darwin-* | grep 386
geth-darwin-amd64: geth-darwin-amd64:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=darwin/amd64 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=darwin/amd64 -v ./cmd/geth
@echo "Darwin amd64 cross compilation done:" @echo "Darwin amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-* | grep amd64 @ls -ld $(GOBIN)/geth-darwin-* | grep amd64
@ -104,21 +104,21 @@ geth-windows: geth-windows-386 geth-windows-amd64
@ls -ld $(GOBIN)/geth-windows-* @ls -ld $(GOBIN)/geth-windows-*
geth-windows-386: geth-windows-386:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=windows/386 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=windows/386 -v ./cmd/geth
@echo "Windows 386 cross compilation done:" @echo "Windows 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep 386 @ls -ld $(GOBIN)/geth-windows-* | grep 386
geth-windows-amd64: geth-windows-amd64:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=windows/amd64 -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=windows/amd64 -v ./cmd/geth
@echo "Windows amd64 cross compilation done:" @echo "Windows amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep amd64 @ls -ld $(GOBIN)/geth-windows-* | grep amd64
geth-android: geth-android:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=android-21/aar -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=android-21/aar -v ./cmd/geth
@echo "Android cross compilation done:" @echo "Android cross compilation done:"
@ls -ld $(GOBIN)/geth-android-* @ls -ld $(GOBIN)/geth-android-*
geth-ios: geth-ios:
build/env.sh go run build/ci.go xgo --go=$(GO) --dest=$(GOBIN) --targets=ios-7.0/framework -v ./cmd/geth build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=ios-7.0/framework -v ./cmd/geth
@echo "iOS framework cross compilation done:" @echo "iOS framework cross compilation done:"
@ls -ld $(GOBIN)/geth-ios-* @ls -ld $(GOBIN)/geth-ios-*

@ -1,5 +1,4 @@
Debian Packaging # Debian Packaging
----------------
Tagged releases and develop branch commits are available as installable Debian packages Tagged releases and develop branch commits are available as installable Debian packages
for Ubuntu. Packages are built for the all Ubuntu versions which are supported by for Ubuntu. Packages are built for the all Ubuntu versions which are supported by
@ -8,6 +7,7 @@ Canonical:
- Trusty Tahr (14.04 LTS) - Trusty Tahr (14.04 LTS)
- Wily Werewolf (15.10) - Wily Werewolf (15.10)
- Xenial Xerus (16.04 LTS) - Xenial Xerus (16.04 LTS)
- Yakkety Yak (16.10)
Packages of develop branch commits have suffix -unstable and cannot be installed alongside Packages of develop branch commits have suffix -unstable and cannot be installed alongside
the stable version. Switching between release streams requires user intervention. the stable version. Switching between release streams requires user intervention.
@ -21,6 +21,29 @@ variable which Travis CI makes available to certain builds.
We want to build go-ethereum with the most recent version of Go, irrespective of the Go We want to build go-ethereum with the most recent version of Go, irrespective of the Go
version that is available in the main Ubuntu repository. In order to make this possible, version that is available in the main Ubuntu repository. In order to make this possible,
our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on
golang-1.6, which is co-installable alongside the regular golang package. PPA dependencies golang-1.7, which is co-installable alongside the regular golang package. PPA dependencies
can be edited at https://launchpad.net/%7Elp-fjl/+archive/ubuntu/geth-ci-testing/+edit-dependencies can be edited at https://launchpad.net/%7Elp-fjl/+archive/ubuntu/geth-ci-testing/+edit-dependencies
## Building Packages Locally (for testing)
You need to run Ubuntu to do test packaging.
Add the gophers PPA and install Go 1.7 and Debian packaging tools:
$ sudo apt-add-repository ppa:gophers/ubuntu/archive
$ sudo apt-get update
$ sudo apt-get install build-essential golang-1.7 devscripts debhelper
Create the source packages:
$ go run build/ci.go debsrc -workdir dist
Then go into the source package directory for your running distribution and build the package:
$ cd dist/ethereum-unstable-1.5.0+xenial
$ dpkg-buildpackage
Built packages are placed in the dist/ directory.
$ cd ..
$ dpkg-deb -c geth-unstable_1.5.0+xenial_amd64.deb

@ -120,8 +120,6 @@ func main() {
doArchive(os.Args[2:]) doArchive(os.Args[2:])
case "debsrc": case "debsrc":
doDebianSource(os.Args[2:]) doDebianSource(os.Args[2:])
case "travis-debsrc":
doTravisDebianSource(os.Args[2:])
case "xgo": case "xgo":
doXgo(os.Args[2:]) doXgo(os.Args[2:])
default: default:
@ -132,8 +130,8 @@ func main() {
// Compiling // Compiling
func doInstall(cmdline []string) { func doInstall(cmdline []string) {
commitHash := flag.String("gitcommit", "", "Git commit hash embedded into binary.")
flag.CommandLine.Parse(cmdline) flag.CommandLine.Parse(cmdline)
env := build.Env()
// Check Go version. People regularly open issues about compilation // Check Go version. People regularly open issues about compilation
// failure with outdated Go. This should save them the trouble. // failure with outdated Go. This should save them the trouble.
@ -150,13 +148,17 @@ func doInstall(cmdline []string) {
packages = flag.Args() packages = flag.Args()
} }
goinstall := goTool("install", makeBuildFlags(*commitHash)...) goinstall := goTool("install", buildFlags(env)...)
goinstall.Args = append(goinstall.Args, "-v") goinstall.Args = append(goinstall.Args, "-v")
goinstall.Args = append(goinstall.Args, packages...) goinstall.Args = append(goinstall.Args, packages...)
build.MustRun(goinstall) build.MustRun(goinstall)
} }
func makeBuildFlags(commitHash string) (flags []string) { func buildFlags(env build.Environment) (flags []string) {
if os.Getenv("GO_OPENCL") != "" {
flags = append(flags, "-tags", "opencl")
}
// Since Go 1.5, the separator char for link time assignments // Since Go 1.5, the separator char for link time assignments
// is '=' and using ' ' prints a warning. However, Go < 1.5 does // is '=' and using ' ' prints a warning. However, Go < 1.5 does
// not support using '='. // not support using '='.
@ -164,26 +166,9 @@ func makeBuildFlags(commitHash string) (flags []string) {
if runtime.Version() > "go1.5" || strings.Contains(runtime.Version(), "devel") { if runtime.Version() > "go1.5" || strings.Contains(runtime.Version(), "devel") {
sep = "=" sep = "="
} }
// Set gitCommit constant via link-time assignment.
if os.Getenv("GO_OPENCL") != "" { if env.Commit != "" {
flags = append(flags, "-tags", "opencl") flags = append(flags, "-ldflags", "-X main.gitCommit"+sep+env.Commit)
}
// Set gitCommit constant via link-time assignment. If this is a git checkout, we can
// just get the current commit hash through git. Otherwise we fall back to the hash
// that was passed as -gitcommit.
//
// -gitcommit is required for Debian package builds. The source package doesn't
// contain .git but we still want to embed the commit hash into the packaged binary.
// The hash is rendered into the debian/rules build script when the source package is
// created.
if _, err := os.Stat(filepath.Join(".git", "HEAD")); !os.IsNotExist(err) {
if c := build.GitCommit(); c != "" {
commitHash = c
}
}
if commitHash != "" {
flags = append(flags, "-ldflags", "-X main.gitCommit"+sep+commitHash)
} }
return flags return flags
} }
@ -253,7 +238,11 @@ func doArchive(cmdline []string) {
default: default:
log.Fatal("unknown archive type: ", atype) log.Fatal("unknown archive type: ", atype)
} }
base := makeArchiveBasename()
env := build.Env()
maybeSkipArchive(env)
base := archiveBasename(env)
if err := build.WriteArchive("geth-"+base, ext, gethArchiveFiles); err != nil { if err := build.WriteArchive("geth-"+base, ext, gethArchiveFiles); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -262,36 +251,41 @@ func doArchive(cmdline []string) {
} }
} }
func makeArchiveBasename() string { func archiveBasename(env build.Environment) string {
// date := time.Now().UTC().Format("200601021504") // date := time.Now().UTC().Format("200601021504")
platform := runtime.GOOS + "-" + runtime.GOARCH platform := runtime.GOOS + "-" + runtime.GOARCH
archive := platform + "-" + build.VERSION() archive := platform + "-" + build.VERSION()
if commit := build.GitCommit(); commit != "" { if env.Commit != "" {
archive += "-" + commit[:8] archive += "-" + env.Commit[:8]
} }
return archive return archive
} }
// skips archiving for some build configurations.
func maybeSkipArchive(env build.Environment) {
if env.IsPullRequest {
log.Printf("skipping because this is a PR build")
os.Exit(0)
}
if env.Branch != "develop" && !strings.HasPrefix(env.Tag, "v1.") {
log.Printf("skipping because branch %q, tag %q is not on the whitelist", env.Branch, env.Tag)
os.Exit(0)
}
}
// Debian Packaging // Debian Packaging
// CLI entry point for Travis CI. func doDebianSource(cmdline []string) {
func doTravisDebianSource(cmdline []string) { var (
signer = flag.String("signer", "", `Signing key name, also used as package author`)
upload = flag.String("upload", "", `Where to upload the source package (usually "ppa:ethereum/ethereum")`)
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
now = time.Now()
)
flag.CommandLine.Parse(cmdline) flag.CommandLine.Parse(cmdline)
*workdir = makeWorkdir(*workdir)
// Package only whitelisted branches. env := build.Env()
switch { maybeSkipArchive(env)
case os.Getenv("TRAVIS_REPO_SLUG") != "ethereum/go-ethereum":
log.Printf("skipping because this is a fork build")
return
case os.Getenv("TRAVIS_PULL_REQUEST") != "false":
log.Printf("skipping because this is a PR build")
return
case os.Getenv("TRAVIS_BRANCH") != "develop" && !strings.HasPrefix(os.Getenv("TRAVIS_TAG"), "v1."):
log.Printf("skipping because branch %q tag %q is not on the whitelist",
os.Getenv("TRAVIS_BRANCH"),
os.Getenv("TRAVIS_TAG"))
return
}
// Import the signing key. // Import the signing key.
if b64key := os.Getenv("PPA_SIGNING_KEY"); b64key != "" { if b64key := os.Getenv("PPA_SIGNING_KEY"); b64key != "" {
@ -304,46 +298,16 @@ func doTravisDebianSource(cmdline []string) {
build.MustRun(gpg) build.MustRun(gpg)
} }
// Assign unstable status to non-tag builds. // Create the packages.
unstable := "true"
if os.Getenv("TRAVIS_BRANCH") != "develop" && os.Getenv("TRAVIS_TAG") != "" {
unstable = "false"
}
doDebianSource([]string{
"-signer", "Felix Lange (Geth CI Testing Key) <fjl@twurst.com>",
"-buildnum", os.Getenv("TRAVIS_BUILD_NUMBER"),
"-upload", "ppa:lp-fjl/geth-ci-testing",
"-unstable", unstable,
})
}
// CLI entry point for doing packaging locally.
func doDebianSource(cmdline []string) {
var (
signer = flag.String("signer", "", `Signing key name, also used as package author`)
upload = flag.String("upload", "", `Where to upload the source package (usually "ppa:ethereum/ethereum")`)
buildnum = flag.String("buildnum", "", `Build number (included in version)`)
unstable = flag.Bool("unstable", false, `Use package name suffix "-unstable"`)
now = time.Now()
)
flag.CommandLine.Parse(cmdline)
// Create the debian worktree in /tmp.
tmpdir, err := ioutil.TempDir("", "eth-deb-build-")
if err != nil {
log.Fatal(err)
}
for _, distro := range debDistros { for _, distro := range debDistros {
meta := newDebMetadata(distro, *signer, *buildnum, *unstable, now) meta := newDebMetadata(distro, *signer, env, now)
pkgdir := stageDebianSource(tmpdir, meta) pkgdir := stageDebianSource(*workdir, meta)
debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc") debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc")
debuild.Dir = pkgdir debuild.Dir = pkgdir
build.MustRun(debuild) build.MustRun(debuild)
changes := fmt.Sprintf("%s_%s_source.changes", meta.Name(), meta.VersionString()) changes := fmt.Sprintf("%s_%s_source.changes", meta.Name(), meta.VersionString())
changes = filepath.Join(tmpdir, changes) changes = filepath.Join(*workdir, changes)
if *signer != "" { if *signer != "" {
build.MustRunCommand("debsign", changes) build.MustRunCommand("debsign", changes)
} }
@ -353,35 +317,53 @@ func doDebianSource(cmdline []string) {
} }
} }
type debExecutable struct { func makeWorkdir(wdflag string) string {
Name, Description string var err error
if wdflag != "" {
err = os.MkdirAll(wdflag, 0744)
} else {
wdflag, err = ioutil.TempDir("", "eth-deb-build-")
}
if err != nil {
log.Fatal(err)
}
return wdflag
}
func isUnstableBuild(env build.Environment) bool {
if env.Branch != "develop" && env.Tag != "" {
return false
}
return true
} }
type debMetadata struct { type debMetadata struct {
Env build.Environment
// go-ethereum version being built. Note that this // go-ethereum version being built. Note that this
// is not the debian package version. The package version // is not the debian package version. The package version
// is constructed by VersionString. // is constructed by VersionString.
Version string Version string
Author string // "name <email>", also selects signing key Author string // "name <email>", also selects signing key
Buildnum string // build number Distro, Time string
Distro, Commit, Time string Executables []debExecutable
Executables []debExecutable
Unstable bool
} }
func newDebMetadata(distro, author, buildnum string, unstable bool, t time.Time) debMetadata { type debExecutable struct {
Name, Description string
}
func newDebMetadata(distro, author string, env build.Environment, t time.Time) debMetadata {
if author == "" { if author == "" {
// No signing key, use default author. // No signing key, use default author.
author = "Ethereum Builds <fjl@ethereum.org>" author = "Ethereum Builds <fjl@ethereum.org>"
} }
return debMetadata{ return debMetadata{
Unstable: unstable, Env: env,
Author: author, Author: author,
Distro: distro, Distro: distro,
Commit: build.GitCommit(),
Version: build.VERSION(), Version: build.VERSION(),
Buildnum: buildnum,
Time: t.Format(time.RFC1123Z), Time: t.Format(time.RFC1123Z),
Executables: debExecutables, Executables: debExecutables,
} }
@ -390,7 +372,7 @@ func newDebMetadata(distro, author, buildnum string, unstable bool, t time.Time)
// Name returns the name of the metapackage that depends // Name returns the name of the metapackage that depends
// on all executable packages. // on all executable packages.
func (meta debMetadata) Name() string { func (meta debMetadata) Name() string {
if meta.Unstable { if isUnstableBuild(meta.Env) {
return "ethereum-unstable" return "ethereum-unstable"
} }
return "ethereum" return "ethereum"
@ -399,8 +381,8 @@ func (meta debMetadata) Name() string {
// VersionString returns the debian version of the packages. // VersionString returns the debian version of the packages.
func (meta debMetadata) VersionString() string { func (meta debMetadata) VersionString() string {
vsn := meta.Version vsn := meta.Version
if meta.Buildnum != "" { if meta.Env.Buildnum != "" {
vsn += "+build" + meta.Buildnum vsn += "+build" + meta.Env.Buildnum
} }
if meta.Distro != "" { if meta.Distro != "" {
vsn += "+" + meta.Distro vsn += "+" + meta.Distro
@ -419,7 +401,7 @@ func (meta debMetadata) ExeList() string {
// ExeName returns the package name of an executable package. // ExeName returns the package name of an executable package.
func (meta debMetadata) ExeName(exe debExecutable) string { func (meta debMetadata) ExeName(exe debExecutable) string {
if meta.Unstable { if isUnstableBuild(meta.Env) {
return exe.Name + "-unstable" return exe.Name + "-unstable"
} }
return exe.Name return exe.Name
@ -428,7 +410,7 @@ func (meta debMetadata) ExeName(exe debExecutable) string {
// ExeConflicts returns the content of the Conflicts field // ExeConflicts returns the content of the Conflicts field
// for executable packages. // for executable packages.
func (meta debMetadata) ExeConflicts(exe debExecutable) string { func (meta debMetadata) ExeConflicts(exe debExecutable) string {
if meta.Unstable { if isUnstableBuild(meta.Env) {
// Set up the conflicts list so that the *-unstable packages // Set up the conflicts list so that the *-unstable packages
// cannot be installed alongside the regular version. // cannot be installed alongside the regular version.
// //
@ -461,8 +443,8 @@ func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) {
build.RenderString("8\n", filepath.Join(debian, "compat"), 0644, meta) build.RenderString("8\n", filepath.Join(debian, "compat"), 0644, meta)
build.RenderString("3.0 (native)\n", filepath.Join(debian, "source/format"), 0644, meta) build.RenderString("3.0 (native)\n", filepath.Join(debian, "source/format"), 0644, meta)
for _, exe := range meta.Executables { for _, exe := range meta.Executables {
install := filepath.Join(debian, exe.Name+".install") install := filepath.Join(debian, meta.ExeName(exe)+".install")
docs := filepath.Join(debian, exe.Name+".docs") docs := filepath.Join(debian, meta.ExeName(exe)+".docs")
build.Render("build/deb.install", install, 0644, exe) build.Render("build/deb.install", install, 0644, exe)
build.Render("build/deb.docs", docs, 0644, exe) build.Render("build/deb.docs", docs, 0644, exe)
} }
@ -473,18 +455,19 @@ func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) {
// Cross compilation // Cross compilation
func doXgo(cmdline []string) { func doXgo(cmdline []string) {
flag.CommandLine.Parse(cmdline)
env := build.Env()
// Make sure xgo is available for cross compilation // Make sure xgo is available for cross compilation
gogetxgo := goTool("get", "github.com/karalabe/xgo") gogetxgo := goTool("get", "github.com/karalabe/xgo")
build.MustRun(gogetxgo) build.MustRun(gogetxgo)
// Execute the actual cross compilation // Execute the actual cross compilation
pkg := cmdline[len(cmdline)-1] xgo := xgoTool(append(buildFlags(env), flag.Args()...))
args := append(cmdline[:len(cmdline)-1], makeBuildFlags("")...) build.MustRun(xgo)
build.MustRun(xgoTool(append(args, pkg)...))
} }
func xgoTool(args ...string) *exec.Cmd { func xgoTool(args []string) *exec.Cmd {
cmd := exec.Command(filepath.Join(GOBIN, "xgo"), args...) cmd := exec.Command(filepath.Join(GOBIN, "xgo"), args...)
cmd.Env = []string{ cmd.Env = []string{
"GOPATH=" + build.GOPATH(), "GOPATH=" + build.GOPATH(),

@ -1,5 +1,5 @@
{{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low {{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low
* git build of {{.Commit}} * git build of {{.Env.Commit}}
-- {{.Author}} {{.Time}} -- {{.Author}} {{.Time}}

@ -2,7 +2,7 @@ Source: {{.Name}}
Section: science Section: science
Priority: extra Priority: extra
Maintainer: {{.Author}} Maintainer: {{.Author}}
Build-Depends: debhelper (>= 8.0.0), golang-1.6 Build-Depends: debhelper (>= 8.0.0), golang-1.7
Standards-Version: 3.9.5 Standards-Version: 3.9.5
Homepage: https://ethereum.org Homepage: https://ethereum.org
Vcs-Git: git://github.com/ethereum/go-ethereum.git Vcs-Git: git://github.com/ethereum/go-ethereum.git

@ -5,7 +5,7 @@
#export DH_VERBOSE=1 #export DH_VERBOSE=1
override_dh_auto_build: override_dh_auto_build:
build/env.sh /usr/lib/go-1.6/bin/go run build/ci.go install -gitcommit {{.Commit}} build/env.sh /usr/lib/go-1.7/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
override_dh_auto_test: override_dh_auto_test:

114
internal/build/env.go Normal file

@ -0,0 +1,114 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package build
import (
"flag"
"fmt"
"os"
)
var (
// These flags override values in build env.
GitCommitFlag = flag.String("git-commit", "", `Overrides git commit hash embedded into executables`)
GitBranchFlag = flag.String("git-branch", "", `Overrides git branch being built`)
GitTagFlag = flag.String("git-tag", "", `Overrides git tag being built`)
BuildnumFlag = flag.String("buildnum", "", `Overrides CI build number`)
PullRequestFlag = flag.Bool("pull-request", false, `Overrides pull request status of the build`)
)
// Environment contains metadata provided by the build environment.
type Environment struct {
Name string // name of the environment
Repo string // name of GitHub repo
Commit, Branch, Tag string // Git info
Buildnum string
IsPullRequest bool
}
func (env Environment) String() string {
return fmt.Sprintf("%s env (commit:%s branch:%s tag:%s buildnum:%s pr:%t)",
env.Name, env.Commit, env.Branch, env.Tag, env.Buildnum, env.IsPullRequest)
}
// Env returns metadata about the current CI environment, falling back to LocalEnv
// if not running on CI.
func Env() Environment {
switch {
case os.Getenv("CI") == "true" && os.Getenv("TRAVIS") == "true":
return Environment{
Name: "travis",
Repo: os.Getenv("TRAVIS_REPO_SLUG"),
Commit: os.Getenv("TRAVIS_COMMIT"),
Branch: os.Getenv("TRAVIS_BRANCH"),
Tag: os.Getenv("TRAVIS_TAG"),
Buildnum: os.Getenv("TRAVIS_BUILD_NUMBER"),
IsPullRequest: os.Getenv("TRAVIS_PULL_REQUEST") != "false",
}
case os.Getenv("CI") == "True" && os.Getenv("APPVEYOR") == "True":
return Environment{
Name: "appveyor",
Repo: os.Getenv("APPVEYOR_REPO_NAME"),
Commit: os.Getenv("APPVEYOR_REPO_COMMIT"),
Branch: os.Getenv("APPVEYOR_REPO_BRANCH"),
Tag: os.Getenv("APPVEYOR_REPO_TAG"),
Buildnum: os.Getenv("APPVEYOR_BUILD_NUMBER"),
IsPullRequest: os.Getenv("APPVEYOR_PULL_REQUEST_NUMBER") != "",
}
default:
return LocalEnv()
}
}
// LocalEnv returns build environment metadata gathered from git.
func LocalEnv() Environment {
env := applyEnvFlags(Environment{Name: "local", Repo: "ethereum/go-ethereum"})
if _, err := os.Stat(".git"); err != nil {
return env
}
if env.Commit == "" {
env.Commit = RunGit("rev-parse", "HEAD")
}
if env.Branch == "" {
env.Branch = RunGit("symbolic-ref", "-q", "--short", "HEAD")
}
// Note that we don't get the current git tag. It would slow down
// builds and isn't used by anything.
return env
}
func applyEnvFlags(env Environment) Environment {
if !flag.Parsed() {
panic("you need to call flag.Parse before Env or LocalEnv")
}
if *GitCommitFlag != "" {
env.Commit = *GitCommitFlag
}
if *GitBranchFlag != "" {
env.Branch = *GitBranchFlag
}
if *GitTagFlag != "" {
env.Tag = *GitTagFlag
}
if *BuildnumFlag != "" {
env.Buildnum = *BuildnumFlag
}
if *PullRequestFlag {
env.IsPullRequest = true
}
return env
}

@ -29,9 +29,7 @@ import (
"text/template" "text/template"
) )
var ( var DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands")
DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands")
)
// MustRun executes the given command and exits the host process for // MustRun executes the given command and exits the host process for
// any error. // any error.
@ -69,6 +67,7 @@ func GOPATH() string {
return strings.Join(newpath, string(filepath.ListSeparator)) return strings.Join(newpath, string(filepath.ListSeparator))
} }
// VERSION returns the content of the VERSION file.
func VERSION() string { func VERSION() string {
version, err := ioutil.ReadFile("VERSION") version, err := ioutil.ReadFile("VERSION")
if err != nil { if err != nil {
@ -77,10 +76,8 @@ func VERSION() string {
return string(bytes.TrimSpace(version)) return string(bytes.TrimSpace(version))
} }
func GitCommit() string { // RunGit runs a git subcommand and returns its output.
return RunGit("rev-parse", "HEAD") // The command must complete successfully.
}
func RunGit(args ...string) string { func RunGit(args ...string) string {
cmd := exec.Command("git", args...) cmd := exec.Command("git", args...)
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
@ -94,12 +91,13 @@ func RunGit(args ...string) string {
return strings.TrimSpace(stdout.String()) return strings.TrimSpace(stdout.String())
} }
// Render renders the given template file. // Render renders the given template file into outputFile.
func Render(templateFile, outputFile string, outputPerm os.FileMode, x interface{}) { func Render(templateFile, outputFile string, outputPerm os.FileMode, x interface{}) {
tpl := template.Must(template.ParseFiles(templateFile)) tpl := template.Must(template.ParseFiles(templateFile))
render(tpl, outputFile, outputPerm, x) render(tpl, outputFile, outputPerm, x)
} }
// RenderString renders the given template string into outputFile.
func RenderString(templateContent, outputFile string, outputPerm os.FileMode, x interface{}) { func RenderString(templateContent, outputFile string, outputPerm os.FileMode, x interface{}) {
tpl := template.Must(template.New("").Parse(templateContent)) tpl := template.Must(template.New("").Parse(templateContent))
render(tpl, outputFile, outputPerm, x) render(tpl, outputFile, outputPerm, x)