Skip to content

Commit 2a4c12f

Browse files
nmittlerimjasonh
authored andcommitted
Add global flags and ldflags
Fixes #1304
1 parent c42ee5f commit 2a4c12f

File tree

8 files changed

+165
-25
lines changed

8 files changed

+165
-25
lines changed

docs/configuration.md

+25
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,31 @@ For a given build, the environment variables are merged in the following order:
147147
- Global `env`
148148
- Build `env` (highest precedence)
149149

150+
### Setting build flags and ldflags
151+
152+
You can specify both `flags` and `ldflags` globally as well as per-build.
153+
154+
```yaml
155+
flags:
156+
- -v
157+
ldflags:
158+
- -s
159+
builds:
160+
- id: foo
161+
dir: .
162+
main: ./foobar/foo
163+
flags:
164+
- -trimpath # Build will use: -v -trimpath
165+
ldflags:
166+
- -w # Build will use: -s -w
167+
- id: bar
168+
dir: ./bar
169+
main: .
170+
```
171+
172+
The values for each `build` will be appended to the global values when creating each build.
173+
Both global and per-build values may use [template parameters](#templating-support).
174+
150175
### Environment Variables (advanced)
151176

152177
For ease of use, backward compatibility and advanced use cases, `ko` supports the following environment variables to

pkg/build/gobuild.go

+34-16
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,13 @@ type GetBase func(context.Context, string) (name.Reference, Result, error)
6666

6767
// buildContext provides parameters for a builder function.
6868
type buildContext struct {
69-
creationTime v1.Time
70-
ip string
71-
dir string
72-
mergedEnv []string
73-
platform v1.Platform
74-
config Config
69+
creationTime v1.Time
70+
ip string
71+
dir string
72+
mergedEnv []string
73+
mergedFlags []string
74+
mergedLdflags []string
75+
platform v1.Platform
7576
}
7677

7778
type builder func(context.Context, buildContext) (string, error)
@@ -95,6 +96,8 @@ type gobuild struct {
9596
trimpath bool
9697
buildConfigs map[string]Config
9798
env []string
99+
flags []string
100+
ldflags []string
98101
platformMatcher *platformMatcher
99102
dir string
100103
labels map[string]string
@@ -118,6 +121,8 @@ type gobuildOpener struct {
118121
trimpath bool
119122
buildConfigs map[string]Config
120123
env []string
124+
flags []string
125+
ldflags []string
121126
platforms []string
122127
labels map[string]string
123128
dir string
@@ -147,6 +152,8 @@ func (gbo *gobuildOpener) Open() (Interface, error) {
147152
trimpath: gbo.trimpath,
148153
buildConfigs: gbo.buildConfigs,
149154
env: gbo.env,
155+
flags: gbo.flags,
156+
ldflags: gbo.ldflags,
150157
labels: gbo.labels,
151158
dir: gbo.dir,
152159
platformMatcher: matcher,
@@ -830,17 +837,17 @@ func createBuildArgs(ctx context.Context, buildCtx buildContext) ([]string, erro
830837
return nil, err
831838
}
832839

833-
if len(buildCtx.config.Flags) > 0 {
834-
flags, err := applyTemplating(buildCtx.config.Flags, data)
840+
if len(buildCtx.mergedFlags) > 0 {
841+
flags, err := applyTemplating(buildCtx.mergedFlags, data)
835842
if err != nil {
836843
return nil, err
837844
}
838845

839846
args = append(args, flags...)
840847
}
841848

842-
if len(buildCtx.config.Ldflags) > 0 {
843-
ldflags, err := applyTemplating(buildCtx.config.Ldflags, data)
849+
if len(buildCtx.mergedLdflags) > 0 {
850+
ldflags, err := applyTemplating(buildCtx.mergedLdflags, data)
844851
if err != nil {
845852
return nil, err
846853
}
@@ -927,14 +934,25 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl
927934
return nil, fmt.Errorf("could not create env for %s: %w", ref.Path(), err)
928935
}
929936

937+
// Merge global and build config flags.
938+
var mergedFlags []string
939+
mergedFlags = append(mergedFlags, g.flags...)
940+
mergedFlags = append(mergedFlags, config.Flags...)
941+
942+
// Merge global and build config ldflags.
943+
var mergedLdflags []string
944+
mergedLdflags = append(mergedLdflags, g.ldflags...)
945+
mergedLdflags = append(mergedLdflags, config.Ldflags...)
946+
930947
// Do the build into a temporary file.
931948
file, err := g.build(ctx, buildContext{
932-
creationTime: g.creationTime,
933-
ip: ref.Path(),
934-
dir: g.dir,
935-
mergedEnv: mergedEnv,
936-
platform: *platform,
937-
config: config,
949+
creationTime: g.creationTime,
950+
ip: ref.Path(),
951+
dir: g.dir,
952+
mergedEnv: mergedEnv,
953+
mergedFlags: mergedFlags,
954+
mergedLdflags: mergedLdflags,
955+
platform: *platform,
938956
})
939957
if err != nil {
940958
return nil, fmt.Errorf("build: %w", err)

pkg/build/gobuild_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,55 @@ func TestGoBuild(t *testing.T) {
915915
})
916916
}
917917

918+
func TestGoBuildMergedValues(t *testing.T) {
919+
baseLayers := int64(3)
920+
base, err := random.Image(1024, baseLayers)
921+
if err != nil {
922+
t.Fatalf("random.Image() = %v", err)
923+
}
924+
importpath := "github.com/google/ko"
925+
926+
creationTime := v1.Time{Time: time.Unix(5000, 0)}
927+
var buildCtx buildContext
928+
ng, err := NewGo(
929+
context.Background(),
930+
"",
931+
WithCreationTime(creationTime),
932+
WithBaseImages(func(context.Context, string) (name.Reference, Result, error) { return baseRef, base, nil }),
933+
withBuilder(func(_ context.Context, b buildContext) (string, error) {
934+
buildCtx = b
935+
return "", errors.New("fake build error")
936+
}),
937+
withSBOMber(fauxSBOM),
938+
WithPlatforms("all"),
939+
WithEnv([]string{"FOO=foo", "BAR=bar"}),
940+
WithFlags([]string{"-v"}),
941+
WithLdflags([]string{"-s"}),
942+
WithConfig(map[string]Config{
943+
"github.com/google/ko/test": {
944+
Env: StringArray{"FOO=baz"},
945+
Flags: FlagArray{"-trimpath"},
946+
Ldflags: StringArray{"-w"},
947+
},
948+
}),
949+
)
950+
require.NoError(t, err)
951+
952+
// Build and capture the buildContext.
953+
_, err = ng.Build(context.Background(), StrictScheme+filepath.Join(importpath, "test"))
954+
require.ErrorContains(t, err, "fake build error")
955+
require.Equal(t, []string{"-v", "-trimpath"}, buildCtx.mergedFlags)
956+
require.Equal(t, []string{"-s", "-w"}, buildCtx.mergedLdflags)
957+
958+
envVars := make(map[string]string)
959+
for _, val := range buildCtx.mergedEnv {
960+
kv := strings.SplitN(val, "=", 2)
961+
envVars[kv[0]] = kv[1]
962+
}
963+
require.Equal(t, "baz", envVars["FOO"])
964+
require.Equal(t, "bar", envVars["BAR"])
965+
}
966+
918967
func TestGoBuildWithKOCACHE(t *testing.T) {
919968
now := time.Now() // current local time
920969
sec := now.Unix()

pkg/build/options.go

+16
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,22 @@ func WithEnv(env []string) Option {
9494
}
9595
}
9696

97+
// WithFlags is a functional option for providing a global set of flags across all builds.
98+
func WithFlags(flags []string) Option {
99+
return func(gbo *gobuildOpener) error {
100+
gbo.flags = flags
101+
return nil
102+
}
103+
}
104+
105+
// WithLdflags is a functional option for providing a global set of ldflags across all builds.
106+
func WithLdflags(ldflags []string) Option {
107+
return func(gbo *gobuildOpener) error {
108+
gbo.ldflags = ldflags
109+
return nil
110+
}
111+
}
112+
97113
// WithPlatforms is a functional option for building certain platforms for
98114
// multi-platform base images. To build everything from the base, use "all",
99115
// otherwise use a list of platform specs, i.e.:

pkg/commands/options/build.go

+16-4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ type BuildOptions struct {
5050
// Env allows setting environment variables globally and applying them to each build.
5151
Env []string
5252

53+
// Flags allows setting flags globally and applying them to each build.
54+
Flags []string
55+
56+
// Ldflags allows setting ldflags globally and applying them to each build.
57+
Ldflags []string
58+
5359
// WorkingDirectory allows for setting the working directory for invocations of the `go` tool.
5460
// Empty string means the current working directory.
5561
WorkingDirectory string
@@ -136,16 +142,22 @@ func (bo *BuildOptions) LoadConfig() error {
136142
}
137143
}
138144

139-
dp := v.GetStringSlice("defaultPlatforms")
140-
if len(dp) > 0 {
145+
if dp := v.GetStringSlice("defaultPlatforms"); len(dp) > 0 {
141146
bo.DefaultPlatforms = dp
142147
}
143148

144-
env := v.GetStringSlice("env")
145-
if len(env) > 0 {
149+
if env := v.GetStringSlice("env"); len(env) > 0 {
146150
bo.Env = env
147151
}
148152

153+
if flags := v.GetStringSlice("flags"); len(flags) > 0 {
154+
bo.Flags = flags
155+
}
156+
157+
if ldflags := v.GetStringSlice("ldflags"); len(ldflags) > 0 {
158+
bo.Ldflags = ldflags
159+
}
160+
149161
if bo.BaseImage == "" {
150162
ref := v.GetString("defaultBaseImage")
151163
if _, err := name.ParseReference(ref); err != nil {

pkg/commands/options/build_test.go

+18-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/google/ko/pkg/build"
2424
"github.com/spf13/cobra"
25+
"github.com/stretchr/testify/require"
2526
)
2627

2728
func TestDefaultBaseImage(t *testing.T) {
@@ -72,14 +73,26 @@ func TestEnv(t *testing.T) {
7273
WorkingDirectory: "testdata/config",
7374
}
7475
err := bo.LoadConfig()
75-
if err != nil {
76-
t.Fatal(err)
76+
require.NoError(t, err)
77+
require.Equal(t, []string{"FOO=bar"}, bo.Env)
78+
}
79+
80+
func TestFlags(t *testing.T) {
81+
bo := &BuildOptions{
82+
WorkingDirectory: "testdata/config",
7783
}
84+
err := bo.LoadConfig()
85+
require.NoError(t, err)
86+
require.Equal(t, []string{"-tags", "netgo"}, bo.Flags)
87+
}
7888

79-
wantEnv := []string{"FOO=bar"} // matches value in ./testdata/config/.ko.yaml
80-
if !reflect.DeepEqual(bo.Env, wantEnv) {
81-
t.Fatalf("wanted Env %s, got %s", wantEnv, bo.Env)
89+
func TestLDFlags(t *testing.T) {
90+
bo := &BuildOptions{
91+
WorkingDirectory: "testdata/config",
8292
}
93+
err := bo.LoadConfig()
94+
require.NoError(t, err)
95+
require.Equal(t, []string{"-s -w"}, bo.Ldflags)
8396
}
8497

8598
func TestBuildConfigWithWorkingDirectoryAndDirAndMain(t *testing.T) {
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
defaultBaseImage: alpine
22
defaultPlatforms: all
33
env: FOO=bar
4+
flags:
5+
- -tags
6+
- netgo
7+
ldflags:
8+
- -s -w

pkg/commands/resolver.go

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ func gobuildOptions(bo *options.BuildOptions) ([]build.Option, error) {
8787
opts := []build.Option{
8888
build.WithBaseImages(getBaseImage(bo)),
8989
build.WithEnv(bo.Env),
90+
build.WithFlags(bo.Flags),
91+
build.WithLdflags(bo.Ldflags),
9092
build.WithPlatforms(bo.Platforms...),
9193
build.WithJobs(bo.ConcurrentBuilds),
9294
}

0 commit comments

Comments
 (0)