1
0
mirror of https://github.com/ko-build/ko.git synced 2024-12-03 08:35:34 +02:00
ko-build/pkg/publish/default.go
Matt Moore ea2beac575
Fix -P with passing ko:// through. (#163)
Turns out I broke this.  Thanks to @bobcatfish for reporting the issue.

With this change:
```
ko resolve -Pf cmd/ko/test/test.yaml > /dev/null
2020/05/04 08:44:35 Using base gcr.io/distroless/static:nonroot for github.com/google/ko/cmd/ko/test
2020/05/04 08:44:36 Building github.com/google/ko/cmd/ko/test
2020/05/04 08:44:37 Publishing gcr.io/mattmoor-knative/github.com/google/ko/cmd/ko/test:latest
2020/05/04 08:44:39 Published gcr.io/mattmoor-knative/github.com/google/ko/cmd/ko/test@sha256:ee655510172b429dbce619fc69677621d71cb824cbbf2a21746d700127257ec4
```

I can cut v0.5.1 once this lands.
2020-05-04 09:06:55 -07:00

149 lines
4.0 KiB
Go

// Copyright 2018 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 publish
import (
"fmt"
"log"
"net/http"
"strings"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/ko/pkg/build"
)
// defalt is intentionally misspelled to avoid keyword collision (and drive Jon nuts).
type defalt struct {
base string
t http.RoundTripper
auth authn.Authenticator
namer Namer
tags []string
insecure bool
}
// Option is a functional option for NewDefault.
type Option func(*defaultOpener) error
type defaultOpener struct {
base string
t http.RoundTripper
auth authn.Authenticator
namer Namer
tags []string
insecure bool
}
// Namer is a function from a supported import path to the portion of the resulting
// image name that follows the "base" repository name.
type Namer func(string) string
// identity is the default namer, so import paths are affixed as-is under the repository
// name for maximum clarity, e.g.
// gcr.io/foo/github.com/bar/baz/cmd/blah
// ^--base--^ ^-------import path-------^
func identity(in string) string { return in }
// As some registries do not support pushing an image by digest, the default tag for pushing
// is the 'latest' tag.
var defaultTags = []string{"latest"}
func (do *defaultOpener) Open() (Interface, error) {
return &defalt{
base: do.base,
t: do.t,
auth: do.auth,
namer: do.namer,
tags: do.tags,
insecure: do.insecure,
}, nil
}
// NewDefault returns a new publish.Interface that publishes references under the provided base
// repository using the default keychain to authenticate and the default naming scheme.
func NewDefault(base string, options ...Option) (Interface, error) {
do := &defaultOpener{
base: base,
t: http.DefaultTransport,
auth: authn.Anonymous,
namer: identity,
tags: defaultTags,
}
for _, option := range options {
if err := option(do); err != nil {
return nil, err
}
}
return do.Open()
}
// Publish implements publish.Interface
func (d *defalt) Publish(img v1.Image, s string) (name.Reference, error) {
s = strings.TrimPrefix(s, build.StrictScheme)
// https://github.com/google/go-containerregistry/issues/212
s = strings.ToLower(s)
ro := []remote.Option{remote.WithAuth(d.auth), remote.WithTransport(d.t)}
no := []name.Option{}
if d.insecure {
no = append(no, name.Insecure)
}
for i, tagName := range d.tags {
tag, err := name.NewTag(fmt.Sprintf("%s/%s:%s", d.base, d.namer(s), tagName), no...)
if err != nil {
return nil, err
}
if i == 0 {
log.Printf("Publishing %v", tag)
if err := remote.Write(tag, img, ro...); err != nil {
return nil, err
}
} else {
log.Printf("Tagging %v", tag)
if err := remote.Tag(tag, img, ro...); err != nil {
return nil, err
}
}
}
h, err := img.Digest()
if err != nil {
return nil, err
}
ref := fmt.Sprintf("%s/%s@%s", d.base, d.namer(s), h)
if len(d.tags) == 1 && d.tags[0] != defaultTags[0] {
// If a single tag is explicitly set (not latest), then this
// is probably a release, so include the tag in the reference.
ref = fmt.Sprintf("%s/%s:%s@%s", d.base, d.namer(s), d.tags[0], h)
}
dig, err := name.NewDigest(ref)
if err != nil {
return nil, err
}
log.Printf("Published %v", dig)
return &dig, nil
}
func (d *defalt) Close() error {
return nil
}