Skip to content

Commit 1e7f810

Browse files
Merge pull request #25355 from baude/artifactrmall
Add --all to artifact rm
2 parents ca1c029 + cbc7345 commit 1e7f810

File tree

5 files changed

+129
-29
lines changed

5 files changed

+129
-29
lines changed

cmd/podman/artifact/rm.go

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package artifact
22

33
import (
4+
"errors"
45
"fmt"
56

67
"github.com/containers/podman/v5/cmd/podman/common"
@@ -11,40 +12,67 @@ import (
1112

1213
var (
1314
rmCmd = &cobra.Command{
14-
Use: "rm ARTIFACT",
15-
Short: "Remove an OCI artifact",
16-
Long: "Remove an OCI from local storage",
17-
RunE: rm,
18-
Aliases: []string{"remove"},
19-
Args: cobra.ExactArgs(1),
15+
Use: "rm [options] ARTIFACT",
16+
Short: "Remove an OCI artifact",
17+
Long: "Remove an OCI artifact from local storage",
18+
RunE: rm,
19+
Aliases: []string{"remove"},
20+
Args: func(cmd *cobra.Command, args []string) error { //nolint: gocritic
21+
return checkAllAndArgs(cmd, args)
22+
},
2023
ValidArgsFunction: common.AutocompleteArtifacts,
21-
Example: `podman artifact rm quay.io/myimage/myartifact:latest`,
22-
Annotations: map[string]string{registry.EngineMode: registry.ABIMode},
24+
Example: `podman artifact rm quay.io/myimage/myartifact:latest
25+
podman artifact rm -a`,
26+
Annotations: map[string]string{registry.EngineMode: registry.ABIMode},
2327
}
24-
// The lint avoid here is because someday soon we will need flags for
25-
// this command
26-
rmFlag = rmFlagType{} //nolint:unused
28+
29+
rmOptions = entities.ArtifactRemoveOptions{}
2730
)
2831

29-
// TODO at some point force will be a required option; but this cannot be
30-
// until we have artifacts being consumed by other parts of libpod like
31-
// volumes
32-
type rmFlagType struct { //nolint:unused
33-
force bool
32+
func rmFlags(cmd *cobra.Command) {
33+
flags := cmd.Flags()
34+
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all artifacts")
3435
}
35-
3636
func init() {
3737
registry.Commands = append(registry.Commands, registry.CliCommand{
3838
Command: rmCmd,
3939
Parent: artifactCmd,
4040
})
41+
rmFlags(rmCmd)
4142
}
4243

4344
func rm(cmd *cobra.Command, args []string) error {
44-
artifactRemoveReport, err := registry.ImageEngine().ArtifactRm(registry.Context(), args[0], entities.ArtifactRemoveOptions{})
45+
var nameOrID string
46+
if len(args) > 0 {
47+
nameOrID = args[0]
48+
}
49+
artifactRemoveReport, err := registry.ImageEngine().ArtifactRm(registry.Context(), nameOrID, rmOptions)
4550
if err != nil {
4651
return err
4752
}
48-
fmt.Println(artifactRemoveReport.ArtfactDigest.Encoded())
53+
for _, d := range artifactRemoveReport.ArtifactDigests {
54+
fmt.Println(d.Encoded())
55+
}
56+
return nil
57+
}
58+
59+
// checkAllAndArgs takes a cobra command and args and checks if
60+
// all is used, then no args can be passed. note: this was created
61+
// as an unexported local func for now and could be moved to pkg
62+
// validate. if we add "--latest" to the command, then perhaps
63+
// one of the existing plg validate funcs would be appropriate.
64+
func checkAllAndArgs(c *cobra.Command, args []string) error {
65+
all, _ := c.Flags().GetBool("all")
66+
if all && len(args) > 0 {
67+
return fmt.Errorf("when using the --all switch, you may not pass any artifact names or digests")
68+
}
69+
if !all {
70+
if len(args) < 1 {
71+
return errors.New("a single artifact name or digest must be specified")
72+
}
73+
if len(args) > 1 {
74+
return errors.New("too many arguments: only accepts one artifact name or digest ")
75+
}
76+
}
4977
return nil
5078
}

docs/source/markdown/podman-artifact-rm.1.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ subject to change.*
99
podman\-artifact\-rm - Remove an OCI from local storage
1010

1111
## SYNOPSIS
12-
**podman artifact rm** *name*
12+
**podman artifact rm** [*options*] *name*
1313

1414
## DESCRIPTION
1515

@@ -18,6 +18,11 @@ qualified artifact name or a full or partial artifact digest.
1818

1919
## OPTIONS
2020

21+
#### **--all**, **-a**
22+
23+
Remove all artifacts in the local store. The use of this option conflicts with
24+
providing a name or digest of the artifact.
25+
2126
#### **--help**
2227

2328
Print usage statement.
@@ -29,14 +34,21 @@ Remove an artifact by name
2934

3035
```
3136
$ podman artifact rm quay.io/artifact/foobar2:test
32-
e7b417f49fc24fc7ead6485da0ebd5bc4419d8a3f394c169fee5a6f38faa4056
37+
Deleted: e7b417f49fc24fc7ead6485da0ebd5bc4419d8a3f394c169fee5a6f38faa4056
3338
```
3439

3540
Remove an artifact by partial digest
3641

3742
```
3843
$ podman artifact rm e7b417f49fc
39-
e7b417f49fc24fc7ead6485da0ebd5bc4419d8a3f394c169fee5a6f38faa4056
44+
Deleted: e7b417f49fc24fc7ead6485da0ebd5bc4419d8a3f394c169fee5a6f38faa4056
45+
```
46+
47+
Remove all artifacts in local storage
48+
```
49+
$ podman artifact rm -a
50+
Deleted: cee15f7c5ce3e86ae6ce60d84bebdc37ad34acfa9a2611cf47501469ac83a1ab
51+
Deleted: 72875f8f6f78d5b8ba98b2dd2c0a6f395fde8f05ff63a1df580d7a88f5afa97b
4052
```
4153

4254
## SEE ALSO

pkg/domain/entities/artifact.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ type ArtifactPushOptions struct {
5959
}
6060

6161
type ArtifactRemoveOptions struct {
62+
// Remove all artifacts
63+
All bool
6264
}
6365

6466
type ArtifactPullReport struct{}
@@ -79,5 +81,5 @@ type ArtifactAddReport struct {
7981
}
8082

8183
type ArtifactRemoveReport struct {
82-
ArtfactDigest *digest.Digest
84+
ArtifactDigests []*digest.Digest
8385
}

pkg/domain/infra/abi/artifact.go

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/containers/podman/v5/pkg/domain/entities"
1313
"github.com/containers/podman/v5/pkg/libartifact/store"
1414
"github.com/containers/podman/v5/pkg/libartifact/types"
15+
"github.com/opencontainers/go-digest"
1516
)
1617

1718
func getDefaultArtifactStore(ir *ImageEngine) string {
@@ -86,17 +87,45 @@ func (ir *ImageEngine) ArtifactPull(ctx context.Context, name string, opts entit
8687
return nil, artStore.Pull(ctx, name, *pullOptions)
8788
}
8889

89-
func (ir *ImageEngine) ArtifactRm(ctx context.Context, name string, _ entities.ArtifactRemoveOptions) (*entities.ArtifactRemoveReport, error) {
90+
func (ir *ImageEngine) ArtifactRm(ctx context.Context, name string, opts entities.ArtifactRemoveOptions) (*entities.ArtifactRemoveReport, error) {
91+
var (
92+
namesOrDigests []string
93+
)
94+
artifactDigests := make([]*digest.Digest, 0, len(namesOrDigests))
9095
artStore, err := store.NewArtifactStore(getDefaultArtifactStore(ir), ir.Libpod.SystemContext())
9196
if err != nil {
9297
return nil, err
9398
}
94-
artifactDigest, err := artStore.Remove(ctx, name)
95-
if err != nil {
96-
return nil, err
99+
100+
if opts.All {
101+
allArtifacts, err := artStore.List(ctx)
102+
if err != nil {
103+
return nil, err
104+
}
105+
for _, art := range allArtifacts {
106+
// Using the digest here instead of name to protect against
107+
// an artifact that lacks a name
108+
manifestDigest, err := art.GetDigest()
109+
if err != nil {
110+
return nil, err
111+
}
112+
namesOrDigests = append(namesOrDigests, manifestDigest.Encoded())
113+
}
114+
}
115+
116+
if name != "" {
117+
namesOrDigests = append(namesOrDigests, name)
118+
}
119+
120+
for _, namesOrDigest := range namesOrDigests {
121+
artifactDigest, err := artStore.Remove(ctx, namesOrDigest)
122+
if err != nil {
123+
return nil, err
124+
}
125+
artifactDigests = append(artifactDigests, artifactDigest)
97126
}
98127
artifactRemoveReport := entities.ArtifactRemoveReport{
99-
ArtfactDigest: artifactDigest,
128+
ArtifactDigests: artifactDigests,
100129
}
101130
return &artifactRemoveReport, err
102131
}

test/e2e/artifact_test.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,41 @@ var _ = Describe("Podman artifact", func() {
175175
// Removing that artifact should work
176176
rmWorks := podmanTest.PodmanExitCleanly("artifact", "rm", artifact1Name)
177177
// The digests printed by removal should be the same as the digest that was added
178-
Expect(addArtifact1.OutputToString()).To(Equal(rmWorks.OutputToString()))
178+
Expect(rmWorks.OutputToString()).To(ContainSubstring(addArtifact1.OutputToString()))
179179

180180
// Inspecting that the removed artifact should fail
181181
inspectArtifact := podmanTest.Podman([]string{"artifact", "inspect", artifact1Name})
182182
inspectArtifact.WaitWithDefaultTimeout()
183183
Expect(inspectArtifact).Should(ExitWithError(125, fmt.Sprintf("Error: %s: artifact does not exist", artifact1Name)))
184+
185+
// Add some artifacts back in
186+
artifact2File, err := createArtifactFile(8096)
187+
Expect(err).ToNot(HaveOccurred())
188+
artifact2Name := "localhost/test/artifact2"
189+
podmanTest.PodmanExitCleanly("artifact", "add", artifact2Name, artifact2File)
190+
podmanTest.PodmanExitCleanly("artifact", "add", artifact1Name, artifact1File)
191+
192+
// Using -a and an arg should trigger an error
193+
failArgs := podmanTest.Podman([]string{"artifact", "rm", "-a", artifact1Name})
194+
failArgs.WaitWithDefaultTimeout()
195+
Expect(failArgs).Should(ExitWithError(125, "Error: when using the --all switch, you may not pass any artifact names or digests"))
196+
197+
// No args is an error
198+
failNoArgs := podmanTest.Podman([]string{"artifact", "rm"})
199+
failNoArgs.WaitWithDefaultTimeout()
200+
Expect(failNoArgs).Should(ExitWithError(125, "Error: a single artifact name or digest must be specified"))
201+
202+
// Multiple args is an error
203+
multipleArgs := podmanTest.Podman([]string{"artifact", "rm", artifact1Name, artifact2File})
204+
multipleArgs.WaitWithDefaultTimeout()
205+
Expect(multipleArgs).Should(ExitWithError(125, "Error: too many arguments: only accepts one artifact name or digest"))
206+
207+
// Remove all
208+
podmanTest.PodmanExitCleanly("artifact", "rm", "-a")
209+
210+
// There should be no artifacts in the store
211+
rmAll := podmanTest.PodmanExitCleanly("artifact", "ls", "--noheading")
212+
Expect(rmAll.OutputToString()).To(BeEmpty())
184213
})
185214

186215
It("podman artifact inspect with full or partial digest", func() {

0 commit comments

Comments
 (0)