Skip to content

Commit 734e00a

Browse files
authored
travis, build, internal: use own Go bundle for PPA builds (ethereum#20240)
* build: bump PPAs to Go 1.13 (via longsleep), keep Trusty on 1.11 * travis, build, vendor: use own Go bundle for PPA builds * travis, build, internal, vendor: smarter Go bundler, own untar * build: updated ci-notes with new Go bundling, only make, don't test
1 parent b566cfd commit 734e00a

File tree

7 files changed

+193
-32
lines changed

7 files changed

+193
-32
lines changed

.travis.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,12 @@ jobs:
7575
- fakeroot
7676
- python-bzrlib
7777
- python-paramiko
78+
cache:
79+
directories:
80+
- $HOME/.gobundle
7881
script:
7982
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
80-
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <[email protected]>"
83+
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <[email protected]>" -goversion 1.13.4 -gohash 95dbeab442ee2746b9acf0934c8e2fc26414a0565c008631b04addb8c02e7624 -gobundle $HOME/.gobundle/go.tar.gz
8184

8285
# This builder does the Linux Azure uploads
8386
- stage: build

build/ci-notes.md

+8-9
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,29 @@ variables `PPA_SIGNING_KEY` and `PPA_SSH_KEY` on Travis.
2222

2323
We want to build go-ethereum with the most recent version of Go, irrespective of the Go
2424
version that is available in the main Ubuntu repository. In order to make this possible,
25-
our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on
26-
golang-1.11, which is co-installable alongside the regular golang package. PPA dependencies
27-
can be edited at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies
25+
we bundle the entire Go sources into our own source archive and start the built job by
26+
compiling Go and then using that to build go-ethereum. On Trusty we have a special case
27+
requiring the `~gophers/ubuntu/archive` PPA since Trusty can't even build Go itself. PPA
28+
deps are set at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies
2829

2930
## Building Packages Locally (for testing)
3031

3132
You need to run Ubuntu to do test packaging.
3233

33-
Add the gophers PPA and install Go 1.11 and Debian packaging tools:
34+
Install any version of Go and Debian packaging tools:
3435

35-
$ sudo apt-add-repository ppa:gophers/ubuntu/archive
36-
$ sudo apt-get update
37-
$ sudo apt-get install build-essential golang-1.11 devscripts debhelper python-bzrlib python-paramiko
36+
$ sudo apt-get install build-essential golang-go devscripts debhelper python-bzrlib python-paramiko
3837

3938
Create the source packages:
4039

4140
$ go run build/ci.go debsrc -workdir dist
4241

4342
Then go into the source package directory for your running distribution and build the package:
4443

45-
$ cd dist/ethereum-unstable-1.6.0+xenial
44+
$ cd dist/ethereum-unstable-1.9.6+bionic
4645
$ dpkg-buildpackage
4746

4847
Built packages are placed in the dist/ directory.
4948

5049
$ cd ..
51-
$ dpkg-deb -c geth-unstable_1.6.0+xenial_amd64.deb
50+
$ dpkg-deb -c geth-unstable_1.9.6+bionic_amd64.deb

build/ci.go

+50-20
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import (
5858
"strings"
5959
"time"
6060

61+
"github.com/ethereum/go-ethereum/common/hexutil"
6162
"github.com/ethereum/go-ethereum/internal/build"
6263
"github.com/ethereum/go-ethereum/params"
6364
)
@@ -138,7 +139,18 @@ var (
138139
// Note: zesty is unsupported because it was officially deprecated on Launchpad.
139140
// Note: artful is unsupported because it was officially deprecated on Launchpad.
140141
// Note: cosmic is unsupported because it was officially deprecated on Launchpad.
141-
debDistros = []string{"trusty", "xenial", "bionic", "disco", "eoan"}
142+
debDistroGoBoots = map[string]string{
143+
"trusty": "golang-1.11",
144+
"xenial": "golang-go",
145+
"bionic": "golang-go",
146+
"disco": "golang-go",
147+
"eoan": "golang-go",
148+
}
149+
150+
debGoBootPaths = map[string]string{
151+
"golang-1.11": "/usr/lib/go-1.11",
152+
"golang-go": "/usr/lib/go",
153+
}
142154
)
143155

144156
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
@@ -459,11 +471,14 @@ func maybeSkipArchive(env build.Environment) {
459471
// Debian Packaging
460472
func doDebianSource(cmdline []string) {
461473
var (
462-
signer = flag.String("signer", "", `Signing key name, also used as package author`)
463-
upload = flag.String("upload", "", `Where to upload the source package (usually "ethereum/ethereum")`)
464-
sshUser = flag.String("sftp-user", "", `Username for SFTP upload (usually "geth-ci")`)
465-
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
466-
now = time.Now()
474+
goversion = flag.String("goversion", "", `Go version to build with (will be included in the source package)`)
475+
gobundle = flag.String("gobundle", "/tmp/go.tar.gz", `Filesystem path to cache the downloaded Go bundles at`)
476+
gohash = flag.String("gohash", "", `SHA256 checksum of the Go sources requested to build with`)
477+
signer = flag.String("signer", "", `Signing key name, also used as package author`)
478+
upload = flag.String("upload", "", `Where to upload the source package (usually "ethereum/ethereum")`)
479+
sshUser = flag.String("sftp-user", "", `Username for SFTP upload (usually "geth-ci")`)
480+
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
481+
now = time.Now()
467482
)
468483
flag.CommandLine.Parse(cmdline)
469484
*workdir = makeWorkdir(*workdir)
@@ -476,12 +491,25 @@ func doDebianSource(cmdline []string) {
476491
gpg.Stdin = bytes.NewReader(key)
477492
build.MustRun(gpg)
478493
}
479-
494+
// Download and verify the Go source package
495+
if err := build.EnsureGoSources(*goversion, hexutil.MustDecode("0x"+*gohash), *gobundle); err != nil {
496+
log.Fatalf("Failed to ensure Go source package: %v", err)
497+
}
480498
// Create Debian packages and upload them
481499
for _, pkg := range debPackages {
482-
for _, distro := range debDistros {
483-
meta := newDebMetadata(distro, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables)
500+
for distro, goboot := range debDistroGoBoots {
501+
// Prepare the debian package with the go-ethereum sources
502+
meta := newDebMetadata(distro, goboot, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables)
484503
pkgdir := stageDebianSource(*workdir, meta)
504+
505+
// Ship the Go sources along so we have a proper thing to build with
506+
if err := build.ExtractTarballArchive(*gobundle, pkgdir); err != nil {
507+
log.Fatalf("Failed to extract Go sources: %v", err)
508+
}
509+
if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, ".go")); err != nil {
510+
log.Fatalf("Failed to rename Go source folder: %v", err)
511+
}
512+
// Run the packaging and upload to the PPA
485513
debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc", "-d", "-Zxz")
486514
debuild.Dir = pkgdir
487515
build.MustRun(debuild)
@@ -561,7 +589,9 @@ type debPackage struct {
561589
}
562590

563591
type debMetadata struct {
564-
Env build.Environment
592+
Env build.Environment
593+
GoBootPackage string
594+
GoBootPath string
565595

566596
PackageName string
567597

@@ -590,19 +620,21 @@ func (d debExecutable) Package() string {
590620
return d.BinaryName
591621
}
592622

593-
func newDebMetadata(distro, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata {
623+
func newDebMetadata(distro, goboot, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata {
594624
if author == "" {
595625
// No signing key, use default author.
596626
author = "Ethereum Builds <[email protected]>"
597627
}
598628
return debMetadata{
599-
PackageName: name,
600-
Env: env,
601-
Author: author,
602-
Distro: distro,
603-
Version: version,
604-
Time: t.Format(time.RFC1123Z),
605-
Executables: exes,
629+
GoBootPackage: goboot,
630+
GoBootPath: debGoBootPaths[goboot],
631+
PackageName: name,
632+
Env: env,
633+
Author: author,
634+
Distro: distro,
635+
Version: version,
636+
Time: t.Format(time.RFC1123Z),
637+
Executables: exes,
606638
}
607639
}
608640

@@ -667,7 +699,6 @@ func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) {
667699
if err := os.Mkdir(pkgdir, 0755); err != nil {
668700
log.Fatal(err)
669701
}
670-
671702
// Copy the source code.
672703
build.MustRunCommand("git", "checkout-index", "-a", "--prefix", pkgdir+string(filepath.Separator))
673704

@@ -685,7 +716,6 @@ func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) {
685716
build.Render("build/deb/"+meta.PackageName+"/deb.install", install, 0644, exe)
686717
build.Render("build/deb/"+meta.PackageName+"/deb.docs", docs, 0644, exe)
687718
}
688-
689719
return pkgdir
690720
}
691721

build/deb/ethereum/deb.control

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Source: {{.Name}}
22
Section: science
33
Priority: extra
44
Maintainer: {{.Author}}
5-
Build-Depends: debhelper (>= 8.0.0), golang-1.11
5+
Build-Depends: debhelper (>= 8.0.0), {{.GoBootPackage}}
66
Standards-Version: 3.9.5
77
Homepage: https://ethereum.org
88
Vcs-Git: git://github.com/ethereum/go-ethereum.git

build/deb/ethereum/deb.rules

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66

77
# Launchpad rejects Go's access to $HOME/.cache, use custom folder
88
export GOCACHE=/tmp/go-build
9+
export GOROOT_BOOTSTRAP={{.GoBootPath}}
910

1011
override_dh_auto_build:
11-
build/env.sh /usr/lib/go-1.11/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
12+
(cd .go/src && ./make.bash)
13+
build/env.sh .go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
1214

1315
override_dh_auto_test:
1416

internal/build/archive.go

+46
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,49 @@ func (a *TarballArchive) Close() error {
183183
}
184184
return a.file.Close()
185185
}
186+
187+
func ExtractTarballArchive(archive string, dest string) error {
188+
// We're only interested in gzipped archives, wrap the reader now
189+
ar, err := os.Open(archive)
190+
if err != nil {
191+
return err
192+
}
193+
defer ar.Close()
194+
195+
gzr, err := gzip.NewReader(ar)
196+
if err != nil {
197+
return err
198+
}
199+
defer gzr.Close()
200+
201+
// Iterate over all the files in the tarball
202+
tr := tar.NewReader(gzr)
203+
for {
204+
// Fetch the next tarball header and abort if needed
205+
header, err := tr.Next()
206+
if err != nil {
207+
if err == io.EOF {
208+
return nil
209+
}
210+
return err
211+
}
212+
// Figure out the target and create it
213+
target := filepath.Join(dest, header.Name)
214+
215+
switch header.Typeflag {
216+
case tar.TypeDir:
217+
if err := os.MkdirAll(target, 0755); err != nil {
218+
return err
219+
}
220+
case tar.TypeReg:
221+
file, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
222+
if err != nil {
223+
return err
224+
}
225+
if _, err := io.Copy(file, tr); err != nil {
226+
return err
227+
}
228+
file.Close()
229+
}
230+
}
231+
}

internal/build/gosrc.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2019 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package build
18+
19+
import (
20+
"bytes"
21+
"crypto/sha256"
22+
"fmt"
23+
"io/ioutil"
24+
"net/http"
25+
"os"
26+
"path/filepath"
27+
"strings"
28+
)
29+
30+
// EnsureGoSources ensures that path contains a file with the given SHA256 hash,
31+
// and if not, it downloads a fresh Go source package from upstream and replaces
32+
// path with it (if the hash matches).
33+
func EnsureGoSources(version string, hash []byte, path string) error {
34+
// Sanity check the destination path to ensure we don't do weird things
35+
if !strings.HasSuffix(path, ".tar.gz") {
36+
return fmt.Errorf("destination path (%s) must end with .tar.gz", path)
37+
}
38+
// If the file exists, validate it's hash
39+
if archive, err := ioutil.ReadFile(path); err == nil { // Go sources are ~20MB, it's fine to read all
40+
hasher := sha256.New()
41+
hasher.Write(archive)
42+
have := hasher.Sum(nil)
43+
44+
if bytes.Equal(have, hash) {
45+
fmt.Printf("Go %s [%x] available at %s\n", version, hash, path)
46+
return nil
47+
}
48+
fmt.Printf("Go %s hash mismatch (have %x, want %x) at %s, deleting old archive\n", version, have, hash, path)
49+
if err := os.Remove(path); err != nil {
50+
return err
51+
}
52+
}
53+
// Archive missing or bad hash, download a new one
54+
fmt.Printf("Downloading Go %s [want %x] into %s\n", version, hash, path)
55+
56+
res, err := http.Get(fmt.Sprintf("https://dl.google.com/go/go%s.src.tar.gz", version))
57+
if err != nil || res.StatusCode != http.StatusOK {
58+
return fmt.Errorf("failed to access Go sources: code %d, err %v", res.StatusCode, err)
59+
}
60+
defer res.Body.Close()
61+
62+
archive, err := ioutil.ReadAll(res.Body)
63+
if err != nil {
64+
return err
65+
}
66+
// Sanity check the downloaded archive, save if checks out
67+
hasher := sha256.New()
68+
hasher.Write(archive)
69+
70+
if have := hasher.Sum(nil); !bytes.Equal(have, hash) {
71+
return fmt.Errorf("downloaded Go %s hash mismatch (have %x, want %x)", version, have, hash)
72+
}
73+
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
74+
return err
75+
}
76+
if err := ioutil.WriteFile(path, archive, 0644); err != nil {
77+
return err
78+
}
79+
fmt.Printf("Downloaded Go %s [%x] into %s\n", version, hash, path)
80+
return nil
81+
}

0 commit comments

Comments
 (0)