From 6c33ba14a4db99409657e6a68a7c629e09ceee3f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 25 May 2016 14:07:57 +0200 Subject: [PATCH] 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. --- .gitignore | 8 +- .gitmodules | 3 - .travis.yml | 60 +++-- Makefile | 46 ++-- appveyor.yml | 31 +++ build/ci-notes.md | 26 ++ build/ci.go | 465 ++++++++++++++++++++++++++++++++++ build/deb.changelog | 5 + build/deb.control | 25 ++ build/deb.copyright | 14 + build/deb.docs | 1 + build/deb.install | 1 + build/deb.rules | 13 + build/env.sh | 5 +- build/test-global-coverage.sh | 15 -- build/win-ci-compile.bat | 26 -- build/win-ci-test.bat | 15 -- internal/build/archive.go | 177 +++++++++++++ internal/build/util.go | 122 +++++++++ 19 files changed, 941 insertions(+), 117 deletions(-) delete mode 100644 .gitmodules create mode 100644 appveyor.yml create mode 100644 build/ci-notes.md create mode 100644 build/ci.go create mode 100644 build/deb.changelog create mode 100644 build/deb.control create mode 100644 build/deb.copyright create mode 100644 build/deb.docs create mode 100644 build/deb.install create mode 100644 build/deb.rules delete mode 100755 build/test-global-coverage.sh delete mode 100644 build/win-ci-compile.bat delete mode 100644 build/win-ci-test.bat create mode 100644 internal/build/archive.go create mode 100644 internal/build/util.go 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 -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 -after_success: - - bash <(curl -s https://codecov.io/bash) -env: - global: - - secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64=" +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 golang.org/x/tools/cmd/cover +script: + - go run build/ci.go install + - go run build/ci.go test -coverage -vet +after_success: + # - 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 . + +// +build none + +/* +The ci command is called from Continuous Integration scripts. + +Usage: go run ci.go + +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) ", + "-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 ", 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 " + } + 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 . 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 . + +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 . + +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) + } +}