Skip to content

Commit

Permalink
Allow to customize publish.Namer
Browse files Browse the repository at this point in the history
  • Loading branch information
cardil committed Oct 13, 2021
1 parent 6447264 commit 2e666a8
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 10 deletions.
77 changes: 77 additions & 0 deletions pkg/commands/options/namer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 2021 Google LLC All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package options_test

import (
"path"
"testing"

"github.com/google/ko/pkg/commands/options"
)

func TestMakeNamer(t *testing.T) {
for _, namerCase := range testMakeNamerCases() {
namerCase := namerCase
t.Run(namerCase.name, func(t *testing.T) {
namer := options.MakeNamer(&namerCase.opts)
got := namer("registry.example.org/foo/bar", "example.org/sample/cmd/example")

if got != namerCase.want {
t.Errorf("got image name %s, wanted %s", got, namerCase.want)
}
})
}
}

func testMakeNamerCases() []testMakeNamerCase {
return []testMakeNamerCase{{
name: "defaults",
want: "registry.example.org/foo/bar/example-51d74b7127c5f7495a338df33ecdeb19",
}, {
name: "with different separator",
want: "registry.example.org/foo/bar-example-51d74b7127c5f7495a338df33ecdeb19",
opts: options.PublishOptions{ImageNameSeparator: "-"},
}, {
name: "with preserve import paths",
want: "registry.example.org/foo/bar/example.org/sample/cmd/example",
opts: options.PublishOptions{PreserveImportPaths: true},
}, {
name: "with base import paths",
want: "registry.example.org/foo/bar/example",
opts: options.PublishOptions{BaseImportPaths: true},
}, {
name: "with base import paths and custom separator",
want: "registry.example.org/foo/bar-example",
opts: options.PublishOptions{BaseImportPaths: true, ImageNameSeparator: "-"},
}, {
name: "with bare",
want: "registry.example.org/foo/bar",
opts: options.PublishOptions{Bare: true},
}, {
name: "with custom namer",
want: "registry.example.org/foo/bar!example",
opts: options.PublishOptions{ImageNamer: func(base string, importpath string) string {
return base + "!" + path.Base(importpath)
}},
}}
}

type testMakeNamerCase struct {
name string
opts options.PublishOptions
want string
}
48 changes: 38 additions & 10 deletions pkg/commands/options/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/hex"
"os"
"path"
"strings"

"github.com/google/go-containerregistry/pkg/v1/daemon"
"github.com/google/ko/pkg/publish"
Expand Down Expand Up @@ -65,6 +66,14 @@ type PublishOptions struct {
BaseImportPaths bool
// Bare uses a tag on the KO_DOCKER_REPO without anything additional.
Bare bool
// ImageNameSeparator is used to create the image name from base repo and
// specific import path.
ImageNameSeparator string

// ImageNamer can be used to pass a custom image name function. When given
// PreserveImportPaths, BaseImportPaths, Bare, and ImageNameSeparator has
// no effect.
ImageNamer publish.Namer
}

func AddPublishArg(cmd *cobra.Command, po *PublishOptions) {
Expand Down Expand Up @@ -96,33 +105,52 @@ func AddPublishArg(cmd *cobra.Command, po *PublishOptions) {
"Whether to use the base path without MD5 hash after KO_DOCKER_REPO (may not work properly with --tags).")
cmd.Flags().BoolVar(&po.Bare, "bare", po.Bare,
"Whether to just use KO_DOCKER_REPO without additional context (may not work properly with --tags).")
cmd.Flags().StringVar(&po.ImageNameSeparator, "image-name-separator", defaultImageNameSeparator,
"A separator to be used to concatenate KO_DOCKER_REPO with specific image name.")
}

func packageWithMD5(base, importpath string) string {
const defaultImageNameSeparator = "/"

func pathJoin(sep string, paths ...string) string {
if sep == "" {
sep = defaultImageNameSeparator
}
for i, e := range paths {
if e != "" {
return path.Clean(strings.Join(paths[i:], sep))
}
}
return ""
}

func (po *PublishOptions) packageWithMD5(base, importpath string) string {
hasher := md5.New() //nolint: gosec // No strong cryptography needed.
hasher.Write([]byte(importpath))
return path.Join(base, path.Base(importpath)+"-"+hex.EncodeToString(hasher.Sum(nil)))
return pathJoin(po.ImageNameSeparator,
base, path.Base(importpath)+"-"+hex.EncodeToString(hasher.Sum(nil)))
}

func preserveImportPath(base, importpath string) string {
return path.Join(base, importpath)
func (po *PublishOptions) preserveImportPath(base, importpath string) string {
return pathJoin(po.ImageNameSeparator, base, importpath)
}

func baseImportPaths(base, importpath string) string {
return path.Join(base, path.Base(importpath))
func (po *PublishOptions) baseImportPaths(base, importpath string) string {
return pathJoin(po.ImageNameSeparator, base, path.Base(importpath))
}

func bareDockerRepo(base, _ string) string {
return base
}

func MakeNamer(po *PublishOptions) publish.Namer {
if po.PreserveImportPaths {
return preserveImportPath
if po.ImageNamer != nil {
return po.ImageNamer
} else if po.PreserveImportPaths {
return po.preserveImportPath
} else if po.BaseImportPaths {
return baseImportPaths
return po.baseImportPaths
} else if po.Bare {
return bareDockerRepo
}
return packageWithMD5
return po.packageWithMD5
}

0 comments on commit 2e666a8

Please sign in to comment.