diff --git a/.gitignore b/.gitignore
index e8e10db2ffd8279d9081332fca0d1f22bad253ed..21dbd28c56c5ad043662f4760f93014559865592 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 219564eb7b0fdff08b40d95a75f8c920c6da2d7d..0000000000000000000000000000000000000000
--- 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 24486d4a0a12781e87fb611dd0f98bffeb9d6957..d0fd4b77588c490cec235a4d1f2db0a63b80365d 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 c2fb9bb354a8168ffa776d8b146f8764ddb60008..148cb5758bececef40c333f226182ea4d638e922 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 0000000000000000000000000000000000000000..89d3dfe3d776469a9c1cc509c2248f85ec131efe
--- /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 0000000000000000000000000000000000000000..989cba6dde905a0e5641162462b77b73c089d28e
--- /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 0000000000000000000000000000000000000000..33d97c18210c69b7826c2a9db05d7c9432e8a070
--- /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 0000000000000000000000000000000000000000..a221f54702b8096a5746a5b9271c0f8e5303fb8c
--- /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 0000000000000000000000000000000000000000..4a65c7fac133eac4413522609a0d5a3b4048cf7d
--- /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 0000000000000000000000000000000000000000..513be45b193d6089db1cbcf897e37cd501dc1201
--- /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 0000000000000000000000000000000000000000..62deb04972dad47f357c257d314bd5a3a3491492
--- /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 0000000000000000000000000000000000000000..7dc76e1f5673e0cfecd9429b8f3e7e02c641544a
--- /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 0000000000000000000000000000000000000000..3dfadb08d3ac65245e306f397a0051f4ecc6efce
--- /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 04401a3e176a972a19d9395325a8bb7f0c7350a4..c418dae44168c93a3972872247e56157feece142 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 a51b6a9e57af828f05605bc4584dbca69c53ab96..0000000000000000000000000000000000000000
--- 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 5750990bf0bff67fa194e799ea40d5b03c5e5aec..0000000000000000000000000000000000000000
--- 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 5945426db032bdf909ff1458aa0be994f72e84ba..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..2a7090c0df937982557c5afdc3239560ace84145
--- /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 0000000000000000000000000000000000000000..eead824b25ebd1a6f0a3ec2f6468f5982f1f8e1d
--- /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)
+	}
+}