-
Notifications
You must be signed in to change notification settings - Fork 181
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
feat(oci-layout): support in oras cp
#748
Changes from 12 commits
83c4af1
f8d4a27
2026d9d
071c792
c244cd5
a5fd875
d4f96d3
b0e8e28
3df7915
ec2f556
07dba15
f5bb892
6dbd0a6
d71860c
6d11cef
01c5674
c20e948
3962a55
33f6561
fca9db1
2a70519
6036d0d
1e463d4
c83b54b
b4b2a6c
1585f5a
12fc8ea
87771b6
6af8f50
56e29f9
b9f5df3
440731e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,15 +30,12 @@ import ( | |
) | ||
|
||
type copyOptions struct { | ||
src option.Remote | ||
dst option.Remote | ||
option.Common | ||
option.Platform | ||
recursive bool | ||
option.BinaryTarget | ||
|
||
recursive bool | ||
concurrency int | ||
srcRef string | ||
dstRef string | ||
extraRefs []string | ||
} | ||
|
||
|
@@ -52,54 +49,60 @@ func copyCmd() *cobra.Command { | |
|
||
** This command is in preview and under development. ** | ||
|
||
Example - Copy the artifact tagged with 'v1' from repository 'localhost:5000/net-monitor' to repository 'localhost:5000/net-monitor-copy' | ||
oras cp localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:v1 | ||
|
||
Example - Copy the artifact tagged with 'v1' and its referrers from repository 'localhost:5000/net-monitor' to 'localhost:5000/net-monitor-copy' | ||
oras cp -r localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:v1 | ||
|
||
Example - Copy the artifact tagged with 'v1' from repository 'localhost:5000/net-monitor' to 'localhost:5000/net-monitor-copy' with certain platform | ||
oras cp --platform linux/arm/v5 localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:v1 | ||
|
||
Example - Copy the artifact tagged with 'v1' from repository 'localhost:5000/net-monitor' to 'localhost:5000/net-monitor-copy' with multiple tags | ||
oras cp localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:v1,tag2,tag3 | ||
|
||
Example - Copy the artifact tagged with 'v1' from repository 'localhost:5000/net-monitor' to 'localhost:5000/net-monitor-copy' with multiple tags and concurrency level tuned | ||
oras cp --concurrency 6 localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:v1,tag2,tag3 | ||
Example - Copy the artifacts: | ||
oras cp localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:v1 # copy between repositories | ||
oras cp localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy # copy without tagging in the destination | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think from a customers perspective There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking about it more, I like the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The oci image layout is not a format but a layout, see spec So for short flags, how about
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate on the scenarios of using an input of stdin? To me the UX sounds looks like below:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also for uploading There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Currently, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't want to get too side tracked by all the possible formats and destinations, but also don't want to design into a corner. It definitely might be convenient to support stdin/stdout for example, but maybe that should be done in another command. The tgz thing also might make more sense for another command since tgz input/output make sense for multiple repositories. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@TerryHowe Can you help create enhancement issues with detailed scenario for those? We can continue discussion there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@TerryHowe To avoid ambiguity, how about using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
oras cp --to-oci localhost:5000/net-monitor:v1 test:v1 # download into an OCI layout folder 'test' | ||
oras cp --from-oci test:v1 localhost:5000/net-monitor:v1 # upload from an OCI layout folder 'test' | ||
|
||
Example - Copy the artifact and its referrers: | ||
oras cp -r localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:v1 # copy between repositories | ||
oras cp -r --to-oci localhost:5000/net-monitor:v1 test:v1 # download into an OCI image layout folder 'test' | ||
oras cp -r --from-oci test:v1 localhost:5000/net-monitor:v1 # upload from an OCI image layout folder 'test' | ||
|
||
Example - Copy certain platform of an artifact: | ||
oras cp --platform linux/arm/v5 localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:v1 # copy between repositories | ||
oras cp --platform linux/arm/v5 --to-oci localhost:5000/net-monitor:v1 test:v1 # download into an OCI layout folder 'test' | ||
oras cp --platform linux/arm/v5 --from-oci test:v1 localhost:5000/net-monitor:v1 # upload from an OCI layout folder 'test' | ||
|
||
Example - Copy the artifact with multiple tags: | ||
oras cp localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:tag1,tag2,tag3 # copy between repositories | ||
oras cp localhost:5000/net-monitor:v1 localhost:5000/net-monitor-copy:tag1,tag2,tag3 # copy between repositories with concurrency level tuned | ||
oras cp localhost:5000/net-monitor:v1 test:tag1,tag2,tag3 --to-oci # download into an OCI layout folder 'test' | ||
oras cp test:v1 localhost:5000/net-monitor-copy:tag1,tag2,tag3 --from-oci # upload from an OCI layout folder 'test' | ||
`, | ||
Args: cobra.ExactArgs(2), | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
opts.From.FQDNReference = args[0] | ||
refs := strings.Split(args[1], ",") | ||
opts.To.FQDNReference = refs[0] | ||
opts.extraRefs = refs[1:] | ||
return option.Parse(&opts) | ||
}, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
opts.srcRef = args[0] | ||
refs := strings.Split(args[1], ",") | ||
opts.dstRef = refs[0] | ||
opts.extraRefs = refs[1:] | ||
return runCopy(opts) | ||
}, | ||
} | ||
|
||
cmd.Flags().BoolVarP(&opts.recursive, "recursive", "r", false, "recursively copy the artifact and its referrer artifacts") | ||
opts.src.ApplyFlagsWithPrefix(cmd.Flags(), "from", "source") | ||
opts.dst.ApplyFlagsWithPrefix(cmd.Flags(), "to", "destination") | ||
cmd.Flags().IntVarP(&opts.concurrency, "concurrency", "", 3, "concurrency level") | ||
option.ApplyFlags(&opts, cmd.Flags()) | ||
|
||
return cmd | ||
} | ||
|
||
func runCopy(opts copyOptions) error { | ||
ctx, _ := opts.SetLoggerLevel() | ||
|
||
// Prepare source | ||
src, err := opts.src.NewRepository(opts.srcRef, opts.Common) | ||
src, err := opts.From.NewReadonlyTarget(ctx, opts.Common) | ||
if err != nil { | ||
return err | ||
} | ||
if opts.From.Reference == "" { | ||
return errors.NewErrInvalidReferenceStr(opts.From.FQDNReference) | ||
} | ||
|
||
// Prepare destination | ||
dst, err := opts.dst.NewRepository(opts.dstRef, opts.Common) | ||
dst, err := opts.To.NewTarget(opts.Common) | ||
if err != nil { | ||
return err | ||
} | ||
|
@@ -121,14 +124,10 @@ func runCopy(opts copyOptions) error { | |
return display.PrintStatus(desc, "Exists ", opts.Verbose) | ||
} | ||
|
||
if src.Reference.Reference == "" { | ||
return errors.NewErrInvalidReference(src.Reference) | ||
} | ||
|
||
var desc ocispec.Descriptor | ||
if ref := dst.Reference.Reference; ref == "" { | ||
if ref := opts.To.Reference; ref == "" { | ||
// push to the destination with digest only if no tag specified | ||
desc, err = src.Resolve(ctx, src.Reference.Reference) | ||
desc, err = src.Resolve(ctx, opts.From.Reference) | ||
if err != nil { | ||
return err | ||
} | ||
|
@@ -139,27 +138,27 @@ func runCopy(opts copyOptions) error { | |
} | ||
} else { | ||
if opts.recursive { | ||
desc, err = oras.ExtendedCopy(ctx, src, opts.srcRef, dst, opts.dstRef, extendedCopyOptions) | ||
desc, err = oras.ExtendedCopy(ctx, src, opts.From.Reference, dst, opts.To.Reference, extendedCopyOptions) | ||
} else { | ||
copyOptions := oras.CopyOptions{ | ||
CopyGraphOptions: extendedCopyOptions.CopyGraphOptions, | ||
} | ||
if opts.Platform.Platform != nil { | ||
copyOptions.WithTargetPlatform(opts.Platform.Platform) | ||
} | ||
desc, err = oras.Copy(ctx, src, opts.srcRef, dst, opts.dstRef, copyOptions) | ||
desc, err = oras.Copy(ctx, src, opts.From.Reference, dst, opts.To.Reference, copyOptions) | ||
} | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Println("Copied", opts.srcRef, "=>", opts.dstRef) | ||
fmt.Printf("Copied %s => %s \n", opts.From.FullReference(), opts.To.FullReference()) | ||
qweeah marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if len(opts.extraRefs) != 0 { | ||
tagNOpts := oras.DefaultTagNOptions | ||
tagNOpts.Concurrency = opts.concurrency | ||
if err = oras.TagN(ctx, &display.TagManifestStatusPrinter{Repository: dst}, opts.dstRef, opts.extraRefs, tagNOpts); err != nil { | ||
if _, err = oras.TagN(ctx, &display.TagManifestStatusPrinter{Target: dst}, opts.To.Reference, opts.extraRefs, tagNOpts); err != nil { | ||
return err | ||
} | ||
} | ||
|
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.
@FeynmanZhou I have grouped examples by features, can you help review, thanks!