Skip to content

Add ability to set layer media type for artifacts #25909

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions cmd/podman/artifact/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ var (
RunE: add,
Args: cobra.MinimumNArgs(2),
ValidArgsFunction: common.AutocompleteArtifactAdd,
Example: `podman artifact add quay.io/myimage/myartifact:latest /tmp/foobar.txt`,
Annotations: map[string]string{registry.EngineMode: registry.ABIMode},
Example: `podman artifact add quay.io/myimage/myartifact:latest /tmp/foobar.txt
podman artifact add --file-type text/yaml quay.io/myimage/myartifact:latest /tmp/foobar.yaml
podman artifact add --append quay.io/myimage/myartifact:latest /tmp/foobar.tar.gz`,
Annotations: map[string]string{registry.EngineMode: registry.ABIMode},
}
)

type artifactAddOptions struct {
ArtifactType string
Annotations []string
Append bool
FileType string
}

var (
Expand All @@ -51,6 +54,10 @@ func init() {

appendFlagName := "append"
flags.BoolVarP(&addOpts.Append, appendFlagName, "a", false, "Append files to an existing artifact")

fileTypeFlagName := "file-type"
flags.StringVarP(&addOpts.FileType, fileTypeFlagName, "", "", "Set file type to use for the artifact (layer)")
_ = addCmd.RegisterFlagCompletionFunc(fileTypeFlagName, completion.AutocompleteNone)
}

func add(cmd *cobra.Command, args []string) error {
Expand All @@ -63,6 +70,7 @@ func add(cmd *cobra.Command, args []string) error {
opts.Annotations = annots
opts.ArtifactType = addOpts.ArtifactType
opts.Append = addOpts.Append
opts.FileType = addOpts.FileType

report, err := registry.ImageEngine().ArtifactAdd(registry.Context(), args[0], args[1:], opts)
if err != nil {
Expand Down
14 changes: 14 additions & 0 deletions docs/source/markdown/podman-artifact-add.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ Note: Set annotations for each file being added.

Append files to an existing artifact. This option cannot be used with the **--type** option.

#### **--file-type**

Set the media type of the artifact file instead of allowing detection to determine the type

#### **--help**

Print usage statement.
Expand Down Expand Up @@ -55,6 +59,16 @@ Set an annotation for an artifact
$ podman artifact add --annotation date=2025-01-30 quay.io/myartifact/myml:latest /tmp/foobar1.ml
```

Append a file to an existing artifact
```
$ podman artifact add --append quay.io/myartifact/tarballs:latest /tmp/foobar.tar.gz
```

Override the media type of the artifact being added
```
$ podman artifact add --file-type text/yaml quay.io/myartifact/descriptors:latest /tmp/info.yaml
```


## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-artifact(1)](podman-artifact.1.md)**
Expand Down
1 change: 1 addition & 0 deletions pkg/domain/entities/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type ArtifactAddOptions struct {
Annotations map[string]string
ArtifactType string
Append bool
FileType string
}

type ArtifactExtractOptions struct {
Expand Down
1 change: 1 addition & 0 deletions pkg/domain/infra/abi/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ func (ir *ImageEngine) ArtifactAdd(ctx context.Context, name string, paths []str
Annotations: opts.Annotations,
ArtifactType: opts.ArtifactType,
Append: opts.Append,
FileType: opts.FileType,
}

artifactDigest, err := artStore.Add(ctx, name, paths, &addOptions)
Expand Down
14 changes: 10 additions & 4 deletions pkg/libartifact/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,20 +251,26 @@ func (as ArtifactStore) Add(ctx context.Context, dest string, paths []string, op
// ImageDestination, in general, requires the caller to write a full image; here we may write only the added layers.
// This works for the oci/layout transport we hard-code.
for _, path := range paths {
mediaType := options.FileType
// get the new artifact into the local store
newBlobDigest, newBlobSize, err := layout.PutBlobFromLocalFile(ctx, imageDest, path)
if err != nil {
return nil, err
}
detectedType, err := determineManifestType(path)
if err != nil {
return nil, err

// If we did not receive an override for the layer's mediatype, use
// detection to determine it.
if len(mediaType) < 1 {
mediaType, err = determineManifestType(path)
if err != nil {
return nil, err
}
}

annotations := maps.Clone(options.Annotations)
annotations[specV1.AnnotationTitle] = filepath.Base(path)
newLayer := specV1.Descriptor{
MediaType: detectedType,
MediaType: mediaType,
Digest: newBlobDigest,
Size: newBlobSize,
Annotations: annotations,
Expand Down
3 changes: 3 additions & 0 deletions pkg/libartifact/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ type AddOptions struct {
ArtifactType string `json:",omitempty"`
// append option is not compatible with ArtifactType option
Append bool `json:",omitempty"`
// FileType describes the media type for the layer. It is an override
// for the standard detection
FileType string `json:",omitempty"`
}

// FilterBlobOptions options used to filter for a single blob in an artifact
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/artifact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ var _ = Describe("Podman artifact", func() {
})

It("podman artifact add with options", func() {
yamlType := "text/yaml"
artifact1Name := "localhost/test/artifact1"
artifact1File, err := createArtifactFile(1024)
Expect(err).ToNot(HaveOccurred())
Expand All @@ -96,13 +97,14 @@ var _ = Describe("Podman artifact", func() {
annotation1 := "color=blue"
annotation2 := "flavor=lemon"

podmanTest.PodmanExitCleanly("artifact", "add", "--type", artifactType, "--annotation", annotation1, "--annotation", annotation2, artifact1Name, artifact1File)
podmanTest.PodmanExitCleanly("artifact", "add", "--file-type", yamlType, "--type", artifactType, "--annotation", annotation1, "--annotation", annotation2, artifact1Name, artifact1File)

a := podmanTest.InspectArtifact(artifact1Name)
Expect(a.Name).To(Equal(artifact1Name))
Expect(a.Manifest.ArtifactType).To(Equal(artifactType))
Expect(a.Manifest.Layers[0].Annotations["color"]).To(Equal("blue"))
Expect(a.Manifest.Layers[0].Annotations["flavor"]).To(Equal("lemon"))
Expect(a.Manifest.Layers[0].MediaType).To(Equal(yamlType))

failSession := podmanTest.Podman([]string{"artifact", "add", "--annotation", "org.opencontainers.image.title=foobar", "foobar", artifact1File})
failSession.WaitWithDefaultTimeout()
Expand Down