Skip to content

Commit

Permalink
Add global flags and ldflags
Browse files Browse the repository at this point in the history
Fixes #1304
  • Loading branch information
nmittler committed May 15, 2024
1 parent c42ee5f commit 1793fd5
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 25 deletions.
25 changes: 25 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,31 @@ For a given build, the environment variables are merged in the following order:
- Global `env`
- Build `env` (highest precedence)

### Setting build flags and ldflags

You can specify both `flags` and `ldflags` globally as well as per-build.

Check failure on line 152 in docs/configuration.md

View workflow job for this annotation

GitHub Actions / Lint

[trailing whitespace] reported by reviewdog 🐶 You can specify both `flags` and `ldflags` globally as well as per-build. Raw Output: docs/configuration.md:152:You can specify both `flags` and `ldflags` globally as well as per-build.

```yaml
flags:
- -v
ldflags:
- -s
builds:
- id: foo
dir: .
main: ./foobar/foo
flags:
- -trimpath # Build will use: -v -trimpath
ldflags:
- -w # Build will use: -s -w
- id: bar
dir: ./bar
main: .
```

The values for each `build` will be appended to the global values when creating each build.
Both global and per-build values may use [template parameters](#templating-support).

### Environment Variables (advanced)

For ease of use, backward compatibility and advanced use cases, `ko` supports the following environment variables to
Expand Down
50 changes: 34 additions & 16 deletions pkg/build/gobuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ type GetBase func(context.Context, string) (name.Reference, Result, error)

// buildContext provides parameters for a builder function.
type buildContext struct {
creationTime v1.Time
ip string
dir string
mergedEnv []string
platform v1.Platform
config Config
creationTime v1.Time
ip string
dir string
mergedEnv []string
mergedFlags []string
mergedLdflags []string
platform v1.Platform
}

type builder func(context.Context, buildContext) (string, error)
Expand All @@ -95,6 +96,8 @@ type gobuild struct {
trimpath bool
buildConfigs map[string]Config
env []string
flags []string
ldflags []string
platformMatcher *platformMatcher
dir string
labels map[string]string
Expand All @@ -118,6 +121,8 @@ type gobuildOpener struct {
trimpath bool
buildConfigs map[string]Config
env []string
flags []string
ldflags []string
platforms []string
labels map[string]string
dir string
Expand Down Expand Up @@ -147,6 +152,8 @@ func (gbo *gobuildOpener) Open() (Interface, error) {
trimpath: gbo.trimpath,
buildConfigs: gbo.buildConfigs,
env: gbo.env,
flags: gbo.flags,
ldflags: gbo.ldflags,
labels: gbo.labels,
dir: gbo.dir,
platformMatcher: matcher,
Expand Down Expand Up @@ -830,17 +837,17 @@ func createBuildArgs(ctx context.Context, buildCtx buildContext) ([]string, erro
return nil, err
}

if len(buildCtx.config.Flags) > 0 {
flags, err := applyTemplating(buildCtx.config.Flags, data)
if len(buildCtx.mergedFlags) > 0 {
flags, err := applyTemplating(buildCtx.mergedFlags, data)
if err != nil {
return nil, err
}

args = append(args, flags...)
}

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

// Merge global and build config flags.
var mergedFlags []string
mergedFlags = append(mergedFlags, g.flags...)
mergedFlags = append(mergedFlags, config.Flags...)

// Merge global and build config ldflags.
var mergedLdflags []string
mergedLdflags = append(mergedLdflags, g.ldflags...)
mergedLdflags = append(mergedLdflags, config.Ldflags...)

// Do the build into a temporary file.
file, err := g.build(ctx, buildContext{
creationTime: g.creationTime,
ip: ref.Path(),
dir: g.dir,
mergedEnv: mergedEnv,
platform: *platform,
config: config,
creationTime: g.creationTime,
ip: ref.Path(),
dir: g.dir,
mergedEnv: mergedEnv,
mergedFlags: mergedFlags,
mergedLdflags: mergedLdflags,
platform: *platform,
})
if err != nil {
return nil, fmt.Errorf("build: %w", err)
Expand Down
49 changes: 49 additions & 0 deletions pkg/build/gobuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,55 @@ func TestGoBuild(t *testing.T) {
})
}

func TestGoBuildMergedValues(t *testing.T) {
baseLayers := int64(3)
base, err := random.Image(1024, baseLayers)
if err != nil {
t.Fatalf("random.Image() = %v", err)
}
importpath := "github.com/google/ko"

creationTime := v1.Time{Time: time.Unix(5000, 0)}
var buildCtx buildContext
ng, err := NewGo(
context.Background(),
"",
WithCreationTime(creationTime),
WithBaseImages(func(context.Context, string) (name.Reference, Result, error) { return baseRef, base, nil }),
withBuilder(func(ctx context.Context, b buildContext) (string, error) {

Check failure on line 933 in pkg/build/gobuild_test.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'ctx' seems to be unused, consider removing or renaming it as _ (revive)
buildCtx = b
return "", errors.New("fake build error")
}),
withSBOMber(fauxSBOM),
WithPlatforms("all"),
WithEnv([]string{"FOO=foo", "BAR=bar"}),
WithFlags([]string{"-v"}),
WithLdflags([]string{"-s"}),
WithConfig(map[string]Config{
"github.com/google/ko/test": {
Env: StringArray{"FOO=baz"},
Flags: FlagArray{"-trimpath"},
Ldflags: StringArray{"-w"},
},
}),
)
require.NoError(t, err)

// Build and capture the buildContext.
_, err = ng.Build(context.Background(), StrictScheme+filepath.Join(importpath, "test"))
require.ErrorContains(t, err, "fake build error")
require.Equal(t, []string{"-v", "-trimpath"}, buildCtx.mergedFlags)
require.Equal(t, []string{"-s", "-w"}, buildCtx.mergedLdflags)

envVars := make(map[string]string)
for _, val := range buildCtx.mergedEnv {
kv := strings.SplitN(val, "=", 2)
envVars[kv[0]] = kv[1]
}
require.Equal(t, "baz", envVars["FOO"])
require.Equal(t, "bar", envVars["BAR"])
}

func TestGoBuildWithKOCACHE(t *testing.T) {
now := time.Now() // current local time
sec := now.Unix()
Expand Down
16 changes: 16 additions & 0 deletions pkg/build/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,22 @@ func WithEnv(env []string) Option {
}
}

// WithFlags is a functional option for providing a global set of flags across all builds.
func WithFlags(flags []string) Option {
return func(gbo *gobuildOpener) error {
gbo.flags = flags
return nil
}
}

// WithLdflags is a functional option for providing a global set of ldflags across all builds.
func WithLdflags(ldflags []string) Option {
return func(gbo *gobuildOpener) error {
gbo.ldflags = ldflags
return nil
}
}

// WithPlatforms is a functional option for building certain platforms for
// multi-platform base images. To build everything from the base, use "all",
// otherwise use a list of platform specs, i.e.:
Expand Down
20 changes: 16 additions & 4 deletions pkg/commands/options/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ type BuildOptions struct {
// Env allows setting environment variables globally and applying them to each build.
Env []string

// Flags allows setting flags globally and applying them to each build.
Flags []string

// Ldflags allows setting ldflags globally and applying them to each build.
Ldflags []string

// WorkingDirectory allows for setting the working directory for invocations of the `go` tool.
// Empty string means the current working directory.
WorkingDirectory string
Expand Down Expand Up @@ -136,16 +142,22 @@ func (bo *BuildOptions) LoadConfig() error {
}
}

dp := v.GetStringSlice("defaultPlatforms")
if len(dp) > 0 {
if dp := v.GetStringSlice("defaultPlatforms"); len(dp) > 0 {
bo.DefaultPlatforms = dp
}

env := v.GetStringSlice("env")
if len(env) > 0 {
if env := v.GetStringSlice("env"); len(env) > 0 {
bo.Env = env
}

if flags := v.GetStringSlice("flags"); len(flags) > 0 {
bo.Flags = flags
}

if ldflags := v.GetStringSlice("ldflags"); len(ldflags) > 0 {
bo.Ldflags = ldflags
}

if bo.BaseImage == "" {
ref := v.GetString("defaultBaseImage")
if _, err := name.ParseReference(ref); err != nil {
Expand Down
23 changes: 18 additions & 5 deletions pkg/commands/options/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/google/ko/pkg/build"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
)

func TestDefaultBaseImage(t *testing.T) {
Expand Down Expand Up @@ -72,14 +73,26 @@ func TestEnv(t *testing.T) {
WorkingDirectory: "testdata/config",
}
err := bo.LoadConfig()
if err != nil {
t.Fatal(err)
require.NoError(t, err)
require.Equal(t, []string{"FOO=bar"}, bo.Env)
}

func TestFlags(t *testing.T) {
bo := &BuildOptions{
WorkingDirectory: "testdata/config",
}
err := bo.LoadConfig()
require.NoError(t, err)
require.Equal(t, []string{"-tags", "netgo"}, bo.Flags)
}

wantEnv := []string{"FOO=bar"} // matches value in ./testdata/config/.ko.yaml
if !reflect.DeepEqual(bo.Env, wantEnv) {
t.Fatalf("wanted Env %s, got %s", wantEnv, bo.Env)
func TestLDFlags(t *testing.T) {
bo := &BuildOptions{
WorkingDirectory: "testdata/config",
}
err := bo.LoadConfig()
require.NoError(t, err)
require.Equal(t, []string{"-s -w"}, bo.Ldflags)
}

func TestBuildConfigWithWorkingDirectoryAndDirAndMain(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions pkg/commands/options/testdata/config/.ko.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
defaultBaseImage: alpine
defaultPlatforms: all
env: FOO=bar
flags:
- -tags
- netgo
ldflags:
- -s -w
2 changes: 2 additions & 0 deletions pkg/commands/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ func gobuildOptions(bo *options.BuildOptions) ([]build.Option, error) {
opts := []build.Option{
build.WithBaseImages(getBaseImage(bo)),
build.WithEnv(bo.Env),
build.WithFlags(bo.Flags),
build.WithLdflags(bo.Ldflags),
build.WithPlatforms(bo.Platforms...),
build.WithJobs(bo.ConcurrentBuilds),
}
Expand Down

0 comments on commit 1793fd5

Please sign in to comment.