aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.go170
-rw-r--r--main_test.go59
-rw-r--r--platforms.go179
-rw-r--r--platforms_defaults.go75
-rw-r--r--platforms_test.go117
5 files changed, 527 insertions, 73 deletions
diff --git a/main.go b/main.go
index ece5f12..8096ae5 100644
--- a/main.go
+++ b/main.go
@@ -10,45 +10,12 @@ import (
"os/exec"
"path/filepath"
"runtime"
+ "strings"
+ bflag "github.com/terinjokes/bakelite/internal/flag"
"golang.org/x/sync/semaphore"
)
-type Arch string
-
-const (
- ARCH_AMD64 Arch = "amd64"
- ARCH_386 Arch = "386"
- ARCH_ARM Arch = "arm"
- ARCH_ARM64 Arch = "arm64"
- ARCH_PPC64 Arch = "ppc64"
- ARCH_PPC64LE Arch = "ppc64le"
- ARCH_MIPS Arch = "mips"
- ARCH_MIPSLE Arch = "mipsle"
- ARCH_MIPS64 Arch = "mips64"
- ARCH_MIPS64LE Arch = "mips64le"
-)
-
-type OS string
-
-const (
- OS_ANDROID OS = "android"
- OS_DARWIN OS = "darwin"
- OS_DRAGONFLY OS = "dragonfly"
- OS_FREEBSD OS = "freebsd"
- OS_LINUX OS = "linux"
- OS_NETBSD OS = "netbsd"
- OS_OPENBSD OS = "openbsd"
- OS_PLAN9 OS = "plan9"
- OS_SOLARIS OS = "solaris"
- OS_WINDOWS OS = "windows"
-)
-
-type Platform struct {
- OS OS
- Arch Arch
-}
-
type kvs map[string]string
func (o kvs) Strings() []string {
@@ -62,46 +29,13 @@ func (o kvs) Strings() []string {
var cgo bool
var ldflags string
+var platformFields []string
func main() {
- // TODO: enable ARM after supporting GOARM
- // TODO: probably should make this configurable…
- platforms := []Platform{
- //{OS_ANDROID, ARCH_ARM},
- {OS_DARWIN, ARCH_386},
- {OS_DARWIN, ARCH_AMD64},
- //{OS_DARWIN, ARCH_ARM},
- //{OS_DARWIN, ARCH_ARM64},
- {OS_DRAGONFLY, ARCH_AMD64},
- {OS_FREEBSD, ARCH_386},
- {OS_FREEBSD, ARCH_AMD64},
- //{OS_FREEBSD, ARCH_ARM},
- {OS_LINUX, ARCH_386},
- {OS_LINUX, ARCH_AMD64},
- //{OS_LINUX, ARCH_ARM},
- //{OS_LINUX, ARCH_ARM64},
- {OS_LINUX, ARCH_PPC64},
- {OS_LINUX, ARCH_PPC64LE},
- {OS_LINUX, ARCH_MIPS},
- {OS_LINUX, ARCH_MIPSLE},
- {OS_LINUX, ARCH_MIPS64},
- {OS_LINUX, ARCH_MIPS64LE},
- {OS_NETBSD, ARCH_386},
- {OS_NETBSD, ARCH_AMD64},
- //{OS_NETBSD, ARCH_ARM},
- {OS_OPENBSD, ARCH_386},
- {OS_OPENBSD, ARCH_AMD64},
- //{OS_OPENBSD, ARCH_ARM},
- {OS_PLAN9, ARCH_386},
- {OS_PLAN9, ARCH_AMD64},
- {OS_SOLARIS, ARCH_AMD64},
- {OS_WINDOWS, ARCH_386},
- {OS_WINDOWS, ARCH_AMD64},
- }
-
flags := flag.NewFlagSet("bakelite", flag.ExitOnError)
flags.BoolVar(&cgo, "cgo", false, "enables cgo (may require your own toolchain).")
flags.StringVar(&ldflags, "ldflags", "", "arguments to pass on each go tool compile invocation.")
+ flags.Var((*bflag.StringsValue)(&platformFields), "platforms", "modify the list of platforms built")
flags.Usage = func() {
fmt.Println("usage: bakelite [build flags] [packages]")
fmt.Println(`
@@ -124,8 +58,42 @@ The Bakelite specific flags:
-cgo
passes CGO_ENABLED=1 to the build environment.
- May require a build toolchain for each GOOS and GOARCH
- combination.
+ May require a build toolchain for each GOOS and GOARCH combination.
+ -platforms 'platform list'
+ modify the built platforms.
+ Platforms are prefixed with "-" to remove from the set and "+" to add
+ to the set. They can be specified sparsely as just the OS, or as a
+ complete GOOS/GOARCH declaration. If the special platform "-" is
+ provided as the first platform, the default set is disabled. See below
+ for the default list of platforms.
+
+By default Bakelite builds for the following platforms:
+
+ darwin/386
+ darwin/amd64
+ dragonfly/amd64
+ freebsd/386
+ freebsd/amd64
+ linux/386
+ linux/amd64
+ linux/ppc64
+ linux/ppc64le
+ linux/mips
+ linux/mipsle
+ linux/mips64
+ linux/mips64le
+ netbsd/386
+ netbsd/amd64
+ openbsd/386
+ openbsd/amd64
+ plan9/386
+ plan9/amd64
+ solaris/amd64
+ windows/386
+ windows/amd64
+
+All the flags that take a list of arguments accept a space-separated
+list of strings.
For more about specifying packages, see 'go help packages'.
For more about calling between Go and C/C++, run 'go help c'.
@@ -144,6 +112,18 @@ See also: go build, go install, go clean.
os.Exit(-1)
}
+ plBuilder, _ := NewPlatformBuilder()
+ if len(platformFields) > 0 && platformFields[0] == "-" {
+ platformFields = platformFields[1:]
+ } else {
+ plBuilder = plBuilder.WithDefaults()
+ }
+ if len(platformFields) != 0 {
+ plBuilder = parsePlatforms(plBuilder, platformFields)
+ }
+
+ platforms := plBuilder.Build()
+
var (
parallelJobs = runtime.NumCPU()
sem = semaphore.NewWeighted(int64(parallelJobs))
@@ -152,22 +132,33 @@ See also: go build, go install, go clean.
fmt.Printf("info: running bakelite with %d jobs\n", parallelJobs)
+ var errored bool
for _, platform := range platforms {
for _, pkg := range packages {
if err := sem.Acquire(ctx, 1); err != nil {
log.Printf("failed to acquire semaphore: %s", err)
+ errored = true
break
}
go func(platform Platform, pkg string) {
defer sem.Release(1)
- build(ctx, platform, pkg)
+ err := build(ctx, platform, pkg)
+
+ if err != nil {
+ errored = true
+ }
}(platform, pkg)
}
}
if err := sem.Acquire(ctx, int64(parallelJobs)); err != nil {
log.Printf("failed to acquire semaphore: %s", err)
+ errored = true
+ }
+
+ if errored {
+ os.Exit(1)
}
}
@@ -220,3 +211,36 @@ func build(ctx context.Context, platform Platform, pkg string) error {
return err
}
+
+func parsePlatforms(plBuilder *PlatformBuilder, fields []string) *PlatformBuilder {
+ for _, f := range fields {
+ switch f[0] {
+ case '-':
+ if strings.ContainsRune(f, '/') {
+ sp := strings.Split(f[1:], "/")
+ p := Platform{
+ OS: OS(sp[0]),
+ Arch: Arch(sp[1]),
+ }
+
+ plBuilder = plBuilder.WithoutPlatform(p)
+ } else {
+ plBuilder = plBuilder.WithoutOS(OS(f[1:]))
+ }
+ case '+':
+ if strings.ContainsRune(f, '/') {
+ sp := strings.Split(f[1:], "/")
+ p := Platform{
+ OS: OS(sp[0]),
+ Arch: Arch(sp[1]),
+ }
+
+ plBuilder = plBuilder.WithPlatform(p)
+ } else {
+ plBuilder = plBuilder.WithOS(OS(f[1:]))
+ }
+ }
+ }
+
+ return plBuilder
+}
diff --git a/main_test.go b/main_test.go
new file mode 100644
index 0000000..4d3e91e
--- /dev/null
+++ b/main_test.go
@@ -0,0 +1,59 @@
+package main
+
+import (
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
+)
+
+func TestParsePlatforms(t *testing.T) {
+ fields := []string{"+windows", "+plan9", "-windows/386"}
+ plb, _ := NewPlatformBuilder()
+
+ plb = parsePlatforms(plb, fields)
+
+ pl := plb.Build()
+ expected := []Platform{
+ {OS("windows"), Arch("amd64")},
+ {OS("plan9"), Arch("386")},
+ {OS("plan9"), Arch("amd64")},
+ }
+
+ if diff := cmp.Diff(expected, pl, cmpopts.SortSlices(lessPlatforms)); diff != "" {
+ t.Errorf("manifest differs. (-got +want):\n%s", diff)
+ }
+}
+
+func TestParsePlatformsRemoveOS(t *testing.T) {
+ fields := []string{"+windows", "+plan9", "-windows"}
+ plb, _ := NewPlatformBuilder()
+
+ plb = parsePlatforms(plb, fields)
+
+ pl := plb.Build()
+ expected := []Platform{
+ {OS("plan9"), Arch("386")},
+ {OS("plan9"), Arch("amd64")},
+ }
+
+ if diff := cmp.Diff(expected, pl, cmpopts.SortSlices(lessPlatforms)); diff != "" {
+ t.Errorf("manifest differs. (-got +want):\n%s", diff)
+ }
+}
+func TestParsePlatformRemoveNothing(t *testing.T) {
+ fields := []string{"+windows", "-"}
+ plb, _ := NewPlatformBuilder()
+
+ plb = parsePlatforms(plb, fields)
+
+ pl := plb.Build()
+ expected := []Platform{
+ {OS("windows"), Arch("amd64")},
+ {OS("windows"), Arch("386")},
+ }
+
+ if diff := cmp.Diff(expected, pl, cmpopts.SortSlices(lessPlatforms)); diff != "" {
+ t.Errorf("manifest differs. (-got +want):\n%s", diff)
+ }
+}
diff --git a/platforms.go b/platforms.go
new file mode 100644
index 0000000..9c0a572
--- /dev/null
+++ b/platforms.go
@@ -0,0 +1,179 @@
+package main
+
+// Arch represents a Go Arch.
+type Arch string
+
+const (
+ ARCH_AMD64 Arch = "amd64"
+ ARCH_386 Arch = "386"
+ ARCH_ARM Arch = "arm"
+ ARCH_ARM64 Arch = "arm64"
+ ARCH_PPC64 Arch = "ppc64"
+ ARCH_PPC64LE Arch = "ppc64le"
+ ARCH_MIPS Arch = "mips"
+ ARCH_MIPSLE Arch = "mipsle"
+ ARCH_MIPS64 Arch = "mips64"
+ ARCH_MIPS64LE Arch = "mips64le"
+)
+
+// OS represents a Go OS.
+type OS string
+
+const (
+ OS_ANDROID OS = "android"
+ OS_DARWIN OS = "darwin"
+ OS_DRAGONFLY OS = "dragonfly"
+ OS_FREEBSD OS = "freebsd"
+ OS_LINUX OS = "linux"
+ OS_NETBSD OS = "netbsd"
+ OS_OPENBSD OS = "openbsd"
+ OS_PLAN9 OS = "plan9"
+ OS_SOLARIS OS = "solaris"
+ OS_WINDOWS OS = "windows"
+)
+
+// Platform represents an OS/Arch combination.
+type Platform struct {
+ OS OS
+ Arch Arch
+}
+
+// PlatformBuilder provides a fluent way to build up (or tear down) a list of
+// Go platforms. The built list of platforms can be retrieved from the Build method
+// of a returned builder.
+type PlatformBuilder struct {
+ platforms map[Platform]bool
+}
+
+// NewPlatformBuilder returns a PlatformBuilder with no platforms configured.
+func NewPlatformBuilder() (*PlatformBuilder, error) {
+ return &PlatformBuilder{
+ platforms: make(map[Platform]bool),
+ }, nil
+}
+
+// WithoutPlatform returns a new PlatformBuilder with platform removed.
+func (p *PlatformBuilder) WithoutPlatform(platform Platform) *PlatformBuilder {
+ pm := make(map[Platform]bool)
+
+ for k, v := range p.platforms {
+ if k != platform {
+ pm[k] = v
+ }
+ }
+
+ return &PlatformBuilder{
+ platforms: pm,
+ }
+}
+
+// WithoutOS returns a new PlatformBuilder with all platforms of the OS's
+// platforms removed.
+func (p *PlatformBuilder) WithoutOS(os OS) *PlatformBuilder {
+ pm := make(map[Platform]bool)
+
+ for k, v := range p.platforms {
+ if k.OS != os {
+ pm[k] = v
+ }
+ }
+
+ return &PlatformBuilder{
+ platforms: pm,
+ }
+}
+
+// WithPlatform returns a new PlatformBuilder with the platform added.
+func (p *PlatformBuilder) WithPlatform(platform Platform) *PlatformBuilder {
+ pm := make(map[Platform]bool)
+
+ for k, v := range p.platforms {
+ pm[k] = v
+ }
+
+ pm[platform] = true
+
+ return &PlatformBuilder{
+ platforms: pm,
+ }
+}
+
+// WithOS returns a new PlatformBuilder with the OS's default platforms added.
+func (p *PlatformBuilder) WithOS(os OS) *PlatformBuilder {
+ pm := make(map[Platform]bool)
+
+ for k, v := range p.platforms {
+ pm[k] = v
+ }
+
+ var pl []Platform
+ switch os {
+ case OS_DARWIN:
+ pl = defaultDarwin()
+ case OS_DRAGONFLY:
+ pl = defaultDragonfly()
+ case OS_FREEBSD:
+ pl = defaultFreeBSD()
+ case OS_LINUX:
+ pl = defaultLinux()
+ case OS_NETBSD:
+ pl = defaultNetBSD()
+ case OS_OPENBSD:
+ pl = defaultOpenBSD()
+ case OS_PLAN9:
+ pl = defaultPlan9()
+ case OS_SOLARIS:
+ pl = defaultSolaris()
+ case OS_WINDOWS:
+ pl = defaultWindows()
+ default:
+ pl = []Platform{}
+ }
+
+ for _, k := range pl {
+ pm[k] = true
+ }
+
+ return &PlatformBuilder{
+ platforms: pm,
+ }
+}
+
+// WithDefaults returns a new PlatformBuilder with just Bakelite's default
+// platforms.
+func (p *PlatformBuilder) WithDefaults() *PlatformBuilder {
+ pm := make(map[Platform]bool)
+
+ pls := []Platform{
+ //{OS_ANDROID, ARCH_ARM},
+ }
+
+ pls = append(pls, defaultDarwin()...)
+ pls = append(pls, defaultDragonfly()...)
+ pls = append(pls, defaultFreeBSD()...)
+ pls = append(pls, defaultLinux()...)
+ pls = append(pls, defaultNetBSD()...)
+ pls = append(pls, defaultOpenBSD()...)
+ pls = append(pls, defaultPlan9()...)
+ pls = append(pls, defaultSolaris()...)
+ pls = append(pls, defaultWindows()...)
+
+ for _, k := range pls {
+ pm[k] = true
+ }
+
+ return &PlatformBuilder{
+ platforms: pm,
+ }
+}
+
+// Build returns a new list of Platforms.
+func (p *PlatformBuilder) Build() []Platform {
+ pl := []Platform{}
+
+ for k, _ := range p.platforms {
+ pl = append(pl, k)
+ }
+
+ return pl
+}
diff --git a/platforms_defaults.go b/platforms_defaults.go
new file mode 100644
index 0000000..9219071
--- /dev/null
+++ b/platforms_defaults.go
@@ -0,0 +1,75 @@
+package main
+
+func defaultDarwin() []Platform {
+ return []Platform{
+ {OS_DARWIN, ARCH_386},
+ {OS_DARWIN, ARCH_AMD64},
+ //{OS_DARWIN, ARCH_ARM},
+ //{OS_DARWIN, ARCH_ARM64},
+ }
+}
+
+func defaultDragonfly() []Platform {
+ return []Platform{
+ {OS_DRAGONFLY, ARCH_AMD64},
+ }
+}
+
+func defaultFreeBSD() []Platform {
+ return []Platform{
+ {OS_FREEBSD, ARCH_386},
+ {OS_FREEBSD, ARCH_AMD64},
+ //{OS_FREEBSD, ARCH_ARM},
+ }
+}
+
+func defaultLinux() []Platform {
+ return []Platform{
+ {OS_LINUX, ARCH_386},
+ {OS_LINUX, ARCH_AMD64},
+ //{OS_LINUX, ARCH_ARM},
+ //{OS_LINUX, ARCH_ARM64},
+ {OS_LINUX, ARCH_PPC64},
+ {OS_LINUX, ARCH_PPC64LE},
+ {OS_LINUX, ARCH_MIPS},
+ {OS_LINUX, ARCH_MIPSLE},
+ {OS_LINUX, ARCH_MIPS64},
+ {OS_LINUX, ARCH_MIPS64LE},
+ }
+}
+
+func defaultNetBSD() []Platform {
+ return []Platform{
+ {OS_NETBSD, ARCH_386},
+ {OS_NETBSD, ARCH_AMD64},
+ //{OS_NETBSD, ARCH_ARM},
+ }
+}
+
+func defaultOpenBSD() []Platform {
+ return []Platform{
+ {OS_OPENBSD, ARCH_386},
+ {OS_OPENBSD, ARCH_AMD64},
+ //{OS_OPENBSD, ARCH_ARM},
+ }
+}
+
+func defaultPlan9() []Platform {
+ return []Platform{
+ {OS_PLAN9, ARCH_386},
+ {OS_PLAN9, ARCH_AMD64},
+ }
+}
+
+func defaultSolaris() []Platform {
+ return []Platform{
+ {OS_SOLARIS, ARCH_AMD64},
+ }
+}
+
+func defaultWindows() []Platform {
+ return []Platform{
+ {OS_WINDOWS, ARCH_386},
+ {OS_WINDOWS, ARCH_AMD64},
+ }
+}
diff --git a/platforms_test.go b/platforms_test.go
new file mode 100644
index 0000000..b2fcacc
--- /dev/null
+++ b/platforms_test.go
@@ -0,0 +1,117 @@
+package main
+
+import (
+ "fmt"
+ "sort"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
+)
+
+func ExampleNewPlatformBuilder() {
+ plb, _ := NewPlatformBuilder()
+
+ plb = plb.
+ WithOS(OS("windows")).
+ WithoutPlatform(Platform{OS("windows"), Arch("amd64")}).
+ WithPlatform(Platform{OS("plan9"), Arch("amd64")})
+
+ pl := plb.Build()
+ sort.SliceStable(pl, func(i, j int) bool {
+ return lessPlatforms(pl[i], pl[j])
+ })
+
+ fmt.Println(pl)
+
+ // Output:
+ // [{plan9 amd64} {windows 386}]
+}
+
+func TestWithOS(t *testing.T) {
+ plb, _ := NewPlatformBuilder()
+
+ plb = plb.WithOS(OS("windows"))
+
+ pl := plb.Build()
+ expected := defaultWindows()
+
+ if diff := cmp.Diff(expected, pl, cmpopts.SortSlices(lessPlatforms)); diff != "" {
+ t.Errorf("manifest differs. (-got +want):\n%s", diff)
+ }
+}
+
+func TestWithoutOS(t *testing.T) {
+ plb, _ := NewPlatformBuilder()
+
+ plb = plb.
+ WithPlatform(
+ Platform{OS("windows"), Arch("amd64")},
+ ).
+ WithPlatform(
+ Platform{OS("plan9"), Arch("amd64")},
+ ).
+ WithoutOS(OS("windows"))
+
+ pl := plb.Build()
+ expected := []Platform{{OS("plan9"), Arch("amd64")}}
+
+ if diff := cmp.Diff(expected, pl, cmpopts.SortSlices(lessPlatforms)); diff != "" {
+ t.Errorf("manifest differs. (-got +want):\n%s", diff)
+ }
+}
+
+func TestWithPlatform(t *testing.T) {
+ plb, _ := NewPlatformBuilder()
+
+ plb = plb.WithPlatform(Platform{OS("windows"), Arch("arm64")})
+
+ pl := plb.Build()
+ expected := []Platform{{OS("windows"), Arch("arm64")}}
+
+ if diff := cmp.Diff(expected, pl, cmpopts.SortSlices(lessPlatforms)); diff != "" {
+ t.Errorf("manifest differs. (-got +want):\n%s", diff)
+ }
+}
+
+func TestWithoutPlaform(t *testing.T) {
+ plb, _ := NewPlatformBuilder()
+
+ plb = plb.
+ WithOS(OS("windows")).
+ WithOS(OS("plan9")).
+ WithoutPlatform(Platform{OS("windows"), Arch("386")})
+
+ pl := plb.Build()
+ expected := []Platform{
+ {OS("windows"), Arch("amd64")},
+ {OS("plan9"), Arch("386")},
+ {OS("plan9"), Arch("amd64")},
+ }
+
+ if diff := cmp.Diff(expected, pl, cmpopts.SortSlices(lessPlatforms)); diff != "" {
+ t.Errorf("manifest differs. (-got +want):\n%s", diff)
+ }
+}
+
+func TestWithDefaults(t *testing.T) {
+ plb, _ := NewPlatformBuilder()
+
+ plb = plb.WithDefaults()
+
+ pl := plb.Build()
+
+ if len(pl) == 0 {
+ t.Errorf("expected more defaults!")
+ }
+}
+
+func lessPlatforms(x, y Platform) bool {
+ if x.OS < y.OS {
+ return true
+ }
+ if x.OS > y.OS {
+ return false
+ }
+ return x.Arch < y.Arch
+}