Merge pull request #1247 from tonistiigi/dangling-naming
exporter: add canonical and dangling image namingv0.7
commit
e486c1193f
15
README.md
15
README.md
|
@ -45,7 +45,7 @@ You don't need to read this document unless you want to use the full-featured st
|
|||
- [Building a Dockerfile using external frontend:](#building-a-dockerfile-using-external-frontend)
|
||||
- [Building a Dockerfile with experimental features like `RUN --mount=type=(bind|cache|tmpfs|secret|ssh)`](#building-a-dockerfile-with-experimental-features-like-run---mounttypebindcachetmpfssecretssh)
|
||||
- [Output](#output)
|
||||
- [Registry](#registry)
|
||||
- [Image/Registry](#imageregistry)
|
||||
- [Local directory](#local-directory)
|
||||
- [Docker tarball](#docker-tarball)
|
||||
- [OCI tarball](#oci-tarball)
|
||||
|
@ -199,7 +199,7 @@ See [`frontend/dockerfile/docs/experimental.md`](frontend/dockerfile/docs/experi
|
|||
|
||||
By default, the build result and intermediate cache will only remain internally in BuildKit. An output needs to be specified to retrieve the result.
|
||||
|
||||
#### Registry
|
||||
#### Image/Registry
|
||||
|
||||
```bash
|
||||
buildctl build ... --output type=image,name=docker.io/username/image,push=true
|
||||
|
@ -215,6 +215,17 @@ buildctl build ...\
|
|||
--import-cache type=registry,ref=docker.io/username/image
|
||||
```
|
||||
|
||||
Keys supported by image output:
|
||||
* `name=[value]`: image name
|
||||
* `push=true`: push after creating the image
|
||||
* `push-by-digest=true`: push unnamed image
|
||||
* `registry.insecure=true`: push to insecure HTTP registry
|
||||
* `oci-mediatypes=true`: use OCI mediatypes in configuration JSON instead of Docker's
|
||||
* `unpack=true`: unpack image after creation (for use with containerd)
|
||||
* `dangling-name-prefix=[value]`: name image with `prefix@<digest>` , used for anonymous images
|
||||
* `name-canonical=true`: add additional canonical name `name@<digest>`
|
||||
|
||||
|
||||
If credentials are required, `buildctl` will attempt to read Docker configuration file `$DOCKER_CONFIG/config.json`.
|
||||
`$DOCKER_CONFIG` defaults to `~/.docker`.
|
||||
|
||||
|
|
|
@ -26,12 +26,14 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
keyImageName = "name"
|
||||
keyPush = "push"
|
||||
keyPushByDigest = "push-by-digest"
|
||||
keyInsecure = "registry.insecure"
|
||||
keyUnpack = "unpack"
|
||||
ociTypes = "oci-mediatypes"
|
||||
keyImageName = "name"
|
||||
keyPush = "push"
|
||||
keyPushByDigest = "push-by-digest"
|
||||
keyInsecure = "registry.insecure"
|
||||
keyUnpack = "unpack"
|
||||
keyDanglingPrefix = "dangling-name-prefix"
|
||||
keyNameCanonical = "name-canonical"
|
||||
ociTypes = "oci-mediatypes"
|
||||
)
|
||||
|
||||
type Opt struct {
|
||||
|
@ -111,6 +113,18 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp
|
|||
return nil, errors.Wrapf(err, "non-bool value specified for %s", k)
|
||||
}
|
||||
i.ociTypes = b
|
||||
case keyDanglingPrefix:
|
||||
i.danglingPrefix = v
|
||||
case keyNameCanonical:
|
||||
if v == "" {
|
||||
i.nameCanonical = true
|
||||
continue
|
||||
}
|
||||
b, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "non-bool value specified for %s", k)
|
||||
}
|
||||
i.nameCanonical = b
|
||||
default:
|
||||
if i.meta == nil {
|
||||
i.meta = make(map[string][]byte)
|
||||
|
@ -123,13 +137,15 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp
|
|||
|
||||
type imageExporterInstance struct {
|
||||
*imageExporter
|
||||
targetName string
|
||||
push bool
|
||||
pushByDigest bool
|
||||
unpack bool
|
||||
insecure bool
|
||||
ociTypes bool
|
||||
meta map[string][]byte
|
||||
targetName string
|
||||
push bool
|
||||
pushByDigest bool
|
||||
unpack bool
|
||||
insecure bool
|
||||
ociTypes bool
|
||||
nameCanonical bool
|
||||
danglingPrefix string
|
||||
meta map[string][]byte
|
||||
}
|
||||
|
||||
func (e *imageExporterInstance) Name() string {
|
||||
|
@ -165,24 +181,35 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source)
|
|||
e.targetName = string(n)
|
||||
}
|
||||
|
||||
nameCanonical := e.nameCanonical
|
||||
if e.targetName == "" && e.danglingPrefix != "" {
|
||||
e.targetName = e.danglingPrefix + "@" + desc.Digest.String()
|
||||
nameCanonical = false
|
||||
}
|
||||
|
||||
if e.targetName != "" {
|
||||
targetNames := strings.Split(e.targetName, ",")
|
||||
for _, targetName := range targetNames {
|
||||
if e.opt.Images != nil {
|
||||
tagDone := oneOffProgress(ctx, "naming to "+targetName)
|
||||
img := images.Image{
|
||||
Name: targetName,
|
||||
Target: *desc,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
sfx := []string{""}
|
||||
if nameCanonical {
|
||||
sfx = append(sfx, "@"+desc.Digest.String())
|
||||
}
|
||||
for _, sfx := range sfx {
|
||||
img.Name = targetName + sfx
|
||||
if _, err := e.opt.Images.Update(ctx, img); err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
return nil, tagDone(err)
|
||||
}
|
||||
|
||||
if _, err := e.opt.Images.Update(ctx, img); err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
return nil, tagDone(err)
|
||||
}
|
||||
|
||||
if _, err := e.opt.Images.Create(ctx, img); err != nil {
|
||||
return nil, tagDone(err)
|
||||
if _, err := e.opt.Images.Create(ctx, img); err != nil {
|
||||
return nil, tagDone(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
tagDone(nil)
|
||||
|
|
Loading…
Reference in New Issue