Skip to content

Commit c180e0a

Browse files
committed
added all-tags flag
1 parent 867c4b3 commit c180e0a

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

cmd/nerdctl/image/image_push.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ func PushCommand() *cobra.Command {
6969

7070
cmd.Flags().Bool(allowNonDistFlag, false, "Allow pushing images with non-distributable blobs")
7171

72+
// support Docker-compatible all-tags flag
73+
cmd.Flags().BoolP("all-tags", "a", false, "Push all local tags of the repository")
74+
7275
return cmd
7376
}
7477

@@ -101,6 +104,10 @@ func pushOptions(cmd *cobra.Command) (types.ImagePushOptions, error) {
101104
if err != nil {
102105
return types.ImagePushOptions{}, err
103106
}
107+
allTags, err := cmd.Flags().GetBool("all-tags")
108+
if err != nil {
109+
return types.ImagePushOptions{}, err
110+
}
104111
allowNonDist, err := cmd.Flags().GetBool(allowNonDistFlag)
105112
if err != nil {
106113
return types.ImagePushOptions{}, err
@@ -123,6 +130,7 @@ func pushOptions(cmd *cobra.Command) (types.ImagePushOptions, error) {
123130
IpfsEnsureImage: ipfsEnsureImage,
124131
IpfsAddress: ipfsAddress,
125132
Quiet: quiet,
133+
AllTags: allTags,
126134
AllowNondistributableArtifacts: allowNonDist,
127135
Stdout: cmd.OutOrStdout(),
128136
}, nil

pkg/api/types/image_types.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ type ImageInspectOptions struct {
184184
// ImagePushOptions specifies options for `nerdctl (image) push`.
185185
type ImagePushOptions struct {
186186
Stdout io.Writer
187+
Stderr io.Writer
188+
// ProgressOutputToStdout directs progress output to stdout instead of stderr
189+
ProgressOutputToStdout bool
190+
187191
GOptions GlobalCommandOptions
188192
SignOptions ImageSignOptions
189193
SociOptions SociOptions
@@ -202,6 +206,12 @@ type ImagePushOptions struct {
202206
Quiet bool
203207
// AllowNondistributableArtifacts allow pushing non-distributable artifacts
204208
AllowNondistributableArtifacts bool
209+
210+
// AllTags if true, push all local tags for the repository when no tag is specified
211+
AllTags bool
212+
213+
// SkipSoci when true, skip creating/pushing SOCI index (used when pushing multiple tags to avoid overwriting)
214+
SkipSoci bool
205215
}
206216

207217
// RemoteSnapshotterFlags are used for pulling with remote snapshotters

pkg/cmd/image/push.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"net/http"
2525
"os"
2626
"path/filepath"
27+
"strings"
2728

2829
"github.com/opencontainers/go-digest"
2930
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -62,6 +63,10 @@ func Push(ctx context.Context, client *containerd.Client, rawRef string, options
6263
}
6364

6465
if parsedReference.Protocol != "" {
66+
if options.AllTags {
67+
return fmt.Errorf("--all-tags is not supported for %q references", parsedReference.Protocol)
68+
}
69+
6570
if parsedReference.Protocol != referenceutil.IPFSProtocol {
6671
return fmt.Errorf("ipfs scheme is only supported but got %q", parsedReference.Protocol)
6772
}
@@ -105,10 +110,42 @@ func Push(ctx context.Context, client *containerd.Client, rawRef string, options
105110
return nil
106111
}
107112

108-
parsedReference, err = referenceutil.Parse(rawRef)
109-
if err != nil {
110-
return err
113+
if options.AllTags {
114+
repo := ""
115+
if parsedReference.Domain != "" {
116+
repo = parsedReference.Domain + "/"
117+
}
118+
repo += parsedReference.Path
119+
120+
imgList, err := client.ImageService().List(ctx)
121+
if err != nil {
122+
return err
123+
}
124+
125+
var tagRefs []string
126+
for _, img := range imgList {
127+
if strings.HasPrefix(img.Name, repo+":") {
128+
tagRefs = append(tagRefs, img.Name)
129+
}
130+
}
131+
132+
if len(tagRefs) == 0 {
133+
return fmt.Errorf("no local tags found for repository %q", repo)
134+
}
135+
136+
for i, tagRef := range tagRefs {
137+
tagOpts := options
138+
tagOpts.AllTags = false // avoid infinite recursion
139+
tagOpts.SkipSoci = i > 0 // avoid SOCI indexing for the same image
140+
141+
if err := Push(ctx, client, tagRef, tagOpts); err != nil {
142+
return err
143+
}
144+
}
145+
146+
return nil
111147
}
148+
112149
ref := parsedReference.String()
113150
refDomain := parsedReference.Domain
114151

@@ -209,7 +246,7 @@ func Push(ctx context.Context, client *containerd.Client, rawRef string, options
209246
options.SignOptions); err != nil {
210247
return err
211248
}
212-
if options.GOptions.Snapshotter == "soci" {
249+
if options.GOptions.Snapshotter == "soci" && !options.SkipSoci {
213250
if err = snapshotterutil.CreateSociIndexV1(ref, options.GOptions, options.AllPlatforms, options.Platforms, options.SociOptions); err != nil {
214251
return err
215252
}

0 commit comments

Comments
 (0)