Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parallel cross building #177

Closed
wants to merge 45 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a04829f
Parallel cross building
Feb 14, 2020
192e798
Fix
Feb 14, 2020
392cca0
Reword
Feb 14, 2020
8749dc7
Debug
Feb 14, 2020
46f9caf
Use built promu instead of downloaded one
Feb 14, 2020
966edef
debug
Feb 14, 2020
d97eeca
debug
Feb 14, 2020
ec1327f
Debug
Feb 14, 2020
e4d440f
debug
Feb 14, 2020
13d906d
Debug
Feb 14, 2020
09607f3
debug
Feb 14, 2020
6ac2170
debug
Feb 14, 2020
f461394
debug
Feb 14, 2020
1246bb6
Copy go mod cache
Feb 14, 2020
c07932f
Add mutex around docker cp
Feb 14, 2020
f1dc4a7
Do not docker cp .build/
Feb 14, 2020
4e0af0f
Use local docker
Feb 14, 2020
7774925
Install go 1.13
Feb 14, 2020
45ff7b2
Install go 1.13
Feb 14, 2020
d10240c
debug
Feb 14, 2020
6603021
debug
Feb 14, 2020
76eb577
debug
Feb 14, 2020
e07249c
debug
Feb 14, 2020
54abc71
debug
Feb 14, 2020
0ca7fe7
debug
Feb 14, 2020
21b9118
debug
Feb 14, 2020
9cf90d5
debug
Feb 14, 2020
e0474c0
Build binaries in parallel
Feb 15, 2020
baf476d
Local crossbuild
Feb 15, 2020
cf99ae6
Mostly display
Feb 15, 2020
c2e9556
Fix circleci
Feb 15, 2020
d77543f
Fix crossbuild outputs
Feb 15, 2020
74ec552
go mod vendor
Feb 15, 2020
8708842
Fix yaml
Feb 15, 2020
c866f49
Fix yaml
Feb 15, 2020
60f8455
Fix yaml
Feb 15, 2020
715e6d7
Fix circleci
Feb 15, 2020
5283758
Fix circleci
Feb 15, 2020
d40d616
go mod vendor
Feb 15, 2020
673f40f
Fix test
Feb 15, 2020
5774a48
Fix crossbuild docker
Feb 15, 2020
0de34e1
Display
Feb 15, 2020
25567c5
reduce sleep
Feb 15, 2020
4df40b7
Display remaining builds counter
Feb 16, 2020
c6e6a2b
Allow building binaries that have their own go.mod
Feb 27, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,22 @@ executors:

jobs:
test:
executor: golang
machine:
image: ubuntu-1604:201903-01
working_directory: /home/circleci/.go_workspace/src/github.com/prometheus/promu
environment:
GOCACHE: /home/circleci/.cache/go-build
GOVERSION: 1.13.8

steps:
- setup_remote_docker
- checkout
- run:
name: install go
command: |
sudo rm -rf /usr/local/go
wget https://dl.google.com/go/go${GOVERSION}.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go${GOVERSION}.linux-amd64.tar.gz
rm -f go${GOVERSION}.linux-amd64.tar.gz
- run: make promu
- run: make check_license style unused lint test build
- store_artifacts:
Expand All @@ -23,14 +34,32 @@ jobs:
- run: git diff --exit-code

build:
executor: golang
machine:
image: ubuntu-1604:201903-01
working_directory: /home/circleci/.go_workspace/src/github.com/prometheus/promu
environment:
GOCACHE: /home/circleci/.cache/go-build
GOVERSION: 1.13.8

steps:
- setup_remote_docker
- checkout
- run:
name: install go
command: |
sudo rm -rf /usr/local/go
wget https://dl.google.com/go/go${GOVERSION}.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go${GOVERSION}.linux-amd64.tar.gz
rm -f go${GOVERSION}.linux-amd64.tar.gz
- restore_cache:
keys:
- v01-gocache-{{ checksum "go.mod" }}
- run: make promu
- run: make build
- run: promu crossbuild -v
- save_cache:
key: v01-gocache-{{ checksum "go.mod" }}
paths:
- /home/circleci/.cache/go-build
- persist_to_workspace:
root: .
paths:
Expand Down
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.build
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/promu
.build
.tarballs
.cache
testoutput
4 changes: 2 additions & 2 deletions .promu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ go:
repository:
path: github.com/prometheus/promu
build:
flags: -mod=vendor -a -tags 'netgo static_build'
ldflags: |
flags: -mod=vendor -tags 'netgo static_build'
ldflags: |-
-s
-X github.com/prometheus/common/version.Version={{.Version}}
-X github.com/prometheus/common/version.Revision={{.Revision}}
Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
include Makefile.common

.PHONY: build
build:
@echo ">> installing promu"
GO111MODULE=$(GO111MODULE) GOOS= GOARCH= $(GO) install github.com/prometheus/promu

build: $(PROMU)
@echo ">> rebuilding binaries using promu"
GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX)
6 changes: 1 addition & 5 deletions Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,7 @@ common-docker-manifest:
promu: $(PROMU)

$(PROMU):
$(eval PROMU_TMP := $(shell mktemp -d))
curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP)
mkdir -p $(FIRST_GOPATH)/bin
cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
rm -r $(PROMU_TMP)
GO111MODULE=$(GO111MODULE) GOPATH=$(GOPATH) GOOS="" GOARCH="" $(GO) install .

.PHONY: proto
proto:
Expand Down
129 changes: 107 additions & 22 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"log"
"os"
"path"
"path/filepath"
"strings"
"text/template"
"time"
Expand All @@ -32,6 +33,8 @@ import (
)

var (
binaryJobs = app.Flag("binary-jobs", "Number of binaries to build simultaneously").Default("1").Int()
crossbuildJobs = app.Flag("crossbuild-jobs", "Number of crossbuilds to run simultaneously").Default("1").Int()
buildcmd = app.Command("build", "Build a Go project")
buildCgoFlagSet bool
buildCgoFlag = buildcmd.Flag("cgo", "Enable CGO").
Expand Down Expand Up @@ -66,34 +69,84 @@ OUTER:
return binaries, nil
}

func buildBinary(ext string, prefix string, ldflags string, binary Binary) {
info("Building binary: " + binary.Name)
binaryName := fmt.Sprintf("%s%s", binary.Name, ext)
fmt.Printf(" > %s\n", binaryName)
func buildBinary(goos string, goarch string, ext string, prefix string, ldflags string, binary Binary) error {
var binaryName, binaryPrettyName string

if len(goos) > 0 && len(goarch) > 0 {
platform := fmt.Sprintf("%s/%s", goos, goarch)
binaryName = fmt.Sprintf(".build/%s-%s/%s%s", goos, goarch, binary.Name, ext)
binaryPrettyName = fmt.Sprintf("%s %s", platform, binary.Name)
} else {
binaryName = fmt.Sprintf("%s%s", binary.Name, ext)
binaryPrettyName = fmt.Sprintf("%s", binary.Name)
}

var dir string
for base := binary.Path; len(base) > 1; base = path.Dir(base) {
gomod := path.Join(base, "go.mod")
gosum := path.Join(base, "go.sum")

if _, err := os.Stat(gomod); err == nil {
if _, err := os.Stat(gosum); err == nil {
dir, _ = filepath.Abs(base)
info(" ~ go.mod found in " + dir)
break
}
}
}

info(" < building binary " + binaryPrettyName)

repoPath := config.Repository.Path
flags := config.Build.Flags

params := []string{"build",
params := []string{
"build",
"-o", path.Join(prefix, binaryName),
"-ldflags", ldflags,
}

params = append(params, sh.SplitParameters(flags)...)
params = append(params, path.Join(repoPath, binary.Path))
info("Building binary: " + "go " + strings.Join(params, " "))
if err := sh.RunCommand("go", params...); err != nil {
fatal(errors.Wrap(err, "command failed: "+strings.Join(params, " ")))

if len(binary.Module) > 0 {
params = append(params, binary.Module)
} else {
params = append(params, path.Join(repoPath, binary.Path))
}

var armversion string
var env []string

if strings.Index(goarch, "arm") == 0 && goarch != "arm" && goarch != "arm64" {
armversion = goarch[4:]
goarch = "arm"

env = []string{
"GOOS=" + goos,
"GOARCH=" + goarch,
"GOARM=" + armversion,
}
} else {
env = []string{
"GOOS=" + goos,
"GOARCH=" + goarch,
}
}
}

func buildAll(ext string, prefix string, ldflags string, binaries []Binary) {
for _, binary := range binaries {
buildBinary(ext, prefix, ldflags, binary)
start := time.Now()
if err := sh.RunCommandWithEnv("go", dir, env, params...); err != nil {
duration := time.Since(start)
fmt.Printf(" > %s failed after %v\n", binaryPrettyName, duration.Round(time.Millisecond))
return err
}

duration := time.Since(start)
fmt.Printf(" > %s (built in %v)\n", binaryPrettyName, duration.Round(time.Millisecond))

return nil
}

func runBuild(binariesString string) {
func runBuild(goos, goarch, binariesString string) {
//Check required configuration
if len(strings.TrimSpace(config.Repository.Path)) == 0 {
log.Fatalf("missing required '%s' configuration", "repository.path")
Expand Down Expand Up @@ -126,19 +179,51 @@ func runBuild(binariesString string) {
}
defer os.Unsetenv("CGO_ENABLED")

var binariesToBuild []Binary

if binariesString == "all" {
buildAll(ext, prefix, ldflags, binaries)
return
}
binariesToBuild = binaries
} else {
var err error
binariesArray := strings.Split(binariesString, ",")
binariesToBuild, err = validateBinaryNames(binariesArray, binaries)

binariesArray := strings.Split(binariesString, ",")
binariesToBuild, err := validateBinaryNames(binariesArray, binaries)
if err != nil {
fatal(errors.Wrap(err, "validation of given binary names for build command failed"))
if err != nil {
fatal(errors.Wrap(err, "validation of given binary names for build command failed"))
}
}

sem := make(chan struct{}, *binaryJobs)
done := make(chan struct{})
errs := make([]error, 0, len(binariesToBuild))

for _, binary := range binariesToBuild {
buildBinary(ext, prefix, ldflags, binary)
sem <- struct{}{}

go func(binary Binary) {
err := buildBinary(goos, goarch, ext, prefix, ldflags, binary)

if err != nil {
errs = append(errs, err)
}

done <- <-sem
}(binary)
}

// Wait for builds to finish
for range done {
if len(done) == 0 && len(sem) == 0 {
close(done)
}
}

if len(errs) > 0 {
for _, err := range errs {
printErr(err)
}

fatal(errors.New("Build failed"))
}
}

Expand Down
Loading