diff --git a/cmd/skopeo/utils.go b/cmd/skopeo/utils.go index c4d2f702..3cb61aac 100644 --- a/cmd/skopeo/utils.go +++ b/cmd/skopeo/utils.go @@ -227,6 +227,7 @@ type imageDestOptions struct { ociAcceptUncompressedLayers bool // Whether to accept uncompressed layers in the oci: transport compressionFormat string // Format to use for the compression compressionLevel optionalInt // Level to use for the compression + precomputeDigests bool // Precompute digests to dedup layers when saving to the docker: transport } // imageDestFlags prepares a collection of CLI flags writing into imageDestOptions, and the managed imageDestOptions structure. @@ -240,6 +241,7 @@ func imageDestFlags(global *globalOptions, shared *sharedImageOptions, deprecate fs.BoolVar(&opts.ociAcceptUncompressedLayers, flagPrefix+"oci-accept-uncompressed-layers", false, "Allow uncompressed image layers when saving to an OCI image using the 'oci' transport. (default is to compress things that aren't compressed)") fs.StringVar(&opts.compressionFormat, flagPrefix+"compress-format", "", "`FORMAT` to use for the compression") fs.Var(newOptionalIntValue(&opts.compressionLevel), flagPrefix+"compress-level", "`LEVEL` to use for the compression") + fs.BoolVar(&opts.precomputeDigests, flagPrefix+"precompute-digests", false, "Precompute digests to prevent uploading layers already on the registry using the 'docker' transport.") return fs, &opts } @@ -264,6 +266,7 @@ func (opts *imageDestOptions) newSystemContext() (*types.SystemContext, error) { if opts.compressionLevel.present { ctx.CompressionLevel = &opts.compressionLevel.value } + ctx.DockerRegistryPushPrecomputeDigests = opts.precomputeDigests return ctx, err } diff --git a/cmd/skopeo/utils_test.go b/cmd/skopeo/utils_test.go index 6c5fada3..1487a031 100644 --- a/cmd/skopeo/utils_test.go +++ b/cmd/skopeo/utils_test.go @@ -167,26 +167,28 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) { "--dest-tls-verify=false", "--dest-creds", "creds-user:creds-password", "--dest-registry-token", "faketoken", + "--dest-precompute-digests=true", }) res, err = opts.newSystemContext() require.NoError(t, err) assert.Equal(t, &types.SystemContext{ - RegistriesDirPath: "/srv/registries.d", - AuthFilePath: "/srv/authfile", - ArchitectureChoice: "overridden-arch", - OSChoice: "overridden-os", - VariantChoice: "overridden-variant", - OCISharedBlobDirPath: "/srv/shared-blob-dir", - DockerCertPath: "/srv/cert-dir", - DockerInsecureSkipTLSVerify: types.OptionalBoolTrue, - DockerAuthConfig: &types.DockerAuthConfig{Username: "creds-user", Password: "creds-password"}, - DockerBearerRegistryToken: "faketoken", - DockerDaemonCertPath: "/srv/cert-dir", - DockerDaemonHost: "daemon-host.example.com", - DockerDaemonInsecureSkipTLSVerify: true, - DockerRegistryUserAgent: defaultUserAgent, - DirForceCompress: true, - BigFilesTemporaryDir: "/srv", + RegistriesDirPath: "/srv/registries.d", + AuthFilePath: "/srv/authfile", + ArchitectureChoice: "overridden-arch", + OSChoice: "overridden-os", + VariantChoice: "overridden-variant", + OCISharedBlobDirPath: "/srv/shared-blob-dir", + DockerCertPath: "/srv/cert-dir", + DockerInsecureSkipTLSVerify: types.OptionalBoolTrue, + DockerAuthConfig: &types.DockerAuthConfig{Username: "creds-user", Password: "creds-password"}, + DockerBearerRegistryToken: "faketoken", + DockerDaemonCertPath: "/srv/cert-dir", + DockerDaemonHost: "daemon-host.example.com", + DockerDaemonInsecureSkipTLSVerify: true, + DockerRegistryUserAgent: defaultUserAgent, + DirForceCompress: true, + BigFilesTemporaryDir: "/srv", + DockerRegistryPushPrecomputeDigests: true, }, res) // Global/per-command tlsVerify behavior is tested in TestTLSVerifyFlags. diff --git a/completions/bash/skopeo b/completions/bash/skopeo index f5a28918..da36d3b2 100644 --- a/completions/bash/skopeo +++ b/completions/bash/skopeo @@ -65,6 +65,7 @@ _skopeo_copy() { --src-no-creds --dest-no-creds --dest-oci-accept-uncompressed-layers + --dest-precompute-digests " local transports diff --git a/docs/skopeo-copy.1.md b/docs/skopeo-copy.1.md index 807a6c6c..e9c21592 100644 --- a/docs/skopeo-copy.1.md +++ b/docs/skopeo-copy.1.md @@ -160,6 +160,10 @@ Bearer token for accessing the source registry. Bearer token for accessing the destination registry. +**--dest-precompute-digests** _bool-value_ + +Precompute digests to ensure layers are not uploaded that already exist on the destination registry. Layers with initially unknown digests (ex. compressing "on the fly") will be temporarily streamed to disk. + **--retry-times** The number of times to retry. Retry wait time will be exponentially increased based on the number of failed attempts.