-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
add podman artifact extract #25238
base: main
Are you sure you want to change the base?
add podman artifact extract #25238
Conversation
Add a new command to extract the blob content of the artifact store to a local path. Fixes https://issues.redhat.com/browse/RUN-2445 Signed-off-by: Paul Holzinger <[email protected]>
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Luap99 The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Ephemeral COPR build failed. @containers/packit-build please check. |
must be used to select only a single blob. If the file already exists it will be | ||
overwritten. | ||
|
||
If the target is an directory (it must exist) all blobs will be copied to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the target is an directory (it must exist) all blobs will be copied to the | |
If the target is an directory (it must exist), all blobs will be copied to the |
overwritten. | ||
|
||
If the target is an directory (it must exist) all blobs will be copied to the | ||
target directory. As target file name the value from `org.opencontainers.image.title` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a typo here maybe ... did you mean "a" or "the" target file ?
|
||
If the target is an directory (it must exist) all blobs will be copied to the | ||
target directory. As target file name the value from `org.opencontainers.image.title` | ||
annotation is used. If the annotation is missing the target file name will be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
annotation is used. If the annotation is missing the target file name will be | |
annotation is used. If the annotation is missing, the target file name will be |
target directory. As target file name the value from `org.opencontainers.image.title` | ||
annotation is used. If the annotation is missing the target file name will be | ||
the digest of the blob (with `:` replaced by `-` in the name). | ||
If the target file already exists in the directory it will be overwritten. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the target file already exists in the directory it will be overwritten. | |
If the target file already exists in the directory, it will be overwritten. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A fairly brief skim; ACK overall, some more design questions.
Note the
path is a file or does not exists the artifact must either consists of one blob | ||
or if it has multiple blobs (layers) then the **--digest** or **--title** option |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/consists/consist/
The (layers)
explanation should probably happen with the first use of the word “blob”.
|
||
## DESCRIPTION | ||
|
||
Extract the blobs of an OCI artifact to a local file or directory. If the target |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider a paragraph break after the first sentence; then there would be a paragraph for files, and a paragraph for directories.
overwritten. | ||
|
||
If the target is an directory (it must exist) all blobs will be copied to the | ||
target directory. As target file name the value from `org.opencontainers.image.title` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With --digest
, the file name probably should be always digest-based, so that the user knows where to find the output.
(Same with --title
, but that happens ~automatically.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes the code actually simpler, I had the in my first version but then thought it would not be consistent. But yeah I guess you are right it makes sense to stick with the digest for users so they can predict the target name.
@@ -14,6 +14,13 @@ type ArtifactAddOptions struct { | |||
ArtifactType string | |||
} | |||
|
|||
type ArtifactExtractOptions struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depending on what we decide about the option semantics, the comments here might need more detail (or to just refer to the man page for details)
if err != nil { | ||
return err | ||
} | ||
return artStore.Extract(ctx, name, target, (*types.ExtractOptions)(opts)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid the cast? My reading of the Go spec is that this is actually safe (Go requires the two structs to have the same fields, in the same order), but to my old C eyes it looks like undefined behavior.
It would also make working with IDEs harder — tools to “find all references” of a field can’t trace how ArtifactExtractOptions.Digest
becomes ExtractOptions.Digest
.
(Disregard if this is a common pattern in Podman.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it is common, I just found it shorter to write then assigning each filed individually. I can totally do that.
return nil | ||
} | ||
|
||
func generateArtifactName(title string, digest digest.Digest) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like
func generateArtifactName(title string, digest digest.Digest) string { | |
func generateArtifactBlobName(title string, digest digest.Digest) string { |
? It is not a name of the whole artifact.
) | ||
for _, l := range arty.Manifest.Layers { | ||
if options.Digest == l.Digest.String() { | ||
if len(digest.String()) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Absolutely non-blocking: IIRC digest != ""
compiles to the same code, we can let the compiler turn that into a len
check. Applies throughout.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair but AFAICT we have no common style on these check empty string conditions in Podman. some do ==/!= ""
and some do len() ==/!= 0
instead. I think I went consitently with len() here.
Also compare already existing
if len(dest) == 0 {
return nil, ErrEmptyArtifactName
}
title string | ||
) | ||
for _, l := range arty.Manifest.Layers { | ||
if options.Digest == l.Digest.String() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-blocking: This probably can be structured as if layerMatchesOptions(…) {
duplicate check; set digest
/title
}
). This works fine as is, and it is short enough that it is not that necessary.
// on all platforms replace it with "-". | ||
filename = strings.ReplaceAll(digest.String(), ":", "-") | ||
} | ||
return filename |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This must protect against ..
in the path, maybe using filepath-securejoin
, maybe outright rejecting paths with /
, maybe something else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, yes I totally forget about that. Let's reject /
, we only support single files. Supporting actual paths with directories would means we have to mkdir them which means more code/tests, etc...
We can reconsider if users have a strong use case for them.
|
||
Extract the blobs of an OCI artifact to a local file or directory. If the target | ||
path is a file or does not exists the artifact must either consists of one blob | ||
or if it has multiple blobs (layers) then the **--digest** or **--title** option |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Late thought: this does not allow extracting the config. I think that’s fine for the file-destination case, we can always add an option later.
For the directory-destination case, maybe we should establish the behavior right now. (It would not be a disaster not to handle that either, we can add an --include-config
option later, but it seems worth thinking about.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not allow setting the config either, AFAICT we also have {}
as config. Extracting that always seems pointless because of that.
Note all man pages say:
## WARNING: Experimental command
*This command is considered experimental and still in development. Inputs, options, and outputs are all
subject to change.*
As such even if we merge it we can reconsider until we remove that warning so I rather to expand the scope of this PR to deal with configs.
Add a new command to extract the blob content of the artifact store to a local path.
Fixes https://issues.redhat.com/browse/RUN-2445
Does this PR introduce a user-facing change?