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

Add global flags and ldflags #1314

Merged
merged 1 commit into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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.

```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(_ context.Context, b buildContext) (string, error) {
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
Loading