Skip to content

Commit a83256f

Browse files
committed
First take
1 parent f76daa1 commit a83256f

File tree

14 files changed

+302
-22
lines changed

14 files changed

+302
-22
lines changed

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*.so
66
*.dylib
77

8+
.DS_Store
9+
810
# Test binary, built with `go test -c`
911
*.test
1012

‎README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
[![Tests on Linux, MacOS and Windows](https://github.com/bep/golibtemplate/workflows/Test/badge.svg)](https://github.com/bep/golibtemplate/actions?query=workflow:Test)
2-
[![Go Report Card](https://goreportcard.com/badge/github.com/bep/golibtemplate)](https://goreportcard.com/report/github.com/bep/golibtemplate)
3-
[![GoDoc](https://godoc.org/github.com/bep/golibtemplate?status.svg)](https://godoc.org/github.com/bep/golibtemplate)
1+
[![Tests on Linux, MacOS and Windows](https://github.com/bep/buildpkg/workflows/Test/badge.svg)](https://github.com/bep/buildpkg/actions?query=workflow:Test)
2+
[![Go Report Card](https://goreportcard.com/badge/github.com/bep/buildpkg)](https://goreportcard.com/report/github.com/bep/buildpkg)
3+
[![GoDoc](https://godoc.org/github.com/bep/buildpkg?status.svg)](https://godoc.org/github.com/bep/buildpkg)

‎build.go‎

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package buildpkg
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
"path/filepath"
8+
9+
"github.com/bep/macosnotarylib"
10+
"github.com/golang-jwt/jwt/v4"
11+
)
12+
13+
// New creates a new Builder.
14+
func New(opts Options) (*Builder, error) {
15+
if err := opts.init(); err != nil {
16+
return nil, err
17+
}
18+
return &Builder{Options: opts}, nil
19+
}
20+
21+
type Builder struct {
22+
Options
23+
}
24+
25+
// Build signs the binary, builds the package and signs and notarizes and staples it.
26+
// It' currently limited to 1 file only.
27+
// The notarization part requires the following environment variables to be set:
28+
// - MACOSNOTARYLIB_ISSUER_ID
29+
// - MACOSNOTARYLIB_KID
30+
// - MACOSNOTARYLIB_PRIVATE_KEY (in base64 format).
31+
func (b *Builder) Build() error {
32+
files, err := os.ReadDir(b.StagingDirectory)
33+
if err != nil {
34+
return err
35+
}
36+
if len(files) != 1 || files[0].IsDir() {
37+
return fmt.Errorf("opts: StagingDirectory must contain exactly one file")
38+
}
39+
40+
if !b.SkipCodeSigning {
41+
for _, fi := range files {
42+
if err := b.runCommand("codesign", "-s", b.SigningIdentity, "--options=runtime", filepath.Join(b.StagingDirectory, fi.Name())); err != nil {
43+
return err
44+
}
45+
}
46+
}
47+
48+
tempPackageOutputPath := b.PackageOutputPath + ".tmp"
49+
50+
args := []string{
51+
"--root", b.StagingDirectory,
52+
"--identifier", b.Identifier,
53+
"--version", b.Version,
54+
"--install-location", b.InstallLocation,
55+
}
56+
57+
if b.ScriptsDirectory != "" {
58+
args = append(args, "--scripts", b.ScriptsDirectory)
59+
}
60+
61+
if b.SkipInstallerSigning {
62+
tempPackageOutputPath = b.PackageOutputPath
63+
}
64+
65+
args = append(args, tempPackageOutputPath)
66+
67+
if err := b.runCommand("pkgbuild", args...); err != nil {
68+
return err
69+
}
70+
71+
if !b.SkipInstallerSigning {
72+
// Sign the package
73+
if err := b.runCommand("productsign", "--sign", b.SigningIdentity, tempPackageOutputPath, b.PackageOutputPath); err != nil {
74+
return err
75+
}
76+
77+
if err := os.Remove(filepath.Join(b.Dir, tempPackageOutputPath)); err != nil {
78+
return err
79+
}
80+
81+
// Check the package signature.
82+
if err := b.runCommand("pkgutil", "--check-signature", b.PackageOutputPath); err != nil {
83+
return err
84+
}
85+
}
86+
87+
if !b.SkipNotarization {
88+
// Notarize the package.
89+
if err := b.notarizePackage(filepath.Join("testdata", b.PackageOutputPath)); err != nil {
90+
return err
91+
}
92+
93+
// Staple the package.
94+
if err := b.runCommand("stapler", "staple", b.PackageOutputPath); err != nil {
95+
return err
96+
}
97+
}
98+
99+
return nil
100+
}
101+
102+
func (b *Builder) notarizePackage(filename string) error {
103+
issuerID := os.Getenv("MACOSNOTARYLIB_ISSUER_ID")
104+
105+
kid := os.Getenv("MACOSNOTARYLIB_KID")
106+
if kid == "" || issuerID == "" {
107+
return fmt.Errorf("env: MACOSNOTARYLIB_ISSUER_ID and MACOSNOTARYLIB_KID must be set")
108+
}
109+
110+
// This test also depends on the private key from env MACOSNOTARYLIB_PRIVATE_KEY in base64 format. See below.
111+
112+
n, err := macosnotarylib.New(
113+
macosnotarylib.Options{
114+
InfoLoggerf: b.Infof,
115+
IssuerID: issuerID,
116+
Kid: kid,
117+
SignFunc: func(token *jwt.Token) (string, error) {
118+
key, err := macosnotarylib.LoadPrivateKeyFromEnvBase64("MACOSNOTARYLIB_PRIVATE_KEY")
119+
if err != nil {
120+
return "", err
121+
}
122+
return token.SignedString(key)
123+
},
124+
},
125+
)
126+
127+
if err != nil {
128+
return err
129+
}
130+
131+
return n.Submit(filename)
132+
133+
}
134+
135+
func (b *Builder) runCommand(name string, args ...string) error {
136+
fmt.Println(name, args)
137+
cmd := exec.Command(name, args...)
138+
cmd.Dir = b.Dir
139+
cmd.Stdout = os.Stdout
140+
cmd.Stderr = os.Stderr
141+
return cmd.Run()
142+
}
143+
144+
type Options struct {
145+
// The Info logger.
146+
// If nil, no Info logging will be done.
147+
Infof func(format string, a ...interface{})
148+
149+
// The Dir to build from.
150+
Dir string
151+
152+
// Developer ID Application + Developer ID Installer
153+
// https://developer.apple.com/account/resources/certificates/list
154+
SigningIdentity string
155+
156+
// The result
157+
PackageOutputPath string
158+
159+
// The staging directory where all your build artifacts are located.
160+
StagingDirectory string
161+
162+
// E.g. io.gohugo.hugo
163+
Identifier string
164+
165+
// E.g. 234
166+
Version string
167+
168+
// E.g. /Applications
169+
InstallLocation string
170+
171+
// Scripts passed on the command line --scripts flag.
172+
// E.g. /mypkgscripts
173+
ScriptsDirectory string
174+
175+
// Flags to enable skipping of build steps.
176+
SkipCodeSigning bool
177+
SkipInstallerSigning bool
178+
SkipNotarization bool
179+
}
180+
181+
func (o *Options) init() error {
182+
if o.Infof == nil {
183+
o.Infof = func(format string, a ...interface{}) {
184+
}
185+
}
186+
if o.SigningIdentity == "" {
187+
return fmt.Errorf("opts: SigningIdentity is required")
188+
}
189+
190+
if o.StagingDirectory == "" {
191+
return fmt.Errorf("opts: StagingDirectory not set")
192+
}
193+
194+
if o.Identifier == "" {
195+
return fmt.Errorf("opts: Identifier not set")
196+
}
197+
198+
if o.Version == "" {
199+
return fmt.Errorf("opts: Version not set")
200+
}
201+
202+
if o.InstallLocation == "" {
203+
return fmt.Errorf("opts: InstallLocation not set")
204+
}
205+
206+
if o.PackageOutputPath == "" {
207+
return fmt.Errorf("opts: PackageOutputPath not set")
208+
}
209+
210+
return nil
211+
}

‎build_test.go‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package buildpkg
2+
3+
import (
4+
"log"
5+
"os"
6+
"testing"
7+
8+
qt "github.com/frankban/quicktest"
9+
)
10+
11+
func TestBuild(t *testing.T) {
12+
if os.Getenv("CI") != "" {
13+
t.Skip("Skipping test on CI")
14+
}
15+
c := qt.New(t)
16+
17+
opts := Options{
18+
Infof: func(format string, args ...interface{}) {
19+
log.Printf(format, args...)
20+
},
21+
Dir: "./testdata",
22+
SigningIdentity: "ZYSJUFSYL4",
23+
StagingDirectory: "./staging",
24+
Identifier: "is.bep.helloworld",
25+
Version: "0.0.13",
26+
InstallLocation: "/usr/local/bin",
27+
PackageOutputPath: "./helloworld.pkg",
28+
SkipCodeSigning: false,
29+
SkipNotarization: false,
30+
SkipInstallerSigning: false,
31+
//ScriptsDirectory: "./testdata/scripts",
32+
}
33+
34+
builder, err := New(opts)
35+
c.Assert(err, qt.IsNil)
36+
c.Assert(builder.runCommand("./prepare.sh", builder.Version), qt.IsNil)
37+
err = builder.Build()
38+
c.Assert(err, qt.IsNil)
39+
40+
}

‎go.mod‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
module github.com/bep/golibtemplate
1+
module github.com/bep/buildpkg
22

33
go 1.18
44

55
require (
6-
github.com/frankban/quicktest v1.14.2 // indirect
6+
github.com/bep/macosnotarylib v0.1.0
7+
github.com/frankban/quicktest v1.14.2
8+
github.com/golang-jwt/jwt/v4 v4.4.3-0.20220820150458-bfea432b1a9d
9+
)
10+
11+
require (
12+
github.com/aws/aws-sdk-go v1.44.86 // indirect
713
github.com/google/go-cmp v0.5.7 // indirect
14+
github.com/jmespath/go-jmespath v0.4.0 // indirect
815
github.com/kr/pretty v0.3.0 // indirect
916
github.com/kr/text v0.2.0 // indirect
1017
github.com/rogpeppe/go-internal v1.6.1 // indirect

‎go.sum‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,45 @@
1+
github.com/aws/aws-sdk-go v1.44.86 h1:Zls97WY9N2c2H85//B88CmSlYYNxS3Zf3k4ds5zAf5A=
2+
github.com/aws/aws-sdk-go v1.44.86/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
3+
github.com/bep/macosnotarylib v0.1.0 h1:3Kl63q2qVx8oyzMKK5UOABlY1EOTW3OHBI3KnPsDwYM=
4+
github.com/bep/macosnotarylib v0.1.0/go.mod h1:oAZa21+u4m1EwFguFx2YmHNkkLrhy1J0kHiNEfdfGPs=
15
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
6+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
7+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
28
github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns=
39
github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
10+
github.com/golang-jwt/jwt/v4 v4.4.3-0.20220820150458-bfea432b1a9d h1:g83sVsMB9c5zW6RG7a767AkmCkAIbQEX6Z7UvEKgTjU=
11+
github.com/golang-jwt/jwt/v4 v4.4.3-0.20220820150458-bfea432b1a9d/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
412
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
513
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
14+
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
15+
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
16+
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
17+
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
618
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
719
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
820
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
921
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
1022
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
1123
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
1224
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
25+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
26+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
27+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1328
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
1429
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
30+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
31+
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
32+
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
33+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
34+
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
35+
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
36+
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
37+
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
38+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
1539
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
1640
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
41+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1742
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1843
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
44+
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
45+
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

‎lib.go‎

Lines changed: 0 additions & 5 deletions
This file was deleted.

‎lib_test.go‎

Lines changed: 0 additions & 12 deletions
This file was deleted.

‎staging/helloworld‎

40.4 KB
Binary file not shown.

‎testdata/bep@100.122.15.86‎

696 KB
Binary file not shown.

0 commit comments

Comments
 (0)