From 6c33ba14a4db99409657e6a68a7c629e09ceee3f Mon Sep 17 00:00:00 2001
From: Felix Lange <fjl@twurst.com>
Date: Wed, 25 May 2016 14:07:57 +0200
Subject: 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.
---
 internal/build/archive.go | 177 ++++++++++++++++++++++++++++++++++++++++++++++
 internal/build/util.go    | 122 ++++++++++++++++++++++++++++++++
 2 files changed, 299 insertions(+)
 create mode 100644 internal/build/archive.go
 create mode 100644 internal/build/util.go

(limited to 'internal')

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)
+	}
+}
-- 
cgit v1.2.3