aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2016-05-25 20:07:57 +0800
committerFelix Lange <fjl@twurst.com>2016-06-22 19:42:39 +0800
commit6c33ba14a4db99409657e6a68a7c629e09ceee3f (patch)
tree7b73dadb69a0e626e6c2c922da2ac17bba8e94d4
parenta38be3eb488a349693a9c9905ab015278281f8db (diff)
downloaddexon-6c33ba14a4db99409657e6a68a7c629e09ceee3f.tar
dexon-6c33ba14a4db99409657e6a68a7c629e09ceee3f.tar.gz
dexon-6c33ba14a4db99409657e6a68a7c629e09ceee3f.tar.bz2
dexon-6c33ba14a4db99409657e6a68a7c629e09ceee3f.tar.lz
dexon-6c33ba14a4db99409657e6a68a7c629e09ceee3f.tar.xz
dexon-6c33ba14a4db99409657e6a68a7c629e09ceee3f.tar.zst
dexon-6c33ba14a4db99409657e6a68a7c629e09ceee3f.zip
build: add ci.go, use it everywhere
The new build script, ci.go, replaces some of the older shell scripts. ci.go can compile go-ethereum, run the tests, create release archives and debian source packages.
-rw-r--r--.gitignore8
-rw-r--r--.gitmodules3
-rw-r--r--.travis.yml54
-rw-r--r--Makefile46
-rw-r--r--appveyor.yml31
-rw-r--r--build/ci-notes.md26
-rw-r--r--build/ci.go465
-rw-r--r--build/deb.changelog5
-rw-r--r--build/deb.control25
-rw-r--r--build/deb.copyright14
-rw-r--r--build/deb.docs1
-rw-r--r--build/deb.install1
-rw-r--r--build/deb.rules13
-rwxr-xr-xbuild/env.sh5
-rwxr-xr-xbuild/test-global-coverage.sh15
-rw-r--r--build/win-ci-compile.bat26
-rw-r--r--build/win-ci-test.bat15
-rw-r--r--internal/build/archive.go177
-rw-r--r--internal/build/util.go122
19 files changed, 938 insertions, 114 deletions
diff --git a/.gitignore b/.gitignore
index e8e10db2f..21dbd28c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,17 +23,11 @@ Godeps/_workspace/bin
.project
.settings
-deploy/osx/Mist.app
-deploy/osx/Mist\ Installer.dmg
-cmd/mist/assets/ext/ethereum.js/
-
# used by the Makefile
/build/_workspace/
/build/bin/
+/geth*.zip
# travis
profile.tmp
profile.cov
-
-# vagrant
-.vagrant
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 219564eb7..000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "cmd/mist/assets/ext/ethereum.js"]
- path = cmd/mist/assets/ext/ethereum.js
- url = https://github.com/ethereum/web3.js
diff --git a/.travis.yml b/.travis.yml
index 24486d4a0..d0fd4b775 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,31 +1,45 @@
language: go
-go:
- - 1.4.2
- - 1.5.4
- - 1.6.2
+go_import_path: github.com/ethereum/go-ethereum
+sudo: false
+matrix:
+ include:
+ - os: linux
+ dist: trusty
+ go: 1.4.2
+ - os: linux
+ dist: trusty
+ go: 1.5.4
+ - os: linux
+ dist: trusty
+ go: 1.6.2
+ - os: osx
+ go: 1.6.2
+
+ # This builder does the PPA upload (and nothing else).
+ - os: linux
+ dist: trusty
+ go: 1.6.2
+ env: PPA
+ addons:
+ apt:
+ packages:
+ - devscripts
+ - debhelper
+ - dput
+ script:
+ - go run build/ci.go travis-debsrc
+
install:
- # - go get code.google.com/p/go.tools/cmd/goimports
- # - go get github.com/golang/lint/golint
- # - go get golang.org/x/tools/cmd/vet
- go get golang.org/x/tools/cmd/cover
-before_script:
- # - gofmt -l -w .
- # - goimports -l -w .
- # - golint .
- # - go vet ./...
- # - go test -race ./...
script:
- - make travis-test-with-coverage
+ - go run build/ci.go install
+ - go run build/ci.go test -coverage -vet
after_success:
- - bash <(curl -s https://codecov.io/bash)
-env:
- global:
- - secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
-sudo: false
+ # - go run build/ci.go archive -type tar
+
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
on_success: change
on_failure: always
- on_start: false
diff --git a/Makefile b/Makefile
index c2fb9bb35..148cb5758 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
# with Go source code. If you know what GOPATH is then you probably
# don't need to bother with make.
-.PHONY: geth geth-cross evm all test travis-test-with-coverage xgo clean
+.PHONY: geth geth-cross evm all test xgo clean
.PHONY: geth-linux geth-linux-386 geth-linux-amd64
.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
@@ -13,10 +13,29 @@ GOBIN = build/bin
GO ?= latest
geth:
- build/env.sh go build -i -v $(shell build/flags.sh) -o $(GOBIN)/geth ./cmd/geth
+ build/env.sh go run build/ci.go install ./cmd/geth
@echo "Done building."
@echo "Run \"$(GOBIN)/geth\" to launch geth."
+evm:
+ build/env.sh go run build/ci.go install ./cmd/evm
+ @echo "Done building."
+ @echo "Run \"$(GOBIN)/evm to start the evm."
+
+all:
+ build/env.sh go run build/ci.go install
+
+test: all
+ build/env.sh go run build/ci.go test
+
+clean:
+ rm -fr build/_workspace/pkg/ Godeps/_workspace/pkg $(GOBIN)/*
+
+# Cross Compilation Targets (xgo)
+
+xgo:
+ build/env.sh go get github.com/karalabe/xgo
+
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
@echo "Full cross compilation done:"
@ls -ld $(GOBIN)/geth-*
@@ -96,26 +115,3 @@ geth-ios: xgo
build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=ios-7.0/framework -v $(shell build/flags.sh) ./cmd/geth
@echo "iOS framework cross compilation done:"
@ls -ld $(GOBIN)/geth-ios-*
-
-evm:
- build/env.sh $(GOROOT)/bin/go install -v $(shell build/flags.sh) ./cmd/evm
- @echo "Done building."
- @echo "Run \"$(GOBIN)/evm to start the evm."
-
-all:
- for cmd in `ls ./cmd/`; do \
- build/env.sh go build -i -v $(shell build/flags.sh) -o $(GOBIN)/$$cmd ./cmd/$$cmd; \
- done
-
-test: all
- build/env.sh go test ./...
-
-travis-test-with-coverage: all
- build/env.sh go vet ./...
- build/env.sh build/test-global-coverage.sh
-
-xgo:
- build/env.sh go get github.com/karalabe/xgo
-
-clean:
- rm -fr build/_workspace/pkg/ Godeps/_workspace/pkg $(GOBIN)/*
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 000000000..89d3dfe3d
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,31 @@
+os: Visual Studio 2015
+
+# Clone directly into GOPATH.
+clone_folder: c:\gopath\src\github.com\ethereum\go-ethereum
+clone_depth: 5
+version: "{branch}.{build}"
+environment:
+ global:
+ GOPATH: c:\gopath
+
+# cache choco package files so we don't hit sourceforge all
+# the time.
+cache:
+ - c:\cache
+
+install:
+ - cmd: choco install --cache c:\cache golang mingw | find /v "Extracting "
+ - refreshenv
+ - cd c:\gopath\src\github.com\ethereum\go-ethereum
+
+build_script:
+ - go run build\ci.go install
+
+test_script:
+ - go run build\ci.go test -vet -coverage
+
+after_build:
+ - go run build\ci.go archive -type zip
+
+artifacts:
+ - path: geth-*.zip
diff --git a/build/ci-notes.md b/build/ci-notes.md
new file mode 100644
index 000000000..989cba6dd
--- /dev/null
+++ b/build/ci-notes.md
@@ -0,0 +1,26 @@
+Debian Packaging
+----------------
+
+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
+Canonical:
+
+- Trusty Tahr (14.04 LTS)
+- Wily Werewolf (15.10)
+- Xenial Xerus (16.04 LTS)
+
+Packages of develop branch commits have suffix -unstable and cannot be installed alongside
+the stable version. Switching between release streams requires user intervention.
+
+The packages are built and served by launchpad.net. We generate a Debian source package
+for each distribution and upload it. Their builder picks up the source package, builds it
+and installs the new version into the PPA repository. Launchpad requires a valid signature
+by a team member for source package uploads. The signing key is stored in an environment
+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
+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
+golang-1.6, 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
+
diff --git a/build/ci.go b/build/ci.go
new file mode 100644
index 000000000..33d97c182
--- /dev/null
+++ b/build/ci.go
@@ -0,0 +1,465 @@
+// 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/>.
+
+// +build none
+
+/*
+The ci command is called from Continuous Integration scripts.
+
+Usage: go run ci.go <command> <command flags/arguments>
+
+Available commands are:
+
+ install [ packages... ] -- builds packages and executables
+ test [ -coverage ] [ -vet ] [ packages... ] -- runs the tests
+ archive [ -type zip|tar ] -- archives build artefacts
+ importkeys -- imports signing keys from env
+ debsrc [ -sign key-id ] [ -upload dest ] -- creates a debian source package
+
+For all commands, -n prevents execution of external programs (dry run mode).
+
+*/
+package main
+
+import (
+ "bytes"
+ "encoding/base64"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "time"
+
+ "../internal/build"
+)
+
+var (
+ // Files that end up in the geth*.zip archive.
+ gethArchiveFiles = []string{
+ "COPYING",
+ executablePath("geth"),
+ }
+
+ // Files that end up in the geth-alltools*.zip archive.
+ allToolsArchiveFiles = []string{
+ "COPYING",
+ executablePath("abigen"),
+ executablePath("evm"),
+ executablePath("geth"),
+ executablePath("rlpdump"),
+ }
+
+ // A debian package is created for all executables listed here.
+ debExecutables = []debExecutable{
+ {
+ Name: "geth",
+ Description: "Ethereum CLI client.",
+ },
+ {
+ Name: "rlpdump",
+ Description: "Developer utility tool that prints RLP structures.",
+ },
+ {
+ Name: "evm",
+ Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
+ },
+ {
+ Name: "abigen",
+ Description: "Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages.",
+ },
+ }
+
+ // Distros for which packages are created.
+ // Note: vivid is unsupported because there is no golang-1.6 package for it.
+ debDistros = []string{"trusty", "wily", "xenial", "yakkety"}
+)
+
+var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
+
+func executablePath(name string) string {
+ if runtime.GOOS == "windows" {
+ name += ".exe"
+ }
+ return filepath.Join(GOBIN, name)
+}
+
+func main() {
+ log.SetFlags(log.Lshortfile)
+
+ if _, err := os.Stat(filepath.Join("build", "ci.go")); os.IsNotExist(err) {
+ log.Fatal("this script must be run from the root of the repository")
+ }
+ if len(os.Args) < 2 {
+ log.Fatal("need subcommand as first argument")
+ }
+ switch os.Args[1] {
+ case "install":
+ doInstall(os.Args[2:])
+ case "test":
+ doTest(os.Args[2:])
+ case "archive":
+ doArchive(os.Args[2:])
+ case "debsrc":
+ doDebianSource(os.Args[2:])
+ case "travis-debsrc":
+ doTravisDebianSource(os.Args[2:])
+ default:
+ log.Fatal("unknown command ", os.Args[1])
+ }
+}
+
+// Compiling
+
+func doInstall(cmdline []string) {
+ commitHash := flag.String("gitcommit", "", "Git commit hash embedded into binary.")
+ flag.CommandLine.Parse(cmdline)
+
+ // Check Go version. People regularly open issues about compilation
+ // failure with outdated Go. This should save them the trouble.
+ if runtime.Version() < "go1.4" && !strings.HasPrefix(runtime.Version(), "devel") {
+ log.Println("You have Go version", runtime.Version())
+ log.Println("go-ethereum requires at least Go version 1.4 and cannot")
+ log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
+ os.Exit(1)
+ }
+
+ // Compile packages given as arguments, or everything if there are no arguments.
+ packages := []string{"./..."}
+ if flag.NArg() > 0 {
+ packages = flag.Args()
+ }
+
+ goinstall := goTool("install", makeBuildFlags(*commitHash)...)
+ goinstall.Args = append(goinstall.Args, "-v")
+ goinstall.Args = append(goinstall.Args, packages...)
+ build.MustRun(goinstall)
+}
+
+func makeBuildFlags(commitHash string) (flags []string) {
+ // Since Go 1.5, the separator char for link time assignments
+ // is '=' and using ' ' prints a warning. However, Go < 1.5 does
+ // not support using '='.
+ sep := " "
+ if runtime.Version() > "go1.5" || strings.Contains(runtime.Version(), "devel") {
+ sep = "="
+ }
+
+ if os.Getenv("GO_OPENCL") != "" {
+ flags = append(flags, "-tags", "opencl")
+ }
+
+ // 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
+}
+
+func goTool(subcmd string, args ...string) *exec.Cmd {
+ gocmd := filepath.Join(runtime.GOROOT(), "bin", "go")
+ cmd := exec.Command(gocmd, subcmd)
+ cmd.Args = append(cmd.Args, args...)
+ cmd.Env = []string{
+ "GOPATH=" + build.GOPATH(),
+ "GOBIN=" + GOBIN,
+ }
+ for _, e := range os.Environ() {
+ if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "GOBIN=") {
+ continue
+ }
+ cmd.Env = append(cmd.Env, e)
+ }
+ return cmd
+}
+
+// Running The Tests
+//
+// "tests" also includes static analysis tools such as vet.
+
+func doTest(cmdline []string) {
+ var (
+ vet = flag.Bool("vet", false, "Whether to run go vet")
+ coverage = flag.Bool("coverage", false, "Whether to record code coverage")
+ )
+ flag.CommandLine.Parse(cmdline)
+ packages := []string{"./..."}
+ if len(flag.CommandLine.Args()) > 0 {
+ packages = flag.CommandLine.Args()
+ }
+
+ // Run analysis tools before the tests.
+ if *vet {
+ build.MustRun(goTool("vet", packages...))
+ }
+
+ // Run the actual tests.
+ gotest := goTool("test")
+ if *coverage {
+ gotest.Args = append(gotest.Args, "-covermode=atomic", "-cover")
+ }
+ gotest.Args = append(gotest.Args, packages...)
+ build.MustRun(gotest)
+}
+
+// Release Packaging
+
+func doArchive(cmdline []string) {
+ var (
+ atype = flag.String("type", "zip", "Type of archive to write (zip|tar)")
+ ext string
+ )
+ flag.CommandLine.Parse(cmdline)
+ switch *atype {
+ case "zip":
+ ext = ".zip"
+ case "tar":
+ ext = ".tar.gz"
+ default:
+ log.Fatal("unknown archive type: ", atype)
+ }
+ base := makeArchiveBasename()
+ if err := build.WriteArchive("geth-"+base, ext, gethArchiveFiles); err != nil {
+ log.Fatal(err)
+ }
+ if err := build.WriteArchive("geth-alltools-"+base, ext, allToolsArchiveFiles); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func makeArchiveBasename() string {
+ // date := time.Now().UTC().Format("200601021504")
+ platform := runtime.GOOS + "-" + runtime.GOARCH
+ archive := platform + "-" + build.VERSION()
+ if commit := build.GitCommit(); commit != "" {
+ archive += "-" + commit[:8]
+ }
+ return archive
+}
+
+// Debian Packaging
+
+// CLI entry point for Travis CI.
+func doTravisDebianSource(cmdline []string) {
+ flag.CommandLine.Parse(cmdline)
+
+ // Package only whitelisted branches.
+ switch {
+ 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.
+ if b64key := os.Getenv("PPA_SIGNING_KEY"); b64key != "" {
+ key, err := base64.StdEncoding.DecodeString(b64key)
+ if err != nil {
+ log.Fatal("invalid base64 PPA_SIGNING_KEY")
+ }
+ gpg := exec.Command("gpg", "--import")
+ gpg.Stdin = bytes.NewReader(key)
+ build.MustRun(gpg)
+ }
+
+ // Assign unstable status to non-tag builds.
+ 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 {
+ meta := newDebMetadata(distro, *signer, *buildnum, *unstable, now)
+ pkgdir := stageDebianSource(tmpdir, meta)
+ debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc")
+ debuild.Dir = pkgdir
+ build.MustRun(debuild)
+
+ changes := fmt.Sprintf("%s_%s_source.changes", meta.Name(), meta.VersionString())
+ changes = filepath.Join(tmpdir, changes)
+ if *signer != "" {
+ build.MustRunCommand("debsign", changes)
+ }
+ if *upload != "" {
+ build.MustRunCommand("dput", *upload, changes)
+ }
+ }
+}
+
+type debExecutable struct {
+ Name, Description string
+}
+
+type debMetadata struct {
+ // go-ethereum version being built. Note that this
+ // is not the debian package version. The package version
+ // is constructed by VersionString.
+ Version string
+
+ Author string // "name <email>", also selects signing key
+ Buildnum string // build number
+ Distro, Commit, Time string
+ Executables []debExecutable
+ Unstable bool
+}
+
+func newDebMetadata(distro, author, buildnum string, unstable bool, t time.Time) debMetadata {
+ if author == "" {
+ // No signing key, use default author.
+ author = "Ethereum Builds <fjl@ethereum.org>"
+ }
+ return debMetadata{
+ Unstable: unstable,
+ Author: author,
+ Distro: distro,
+ Commit: build.GitCommit(),
+ Version: build.VERSION(),
+ Buildnum: buildnum,
+ Time: t.Format(time.RFC1123Z),
+ Executables: debExecutables,
+ }
+}
+
+// Name returns the name of the metapackage that depends
+// on all executable packages.
+func (meta debMetadata) Name() string {
+ if meta.Unstable {
+ return "ethereum-unstable"
+ }
+ return "ethereum"
+}
+
+// VersionString returns the debian version of the packages.
+func (meta debMetadata) VersionString() string {
+ vsn := meta.Version
+ if meta.Buildnum != "" {
+ vsn += "+build" + meta.Buildnum
+ }
+ if meta.Distro != "" {
+ vsn += "+" + meta.Distro
+ }
+ return vsn
+}
+
+// ExeList returns the list of all executable packages.
+func (meta debMetadata) ExeList() string {
+ names := make([]string, len(meta.Executables))
+ for i, e := range meta.Executables {
+ names[i] = meta.ExeName(e)
+ }
+ return strings.Join(names, ", ")
+}
+
+// ExeName returns the package name of an executable package.
+func (meta debMetadata) ExeName(exe debExecutable) string {
+ if meta.Unstable {
+ return exe.Name + "-unstable"
+ }
+ return exe.Name
+}
+
+// ExeConflicts returns the content of the Conflicts field
+// for executable packages.
+func (meta debMetadata) ExeConflicts(exe debExecutable) string {
+ if meta.Unstable {
+ // Set up the conflicts list so that the *-unstable packages
+ // cannot be installed alongside the regular version.
+ //
+ // https://www.debian.org/doc/debian-policy/ch-relationships.html
+ // is very explicit about Conflicts: and says that Breaks: should
+ // be preferred and the conflicting files should be handled via
+ // alternates. We might do this eventually but using a conflict is
+ // easier now.
+ return "ethereum, " + exe.Name
+ }
+ return ""
+}
+
+func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) {
+ pkg := meta.Name() + "-" + meta.VersionString()
+ pkgdir = filepath.Join(tmpdir, pkg)
+ if err := os.Mkdir(pkgdir, 0755); err != nil {
+ log.Fatal(err)
+ }
+
+ // Copy the source code.
+ build.MustRunCommand("git", "checkout-index", "-a", "--prefix", pkgdir+string(filepath.Separator))
+
+ // Put the debian build files in place.
+ debian := filepath.Join(pkgdir, "debian")
+ build.Render("build/deb.rules", filepath.Join(debian, "rules"), 0755, meta)
+ build.Render("build/deb.changelog", filepath.Join(debian, "changelog"), 0644, meta)
+ build.Render("build/deb.control", filepath.Join(debian, "control"), 0644, meta)
+ build.Render("build/deb.copyright", filepath.Join(debian, "copyright"), 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)
+ for _, exe := range meta.Executables {
+ install := filepath.Join(debian, exe.Name+".install")
+ docs := filepath.Join(debian, exe.Name+".docs")
+ build.Render("build/deb.install", install, 0644, exe)
+ build.Render("build/deb.docs", docs, 0644, exe)
+ }
+
+ return pkgdir
+}
diff --git a/build/deb.changelog b/build/deb.changelog
new file mode 100644
index 000000000..a221f5470
--- /dev/null
+++ b/build/deb.changelog
@@ -0,0 +1,5 @@
+{{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low
+
+ * git build of {{.Commit}}
+
+ -- {{.Author}} {{.Time}}
diff --git a/build/deb.control b/build/deb.control
new file mode 100644
index 000000000..4a65c7fac
--- /dev/null
+++ b/build/deb.control
@@ -0,0 +1,25 @@
+Source: {{.Name}}
+Section: science
+Priority: extra
+Maintainer: {{.Author}}
+Build-Depends: debhelper (>= 8.0.0), golang-1.6
+Standards-Version: 3.9.5
+Homepage: https://ethereum.org
+Vcs-Git: git://github.com/ethereum/go-ethereum.git
+Vcs-Browser: https://github.com/ethereum/go-ethereum
+
+Package: {{.Name}}
+Architecture: any
+Depends: ${misc:Depends}, {{.ExeList}}
+Description: Meta-package to install geth and other tools
+ Meta-package to install geth and other tools
+
+{{range .Executables}}
+Package: {{$.ExeName .}}
+Conflicts: {{$.ExeConflicts .}}
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Built-Using: ${misc:Built-Using}
+Description: {{.Description}}
+ {{.Description}}
+{{end}}
diff --git a/build/deb.copyright b/build/deb.copyright
new file mode 100644
index 000000000..513be45b1
--- /dev/null
+++ b/build/deb.copyright
@@ -0,0 +1,14 @@
+Copyright 2016 The go-ethereum Authors
+
+go-ethereum is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+go-ethereum 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
diff --git a/build/deb.docs b/build/deb.docs
new file mode 100644
index 000000000..62deb0497
--- /dev/null
+++ b/build/deb.docs
@@ -0,0 +1 @@
+AUTHORS
diff --git a/build/deb.install b/build/deb.install
new file mode 100644
index 000000000..7dc76e1f5
--- /dev/null
+++ b/build/deb.install
@@ -0,0 +1 @@
+build/bin/{{.Name}} usr/bin
diff --git a/build/deb.rules b/build/deb.rules
new file mode 100644
index 000000000..3dfadb08d
--- /dev/null
+++ b/build/deb.rules
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+override_dh_auto_build:
+ build/env.sh /usr/lib/go-1.6/bin/go run build/ci.go install -gitcommit {{.Commit}}
+
+override_dh_auto_test:
+
+%:
+ dh $@
diff --git a/build/env.sh b/build/env.sh
index 04401a3e1..c418dae44 100755
--- a/build/env.sh
+++ b/build/env.sh
@@ -20,9 +20,8 @@ fi
# Set up the environment to use the workspace.
# Also add Godeps workspace so we build using canned dependencies.
-GOPATH="$ethdir/go-ethereum/Godeps/_workspace:$workspace"
-GOBIN="$PWD/build/bin"
-export GOPATH GOBIN
+GOPATH="$workspace"
+export GOPATH
# Run the command inside the workspace.
cd "$ethdir/go-ethereum"
diff --git a/build/test-global-coverage.sh b/build/test-global-coverage.sh
deleted file mode 100755
index a51b6a9e5..000000000
--- a/build/test-global-coverage.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-echo "" > coverage.txt
-
-for d in $(find ./* -maxdepth 10 -type d -not -path "./build" -not -path "./Godeps/*" ); do
- if ls $d/*.go &> /dev/null; then
- go test -coverprofile=profile.out -covermode=atomic $d
- if [ -f profile.out ]; then
- cat profile.out >> coverage.txt
- echo '<<<<<< EOF' >> coverage.txt
- rm profile.out
- fi
- fi
-done
diff --git a/build/win-ci-compile.bat b/build/win-ci-compile.bat
deleted file mode 100644
index 5750990bf..000000000
--- a/build/win-ci-compile.bat
+++ /dev/null
@@ -1,26 +0,0 @@
-@echo off
-if not exist .\build\win-ci-compile.bat (
- echo This script must be run from the root of the repository.
- exit /b
-)
-if not defined GOPATH (
- echo GOPATH is not set.
- exit /b
-)
-
-set GOPATH=%GOPATH%;%cd%\Godeps\_workspace
-set GOBIN=%cd%\build\bin
-
-rem set gitCommit when running from a Git checkout.
-set goLinkFlags=""
-if exist ".git\HEAD" (
- where /q git
- if not errorlevel 1 (
- for /f %%h in ('git rev-parse HEAD') do (
- set goLinkFlags="-X main.gitCommit=%%h"
- )
- )
-)
-
-@echo on
-go install -v -ldflags %goLinkFlags% ./...
diff --git a/build/win-ci-test.bat b/build/win-ci-test.bat
deleted file mode 100644
index 5945426db..000000000
--- a/build/win-ci-test.bat
+++ /dev/null
@@ -1,15 +0,0 @@
-@echo off
-if not exist .\build\win-ci-test.bat (
- echo This script must be run from the root of the repository.
- exit /b
-)
-if not defined GOPATH (
- echo GOPATH is not set.
- exit /b
-)
-
-set GOPATH=%GOPATH%;%cd%\Godeps\_workspace
-set GOBIN=%cd%\build\bin
-
-@echo on
-go test ./...
diff --git a/internal/build/archive.go b/internal/build/archive.go
new file mode 100644
index 000000000..2a7090c0d
--- /dev/null
+++ b/internal/build/archive.go
@@ -0,0 +1,177 @@
+// 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 (
+ "archive/tar"
+ "archive/zip"
+ "compress/gzip"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+type Archive interface {
+ // Directory adds a new directory entry to the archive and sets the
+ // directory for subsequent calls to Header.
+ Directory(name string) error
+
+ // Header adds a new file to the archive. The file is added to the directory
+ // set by Directory. The content of the file must be written to the returned
+ // writer.
+ Header(os.FileInfo) (io.Writer, error)
+
+ // Close flushes the archive and closes the underlying file.
+ Close() error
+}
+
+func NewArchive(file *os.File) Archive {
+ switch {
+ case strings.HasSuffix(file.Name(), ".zip"):
+ return NewZipArchive(file)
+ case strings.HasSuffix(file.Name(), ".tar.gz"):
+ return NewTarballArchive(file)
+ default:
+ return nil
+ }
+}
+
+// AddFile appends an existing file to an archive.
+func AddFile(a Archive, file string) error {
+ fd, err := os.Open(file)
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+ fi, err := fd.Stat()
+ if err != nil {
+ return err
+ }
+ w, err := a.Header(fi)
+ if err != nil {
+ return err
+ }
+ if _, err := io.Copy(w, fd); err != nil {
+ return err
+ }
+ return nil
+}
+
+// WriteArchive creates an archive containing the given files.
+func WriteArchive(basename, ext string, files []string) error {
+ archfd, err := os.Create(basename + ext)
+ if err != nil {
+ return err
+ }
+ defer archfd.Close()
+ archive := NewArchive(archfd)
+ if archive == nil {
+ return fmt.Errorf("unknown archive extension: %s", ext)
+ }
+ fmt.Println(basename + ext)
+ if err := archive.Directory(basename); err != nil {
+ return err
+ }
+ for _, file := range files {
+ fmt.Println(" +", filepath.Base(file))
+ if err := AddFile(archive, file); err != nil {
+ return err
+ }
+ }
+ return archive.Close()
+}
+
+type ZipArchive struct {
+ dir string
+ zipw *zip.Writer
+ file io.Closer
+}
+
+func NewZipArchive(w io.WriteCloser) Archive {
+ return &ZipArchive{"", zip.NewWriter(w), w}
+}
+
+func (a *ZipArchive) Directory(name string) error {
+ a.dir = name + "/"
+ return nil
+}
+
+func (a *ZipArchive) Header(fi os.FileInfo) (io.Writer, error) {
+ head, err := zip.FileInfoHeader(fi)
+ if err != nil {
+ return nil, fmt.Errorf("can't make zip header: %v", err)
+ }
+ head.Name = a.dir + head.Name
+ w, err := a.zipw.CreateHeader(head)
+ if err != nil {
+ return nil, fmt.Errorf("can't add zip header: %v", err)
+ }
+ return w, nil
+}
+
+func (a *ZipArchive) Close() error {
+ if err := a.zipw.Close(); err != nil {
+ return err
+ }
+ return a.file.Close()
+}
+
+type TarballArchive struct {
+ dir string
+ tarw *tar.Writer
+ gzw *gzip.Writer
+ file io.Closer
+}
+
+func NewTarballArchive(w io.WriteCloser) Archive {
+ gzw := gzip.NewWriter(w)
+ tarw := tar.NewWriter(gzw)
+ return &TarballArchive{"", tarw, gzw, w}
+}
+
+func (a *TarballArchive) Directory(name string) error {
+ a.dir = name + "/"
+ return a.tarw.WriteHeader(&tar.Header{
+ Name: a.dir,
+ Mode: 0755,
+ Typeflag: tar.TypeDir,
+ })
+}
+
+func (a *TarballArchive) Header(fi os.FileInfo) (io.Writer, error) {
+ head, err := tar.FileInfoHeader(fi, "")
+ if err != nil {
+ return nil, fmt.Errorf("can't make tar header: %v", err)
+ }
+ head.Name = a.dir + head.Name
+ if err := a.tarw.WriteHeader(head); err != nil {
+ return nil, fmt.Errorf("can't add tar header: %v", err)
+ }
+ return a.tarw, nil
+}
+
+func (a *TarballArchive) Close() error {
+ if err := a.tarw.Close(); err != nil {
+ return err
+ }
+ if err := a.gzw.Close(); err != nil {
+ return err
+ }
+ return a.file.Close()
+}
diff --git a/internal/build/util.go b/internal/build/util.go
new file mode 100644
index 000000000..eead824b2
--- /dev/null
+++ b/internal/build/util.go
@@ -0,0 +1,122 @@
+// 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 (
+ "bytes"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "text/template"
+)
+
+var (
+ DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands")
+)
+
+// MustRun executes the given command and exits the host process for
+// any error.
+func MustRun(cmd *exec.Cmd) {
+ fmt.Println(">>>", strings.Join(cmd.Args, " "))
+ if !*DryRunFlag {
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = os.Stdout
+ if err := cmd.Run(); err != nil {
+ log.Fatal(err)
+ }
+ }
+}
+
+func MustRunCommand(cmd string, args ...string) {
+ MustRun(exec.Command(cmd, args...))
+}
+
+// GOPATH returns the value that the GOPATH environment
+// variable should be set to.
+func GOPATH() string {
+ path := filepath.SplitList(os.Getenv("GOPATH"))
+ if len(path) == 0 {
+ log.Fatal("GOPATH is not set")
+ }
+ // Ensure Godeps workspace is present in the path.
+ godeps, _ := filepath.Abs(filepath.Join("Godeps", "_workspace"))
+ for _, dir := range path {
+ if dir == godeps {
+ return strings.Join(path, string(filepath.ListSeparator))
+ }
+ }
+ newpath := append(path[:1], godeps)
+ newpath = append(newpath, path[1:]...)
+ return strings.Join(newpath, string(filepath.ListSeparator))
+}
+
+func VERSION() string {
+ version, err := ioutil.ReadFile("VERSION")
+ if err != nil {
+ log.Fatal(err)
+ }
+ return string(bytes.TrimSpace(version))
+}
+
+func GitCommit() string {
+ return RunGit("rev-parse", "HEAD")
+}
+
+func RunGit(args ...string) string {
+ cmd := exec.Command("git", args...)
+ var stdout, stderr bytes.Buffer
+ cmd.Stdout, cmd.Stderr = &stdout, &stderr
+ if err := cmd.Run(); err == exec.ErrNotFound {
+ log.Println("no git in PATH")
+ return ""
+ } else if err != nil {
+ log.Fatal(strings.Join(cmd.Args, " "), ": ", err, "\n", stderr.String())
+ }
+ return strings.TrimSpace(stdout.String())
+}
+
+// Render renders the given template file.
+func Render(templateFile, outputFile string, outputPerm os.FileMode, x interface{}) {
+ tpl := template.Must(template.ParseFiles(templateFile))
+ render(tpl, outputFile, outputPerm, x)
+}
+
+func RenderString(templateContent, outputFile string, outputPerm os.FileMode, x interface{}) {
+ tpl := template.Must(template.New("").Parse(templateContent))
+ render(tpl, outputFile, outputPerm, x)
+}
+
+func render(tpl *template.Template, outputFile string, outputPerm os.FileMode, x interface{}) {
+ if err := os.MkdirAll(filepath.Dir(outputFile), 0755); err != nil {
+ log.Fatal(err)
+ }
+ out, err := os.OpenFile(outputFile, os.O_CREATE|os.O_WRONLY|os.O_EXCL, outputPerm)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := tpl.Execute(out, x); err != nil {
+ log.Fatal(err)
+ }
+ if err := out.Close(); err != nil {
+ log.Fatal(err)
+ }
+}