From 34b2b9172a2757dbfda3fff091dc3c295fee13ba Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Mon, 24 Jul 2023 07:44:20 +0000 Subject: [PATCH 01/10] docs: add e2e examples for oras-go Signed-off-by: Xiaoxuan Wang --- go.mod | 1 + go.sum | 2 + pull_files_from_remote_test.go | 53 +++++++++++++++++++ pull_image_from_remote_test.go | 60 ++++++++++++++++++++++ pull_image_with_docker_store_test.go | 68 ++++++++++++++++++++++++ push_files_to_remote_test.go | 77 ++++++++++++++++++++++++++++ 6 files changed, 261 insertions(+) create mode 100644 pull_files_from_remote_test.go create mode 100644 pull_image_from_remote_test.go create mode 100644 pull_image_with_docker_store_test.go create mode 100644 push_files_to_remote_test.go diff --git a/go.mod b/go.mod index 747de6eb..6c817606 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,6 @@ go 1.19 require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc4 + github.com/oras-project/oras-credentials-go v0.3.0 golang.org/x/sync v0.3.0 ) diff --git a/go.sum b/go.sum index e391513b..eb4f30c3 100644 --- a/go.sum +++ b/go.sum @@ -2,5 +2,7 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/oras-project/oras-credentials-go v0.3.0 h1:Bg1d9iAmgo50RlaIy2XI5MQs7qL00DB3R9Q4JRP1VWs= +github.com/oras-project/oras-credentials-go v0.3.0/go.mod h1:fFCebDQo0Do+gnM96uV9YUnRay0pwuRQupypvofsp4s= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= diff --git a/pull_files_from_remote_test.go b/pull_files_from_remote_test.go new file mode 100644 index 00000000..8b05b3a4 --- /dev/null +++ b/pull_files_from_remote_test.go @@ -0,0 +1,53 @@ +package oras_test + +import ( + "context" + "fmt" + + "oras.land/oras-go/v2" + "oras.land/oras-go/v2/content/file" + "oras.land/oras-go/v2/registry/remote" + "oras.land/oras-go/v2/registry/remote/auth" + "oras.land/oras-go/v2/registry/remote/retry" +) + +func pullFiles() error { + // 0. Create a file store + fs, err := file.New("/tmp/") + if err != nil { + return err + } + defer fs.Close() + + // 1. Connect to a remote repository + ctx := context.Background() + reg := "myregistry.example.com" + repo, err := remote.NewRepository(reg + "/myrepo") + if err != nil { + return err + } + // Note: The below code can be omitted if authentication is not required + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: auth.StaticCredential(reg, auth.Credential{ + Username: "username", + Password: "password", + }), + } + + // 2. Copy from the remote repository to the file store + tag := "latest" + manifestDescriptor, err := oras.Copy(ctx, repo, tag, fs, tag, oras.DefaultCopyOptions) + if err != nil { + return err + } + fmt.Println("manifest descriptor:", manifestDescriptor) + return nil +} + +func Example_pullFilesFromRemoteRepository() { + if err := pullFiles(); err != nil { + panic(err) + } +} diff --git a/pull_image_from_remote_test.go b/pull_image_from_remote_test.go new file mode 100644 index 00000000..cf9ad2d3 --- /dev/null +++ b/pull_image_from_remote_test.go @@ -0,0 +1,60 @@ +package oras_test + +import ( + "context" + "fmt" + + "oras.land/oras-go/v2" + "oras.land/oras-go/v2/content" + "oras.land/oras-go/v2/content/oci" + "oras.land/oras-go/v2/registry/remote" + "oras.land/oras-go/v2/registry/remote/auth" + "oras.land/oras-go/v2/registry/remote/retry" +) + +func pullImageFromRemote() error { + // 0. Create an OCI layout store + store, err := oci.New("/tmp/oci-layout-root") + if err != nil { + return err + } + + // 1. Connect to a remote repository + ctx := context.Background() + reg := "myregistry.example.com" + repo, err := remote.NewRepository(reg + "/myrepo") + if err != nil { + return err + } + // Note: The below code can be omitted if authentication is not required + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: auth.StaticCredential(reg, auth.Credential{ + Username: "username", + Password: "password", + }), + } + + // 2. Copy from the remote repository to the OCI layout store + tag := "latest" + manifestDescriptor, err := oras.Copy(ctx, repo, tag, store, tag, oras.DefaultCopyOptions) + if err != nil { + return err + } + fmt.Println("manifest pulled:", manifestDescriptor.Digest, manifestDescriptor.MediaType) + + // 3. Fetch from OCI layout store to verify + fetched, err := content.FetchAll(ctx, store, manifestDescriptor) + if err != nil { + return err + } + fmt.Printf("manifest content:\n%s", fetched) + return nil +} + +func Example_pullImageFromRemoteRepository() { + if err := pullImageFromRemote(); err != nil { + panic(err) + } +} diff --git a/pull_image_with_docker_store_test.go b/pull_image_with_docker_store_test.go new file mode 100644 index 00000000..fc9aadc8 --- /dev/null +++ b/pull_image_with_docker_store_test.go @@ -0,0 +1,68 @@ +package oras_test + +import ( + "context" + "fmt" + + credentials "github.com/oras-project/oras-credentials-go" + "oras.land/oras-go/v2" + "oras.land/oras-go/v2/content" + "oras.land/oras-go/v2/content/oci" + "oras.land/oras-go/v2/registry/remote" + "oras.land/oras-go/v2/registry/remote/auth" + "oras.land/oras-go/v2/registry/remote/retry" +) + +func pullImageUsingDockerCredentialStore() error { + + // 0. Create an OCI layout store + store, err := oci.New("/tmp/oci-layout-root") + if err != nil { + return err + } + + // 1. Connect to a remote repository + ctx := context.Background() + reg := "docker.io" + repo, err := remote.NewRepository(reg + "/user/my-repo") + if err != nil { + return err + } + + // 2. Get credentials from the docker credential store + storeOpts := credentials.StoreOptions{} + credStore, err := credentials.NewStoreFromDocker(storeOpts) + if err != nil { + return err + } + + // Prepare the auth client for the registry and credential store + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: credentials.Credential(credStore), // Use the credential store + } + + // 3. Copy from the remote repository to the OCI layout store + tag := "latest" + manifestDescriptor, err := oras.Copy(ctx, repo, tag, store, tag, oras.DefaultCopyOptions) + if err != nil { + return err + } + + fmt.Println("manifest pulled:", manifestDescriptor.Digest, manifestDescriptor.MediaType) + + // 3. Fetch from OCI layout store to verify + fetched, err := content.FetchAll(ctx, store, manifestDescriptor) + if err != nil { + return err + } + fmt.Printf("manifest content:\n%s", fetched) + return nil +} + +func Example_pullImageUsingDockerCredentialStore() { + if err := pullImageUsingDockerCredentialStore(); err != nil { + panic(err) + } +} diff --git a/push_files_to_remote_test.go b/push_files_to_remote_test.go new file mode 100644 index 00000000..7e7d9dfa --- /dev/null +++ b/push_files_to_remote_test.go @@ -0,0 +1,77 @@ +package oras_test + +import ( + "context" + "fmt" + + v1 "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras-go/v2" + "oras.land/oras-go/v2/content/file" + "oras.land/oras-go/v2/registry/remote" + "oras.land/oras-go/v2/registry/remote/auth" + "oras.land/oras-go/v2/registry/remote/retry" +) + +func pushFiles() error { + // 0. Create a file store + fs, err := file.New("/tmp/") + if err != nil { + return err + } + defer fs.Close() + ctx := context.Background() + + // 1. Add files to a file store + mediaType := "example/file" + fileNames := []string{"/tmp/myfile"} + fileDescriptors := make([]v1.Descriptor, 0, len(fileNames)) + for _, name := range fileNames { + fileDescriptor, err := fs.Add(ctx, name, mediaType, "") + if err != nil { + return err + } + fileDescriptors = append(fileDescriptors, fileDescriptor) + fmt.Printf("file descriptor for %s: %v\n", name, fileDescriptor) + } + + // 2. Pack the files and tag the packed manifest + artifactType := "example/files" + manifestDescriptor, err := oras.Pack(ctx, fs, artifactType, fileDescriptors, oras.PackOptions{ + PackImageManifest: true, + }) + if err != nil { + return err + } + fmt.Println("manifest descriptor:", manifestDescriptor) + + tag := "latest" + if err = fs.Tag(ctx, manifestDescriptor, tag); err != nil { + return err + } + + // 3. Connect to a remote repository + reg := "myregistry.example.com" + repo, err := remote.NewRepository(reg + "/myrepo") + if err != nil { + panic(err) + } + // Note: The below code can be omitted if authentication is not required + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: auth.StaticCredential(reg, auth.Credential{ + Username: "username", + Password: "password", + }), + } + + // 3. Copy from the file store to the remote repository + _, err = oras.Copy(ctx, fs, tag, repo, tag, oras.DefaultCopyOptions) + return err +} + +func Example_pushFilesToRemoteRepository() { + if err := pushFiles(); err != nil { + panic(err) + } +} From a88093da78c23e259dac6c3630dc2e2e111d67d6 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 1 Aug 2023 06:56:35 +0000 Subject: [PATCH 02/10] changed Pack Signed-off-by: Xiaoxuan Wang --- ...ker_store_test.go => pull_image_using_docker_store_test.go | 0 push_files_to_remote_test.go | 4 +--- 2 files changed, 1 insertion(+), 3 deletions(-) rename pull_image_with_docker_store_test.go => pull_image_using_docker_store_test.go (100%) diff --git a/pull_image_with_docker_store_test.go b/pull_image_using_docker_store_test.go similarity index 100% rename from pull_image_with_docker_store_test.go rename to pull_image_using_docker_store_test.go diff --git a/push_files_to_remote_test.go b/push_files_to_remote_test.go index 7e7d9dfa..3d5ad381 100644 --- a/push_files_to_remote_test.go +++ b/push_files_to_remote_test.go @@ -36,9 +36,7 @@ func pushFiles() error { // 2. Pack the files and tag the packed manifest artifactType := "example/files" - manifestDescriptor, err := oras.Pack(ctx, fs, artifactType, fileDescriptors, oras.PackOptions{ - PackImageManifest: true, - }) + manifestDescriptor, err := oras.Pack(ctx, fs, artifactType, fileDescriptors, oras.DefaultPackOptions) if err != nil { return err } From 0b244c9670f7b181cbdac6a416a1e584808a8bbc Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 1 Aug 2023 07:08:34 +0000 Subject: [PATCH 03/10] added license statement Signed-off-by: Xiaoxuan Wang --- pull_files_from_remote_test.go | 15 +++++++++++++++ pull_image_from_remote_test.go | 15 +++++++++++++++ pull_image_using_docker_store_test.go | 15 +++++++++++++++ push_files_to_remote_test.go | 15 +++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/pull_files_from_remote_test.go b/pull_files_from_remote_test.go index 8b05b3a4..3ae1a341 100644 --- a/pull_files_from_remote_test.go +++ b/pull_files_from_remote_test.go @@ -1,3 +1,18 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package oras_test import ( diff --git a/pull_image_from_remote_test.go b/pull_image_from_remote_test.go index cf9ad2d3..5b6c529a 100644 --- a/pull_image_from_remote_test.go +++ b/pull_image_from_remote_test.go @@ -1,3 +1,18 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package oras_test import ( diff --git a/pull_image_using_docker_store_test.go b/pull_image_using_docker_store_test.go index fc9aadc8..8b45e567 100644 --- a/pull_image_using_docker_store_test.go +++ b/pull_image_using_docker_store_test.go @@ -1,3 +1,18 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package oras_test import ( diff --git a/push_files_to_remote_test.go b/push_files_to_remote_test.go index 3d5ad381..d26ae225 100644 --- a/push_files_to_remote_test.go +++ b/push_files_to_remote_test.go @@ -1,3 +1,18 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package oras_test import ( From 428b3be94aa6ddb181ac6eb10ae4853becf79cf1 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Wed, 2 Aug 2023 09:22:03 +0000 Subject: [PATCH 04/10] removed the credentials example Signed-off-by: Xiaoxuan Wang --- go.mod | 1 - go.sum | 2 - pull_image_using_docker_store_test.go | 83 --------------------------- 3 files changed, 86 deletions(-) delete mode 100644 pull_image_using_docker_store_test.go diff --git a/go.mod b/go.mod index 6c817606..747de6eb 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,5 @@ go 1.19 require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc4 - github.com/oras-project/oras-credentials-go v0.3.0 golang.org/x/sync v0.3.0 ) diff --git a/go.sum b/go.sum index eb4f30c3..e391513b 100644 --- a/go.sum +++ b/go.sum @@ -2,7 +2,5 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/oras-project/oras-credentials-go v0.3.0 h1:Bg1d9iAmgo50RlaIy2XI5MQs7qL00DB3R9Q4JRP1VWs= -github.com/oras-project/oras-credentials-go v0.3.0/go.mod h1:fFCebDQo0Do+gnM96uV9YUnRay0pwuRQupypvofsp4s= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= diff --git a/pull_image_using_docker_store_test.go b/pull_image_using_docker_store_test.go deleted file mode 100644 index 8b45e567..00000000 --- a/pull_image_using_docker_store_test.go +++ /dev/null @@ -1,83 +0,0 @@ -/* -Copyright The ORAS Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package oras_test - -import ( - "context" - "fmt" - - credentials "github.com/oras-project/oras-credentials-go" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/oci" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/retry" -) - -func pullImageUsingDockerCredentialStore() error { - - // 0. Create an OCI layout store - store, err := oci.New("/tmp/oci-layout-root") - if err != nil { - return err - } - - // 1. Connect to a remote repository - ctx := context.Background() - reg := "docker.io" - repo, err := remote.NewRepository(reg + "/user/my-repo") - if err != nil { - return err - } - - // 2. Get credentials from the docker credential store - storeOpts := credentials.StoreOptions{} - credStore, err := credentials.NewStoreFromDocker(storeOpts) - if err != nil { - return err - } - - // Prepare the auth client for the registry and credential store - repo.Client = &auth.Client{ - Client: retry.DefaultClient, - Cache: auth.DefaultCache, - Credential: credentials.Credential(credStore), // Use the credential store - } - - // 3. Copy from the remote repository to the OCI layout store - tag := "latest" - manifestDescriptor, err := oras.Copy(ctx, repo, tag, store, tag, oras.DefaultCopyOptions) - if err != nil { - return err - } - - fmt.Println("manifest pulled:", manifestDescriptor.Digest, manifestDescriptor.MediaType) - - // 3. Fetch from OCI layout store to verify - fetched, err := content.FetchAll(ctx, store, manifestDescriptor) - if err != nil { - return err - } - fmt.Printf("manifest content:\n%s", fetched) - return nil -} - -func Example_pullImageUsingDockerCredentialStore() { - if err := pullImageUsingDockerCredentialStore(); err != nil { - panic(err) - } -} From 04ab04648cc680d5163843264248170696f99a56 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Wed, 2 Aug 2023 09:32:37 +0000 Subject: [PATCH 05/10] refactored the code Signed-off-by: Xiaoxuan Wang --- ...o_remote_test.go => larger_example_test.go | 92 +++++++++++++++++-- pull_files_from_remote_test.go | 68 -------------- pull_image_from_remote_test.go | 75 --------------- 3 files changed, 82 insertions(+), 153 deletions(-) rename push_files_to_remote_test.go => larger_example_test.go (52%) delete mode 100644 pull_files_from_remote_test.go delete mode 100644 pull_image_from_remote_test.go diff --git a/push_files_to_remote_test.go b/larger_example_test.go similarity index 52% rename from push_files_to_remote_test.go rename to larger_example_test.go index d26ae225..d855a6c6 100644 --- a/push_files_to_remote_test.go +++ b/larger_example_test.go @@ -21,17 +21,93 @@ import ( v1 "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras-go/v2" + "oras.land/oras-go/v2/content" "oras.land/oras-go/v2/content/file" + "oras.land/oras-go/v2/content/oci" "oras.land/oras-go/v2/registry/remote" "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras-go/v2/registry/remote/retry" ) -func pushFiles() error { +func Example_pullFilesFromRemoteRepository() { // 0. Create a file store fs, err := file.New("/tmp/") if err != nil { - return err + panic(err) + } + defer fs.Close() + + // 1. Connect to a remote repository + ctx := context.Background() + reg := "myregistry.example.com" + repo, err := remote.NewRepository(reg + "/myrepo") + if err != nil { + panic(err) + } + // Note: The below code can be omitted if authentication is not required + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: auth.StaticCredential(reg, auth.Credential{ + Username: "username", + Password: "password", + }), + } + + // 2. Copy from the remote repository to the file store + tag := "latest" + manifestDescriptor, err := oras.Copy(ctx, repo, tag, fs, tag, oras.DefaultCopyOptions) + if err != nil { + panic(err) + } + fmt.Println("manifest descriptor:", manifestDescriptor) +} + +func Example_pullImageFromRemoteRepository() { + // 0. Create an OCI layout store + store, err := oci.New("/tmp/oci-layout-root") + if err != nil { + panic(err) + } + + // 1. Connect to a remote repository + ctx := context.Background() + reg := "myregistry.example.com" + repo, err := remote.NewRepository(reg + "/myrepo") + if err != nil { + panic(err) + } + // Note: The below code can be omitted if authentication is not required + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: auth.StaticCredential(reg, auth.Credential{ + Username: "username", + Password: "password", + }), + } + + // 2. Copy from the remote repository to the OCI layout store + tag := "latest" + manifestDescriptor, err := oras.Copy(ctx, repo, tag, store, tag, oras.DefaultCopyOptions) + if err != nil { + panic(err) + } + fmt.Println("manifest pulled:", manifestDescriptor.Digest, manifestDescriptor.MediaType) + + // 3. Fetch from OCI layout store to verify + fetched, err := content.FetchAll(ctx, store, manifestDescriptor) + if err != nil { + panic(err) + } + fmt.Printf("manifest content:\n%s", fetched) +} + +func Example_pushFilesToRemoteRepository() { + // 0. Create a file store + fs, err := file.New("/tmp/") + if err != nil { + panic(err) } defer fs.Close() ctx := context.Background() @@ -43,7 +119,7 @@ func pushFiles() error { for _, name := range fileNames { fileDescriptor, err := fs.Add(ctx, name, mediaType, "") if err != nil { - return err + panic(err) } fileDescriptors = append(fileDescriptors, fileDescriptor) fmt.Printf("file descriptor for %s: %v\n", name, fileDescriptor) @@ -53,13 +129,13 @@ func pushFiles() error { artifactType := "example/files" manifestDescriptor, err := oras.Pack(ctx, fs, artifactType, fileDescriptors, oras.DefaultPackOptions) if err != nil { - return err + panic(err) } fmt.Println("manifest descriptor:", manifestDescriptor) tag := "latest" if err = fs.Tag(ctx, manifestDescriptor, tag); err != nil { - return err + panic(err) } // 3. Connect to a remote repository @@ -80,11 +156,7 @@ func pushFiles() error { // 3. Copy from the file store to the remote repository _, err = oras.Copy(ctx, fs, tag, repo, tag, oras.DefaultCopyOptions) - return err -} - -func Example_pushFilesToRemoteRepository() { - if err := pushFiles(); err != nil { + if err != nil { panic(err) } } diff --git a/pull_files_from_remote_test.go b/pull_files_from_remote_test.go deleted file mode 100644 index 3ae1a341..00000000 --- a/pull_files_from_remote_test.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright The ORAS Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package oras_test - -import ( - "context" - "fmt" - - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content/file" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/retry" -) - -func pullFiles() error { - // 0. Create a file store - fs, err := file.New("/tmp/") - if err != nil { - return err - } - defer fs.Close() - - // 1. Connect to a remote repository - ctx := context.Background() - reg := "myregistry.example.com" - repo, err := remote.NewRepository(reg + "/myrepo") - if err != nil { - return err - } - // Note: The below code can be omitted if authentication is not required - repo.Client = &auth.Client{ - Client: retry.DefaultClient, - Cache: auth.DefaultCache, - Credential: auth.StaticCredential(reg, auth.Credential{ - Username: "username", - Password: "password", - }), - } - - // 2. Copy from the remote repository to the file store - tag := "latest" - manifestDescriptor, err := oras.Copy(ctx, repo, tag, fs, tag, oras.DefaultCopyOptions) - if err != nil { - return err - } - fmt.Println("manifest descriptor:", manifestDescriptor) - return nil -} - -func Example_pullFilesFromRemoteRepository() { - if err := pullFiles(); err != nil { - panic(err) - } -} diff --git a/pull_image_from_remote_test.go b/pull_image_from_remote_test.go deleted file mode 100644 index 5b6c529a..00000000 --- a/pull_image_from_remote_test.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright The ORAS Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package oras_test - -import ( - "context" - "fmt" - - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/oci" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/retry" -) - -func pullImageFromRemote() error { - // 0. Create an OCI layout store - store, err := oci.New("/tmp/oci-layout-root") - if err != nil { - return err - } - - // 1. Connect to a remote repository - ctx := context.Background() - reg := "myregistry.example.com" - repo, err := remote.NewRepository(reg + "/myrepo") - if err != nil { - return err - } - // Note: The below code can be omitted if authentication is not required - repo.Client = &auth.Client{ - Client: retry.DefaultClient, - Cache: auth.DefaultCache, - Credential: auth.StaticCredential(reg, auth.Credential{ - Username: "username", - Password: "password", - }), - } - - // 2. Copy from the remote repository to the OCI layout store - tag := "latest" - manifestDescriptor, err := oras.Copy(ctx, repo, tag, store, tag, oras.DefaultCopyOptions) - if err != nil { - return err - } - fmt.Println("manifest pulled:", manifestDescriptor.Digest, manifestDescriptor.MediaType) - - // 3. Fetch from OCI layout store to verify - fetched, err := content.FetchAll(ctx, store, manifestDescriptor) - if err != nil { - return err - } - fmt.Printf("manifest content:\n%s", fetched) - return nil -} - -func Example_pullImageFromRemoteRepository() { - if err := pullImageFromRemote(); err != nil { - panic(err) - } -} From e10b179b42f1b5245757bb7f02e2c1b0b3dba4b1 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Thu, 3 Aug 2023 07:10:34 +0000 Subject: [PATCH 06/10] resolved the comments Signed-off-by: Xiaoxuan Wang --- example_copy_test.go | 356 ++++++++++++++++++++++++++++++++++++++++ example_test.go | 364 +++++++++-------------------------------- larger_example_test.go | 162 ------------------ 3 files changed, 437 insertions(+), 445 deletions(-) create mode 100644 example_copy_test.go delete mode 100644 larger_example_test.go diff --git a/example_copy_test.go b/example_copy_test.go new file mode 100644 index 00000000..91fb9da0 --- /dev/null +++ b/example_copy_test.go @@ -0,0 +1,356 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package oras_test + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "os" + "strconv" + "strings" + "testing" + + "github.com/opencontainers/go-digest" + specs "github.com/opencontainers/image-spec/specs-go" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras-go/v2" + "oras.land/oras-go/v2/content/memory" + "oras.land/oras-go/v2/content/oci" + "oras.land/oras-go/v2/internal/spec" + "oras.land/oras-go/v2/registry/remote" +) + +var exampleMemoryStore oras.Target +var remoteHost string +var ( + exampleManifest, _ = json.Marshal(spec.Artifact{ + MediaType: spec.MediaTypeArtifactManifest, + ArtifactType: "example/content"}) + exampleManifestDescriptor = ocispec.Descriptor{ + MediaType: spec.MediaTypeArtifactManifest, + Digest: digest.Digest(digest.FromBytes(exampleManifest)), + Size: int64(len(exampleManifest))} + exampleSignatureManifest, _ = json.Marshal(spec.Artifact{ + MediaType: spec.MediaTypeArtifactManifest, + ArtifactType: "example/signature", + Subject: &exampleManifestDescriptor}) + exampleSignatureManifestDescriptor = ocispec.Descriptor{ + MediaType: spec.MediaTypeArtifactManifest, + Digest: digest.FromBytes(exampleSignatureManifest), + Size: int64(len(exampleSignatureManifest))} +) + +func pushBlob(ctx context.Context, mediaType string, blob []byte, target oras.Target) (desc ocispec.Descriptor, err error) { + desc = ocispec.Descriptor{ // Generate descriptor based on the media type and blob content + MediaType: mediaType, + Digest: digest.FromBytes(blob), // Calculate digest + Size: int64(len(blob)), // Include blob size + } + return desc, target.Push(ctx, desc, bytes.NewReader(blob)) // Push the blob to the registry target +} + +func generateManifestContent(config ocispec.Descriptor, layers ...ocispec.Descriptor) ([]byte, error) { + content := ocispec.Manifest{ + Config: config, // Set config blob + Layers: layers, // Set layer blobs + Versioned: specs.Versioned{SchemaVersion: 2}, + } + return json.Marshal(content) // Get json content +} + +func TestMain(m *testing.M) { + const exampleTag = "latest" + const exampleUploadUUid = "0bc84d80-837c-41d9-824e-1907463c53b3" + + // Setup example local target + exampleMemoryStore = memory.New() + layerBlob := []byte("Hello layer") + ctx := context.Background() + layerDesc, err := pushBlob(ctx, ocispec.MediaTypeImageLayer, layerBlob, exampleMemoryStore) // push layer blob + if err != nil { + panic(err) + } + configBlob := []byte("Hello config") + configDesc, err := pushBlob(ctx, ocispec.MediaTypeImageConfig, configBlob, exampleMemoryStore) // push config blob + if err != nil { + panic(err) + } + manifestBlob, err := generateManifestContent(configDesc, layerDesc) // generate a image manifest + if err != nil { + panic(err) + } + manifestDesc, err := pushBlob(ctx, ocispec.MediaTypeImageManifest, manifestBlob, exampleMemoryStore) // push manifest blob + if err != nil { + panic(err) + } + err = exampleMemoryStore.Tag(ctx, manifestDesc, exampleTag) + if err != nil { + panic(err) + } + + // Setup example remote target + httpsServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + p := r.URL.Path + m := r.Method + switch { + case strings.Contains(p, "/blobs/uploads/") && m == "POST": + w.Header().Set("Content-Type", ocispec.MediaTypeImageManifest) + w.Header().Set("Location", p+exampleUploadUUid) + w.WriteHeader(http.StatusAccepted) + case strings.Contains(p, "/blobs/uploads/"+exampleUploadUUid) && m == "GET": + w.WriteHeader(http.StatusCreated) + case strings.Contains(p, "/manifests/"+string(exampleSignatureManifestDescriptor.Digest)): + w.Header().Set("Content-Type", spec.MediaTypeArtifactManifest) + w.Header().Set("Docker-Content-Digest", string(exampleSignatureManifestDescriptor.Digest)) + w.Header().Set("Content-Length", strconv.Itoa(len(exampleSignatureManifest))) + w.Write(exampleSignatureManifest) + case strings.Contains(p, "/manifests/latest") && m == "PUT": + w.WriteHeader(http.StatusCreated) + case strings.Contains(p, "/manifests/"+string(exampleManifestDescriptor.Digest)), + strings.Contains(p, "/manifests/latest") && m == "HEAD": + w.Header().Set("Content-Type", spec.MediaTypeArtifactManifest) + w.Header().Set("Docker-Content-Digest", string(exampleManifestDescriptor.Digest)) + w.Header().Set("Content-Length", strconv.Itoa(len(exampleManifest))) + if m == "GET" { + w.Write(exampleManifest) + } + case strings.Contains(p, "/v2/source/referrers/"): + var referrers []ocispec.Descriptor + if p == "/v2/source/referrers/"+exampleManifestDescriptor.Digest.String() { + referrers = []ocispec.Descriptor{exampleSignatureManifestDescriptor} + } + result := ocispec.Index{ + Versioned: specs.Versioned{ + SchemaVersion: 2, // historical value. does not pertain to OCI or docker version + }, + MediaType: ocispec.MediaTypeImageIndex, + Manifests: referrers, + } + if err := json.NewEncoder(w).Encode(result); err != nil { + panic(err) + } + case strings.Contains(p, "/manifests/") && (m == "HEAD" || m == "GET"): + w.Header().Set("Content-Type", ocispec.MediaTypeImageManifest) + w.Header().Set("Docker-Content-Digest", string(manifestDesc.Digest)) + w.Header().Set("Content-Length", strconv.Itoa(len([]byte(manifestBlob)))) + w.Write([]byte(manifestBlob)) + case strings.Contains(p, "/blobs/") && (m == "GET" || m == "HEAD"): + arr := strings.Split(p, "/") + digest := arr[len(arr)-1] + var desc ocispec.Descriptor + var content []byte + switch digest { + case layerDesc.Digest.String(): + desc = layerDesc + content = layerBlob + case configDesc.Digest.String(): + desc = configDesc + content = configBlob + case manifestDesc.Digest.String(): + desc = manifestDesc + content = manifestBlob + } + w.Header().Set("Content-Type", desc.MediaType) + w.Header().Set("Docker-Content-Digest", digest) + w.Header().Set("Content-Length", strconv.Itoa(len([]byte(content)))) + w.Write([]byte(content)) + case strings.Contains(p, "/manifests/") && m == "PUT": + w.WriteHeader(http.StatusCreated) + } + + })) + defer httpsServer.Close() + u, err := url.Parse(httpsServer.URL) + if err != nil { + panic(err) + } + remoteHost = u.Host + http.DefaultTransport = httpsServer.Client().Transport + + os.Exit(m.Run()) +} + +func ExampleCopy_remoteToRemote() { + reg, err := remote.NewRegistry(remoteHost) + if err != nil { + panic(err) // Handle error + } + ctx := context.Background() + src, err := reg.Repository(ctx, "source") + if err != nil { + panic(err) // Handle error + } + dst, err := reg.Repository(ctx, "target") + if err != nil { + panic(err) // Handle error + } + + tagName := "latest" + desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) + if err != nil { + panic(err) // Handle error + } + fmt.Println(desc.Digest) + + // Output: + // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 +} + +func ExampleCopy_remoteToLocal() { + reg, err := remote.NewRegistry(remoteHost) + if err != nil { + panic(err) // Handle error + } + + ctx := context.Background() + src, err := reg.Repository(ctx, "source") + if err != nil { + panic(err) // Handle error + } + dst := memory.New() + + tagName := "latest" + desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) + if err != nil { + panic(err) // Handle error + } + fmt.Println(desc.Digest) + + // Output: + // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 +} + +func ExampleCopy_localToLocal() { + src := exampleMemoryStore + dst := memory.New() + + tagName := "latest" + ctx := context.Background() + desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) + if err != nil { + panic(err) // Handle error + } + fmt.Println(desc.Digest) + + // Output: + // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 +} + +func ExampleCopy_localToOciFile() { + src := exampleMemoryStore + tempDir, err := os.MkdirTemp("", "oras_oci_example_*") + if err != nil { + panic(err) // Handle error + } + defer os.RemoveAll(tempDir) + dst, err := oci.New(tempDir) + if err != nil { + panic(err) // Handle error + } + + tagName := "latest" + ctx := context.Background() + desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) + if err != nil { + panic(err) // Handle error + } + fmt.Println(desc.Digest) + + // Output: + // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 +} + +func ExampleCopy_localToRemote() { + src := exampleMemoryStore + reg, err := remote.NewRegistry(remoteHost) + if err != nil { + panic(err) // Handle error + } + ctx := context.Background() + dst, err := reg.Repository(ctx, "target") + if err != nil { + panic(err) // Handle error + } + + tagName := "latest" + desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) + if err != nil { + panic(err) // Handle error + } + fmt.Println(desc.Digest) + + // Output: + // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 +} + +// Example_copyArtifactManifestRemoteToLocal gives an example of copying +// an artifact manifest from a remote repository to local. +func Example_copyArtifactManifestRemoteToLocal() { + src, err := remote.NewRepository(fmt.Sprintf("%s/source", remoteHost)) + if err != nil { + panic(err) + } + dst := memory.New() + ctx := context.Background() + + exampleDigest := "sha256:70c29a81e235dda5c2cebb8ec06eafd3cca346cbd91f15ac74cefd98681c5b3d" + descriptor, err := src.Resolve(ctx, exampleDigest) + if err != nil { + panic(err) + } + err = oras.CopyGraph(ctx, src, dst, descriptor, oras.DefaultCopyGraphOptions) + if err != nil { + panic(err) + } + + // verify that the artifact manifest described by the descriptor exists in dst + contentExists, err := dst.Exists(ctx, descriptor) + if err != nil { + panic(err) + } + fmt.Println(contentExists) + + // Output: + // true +} + +// Example_extendedCopyArtifactAndReferrersRemoteToLocal gives an example of +// copying an artifact along with its referrers from a remote repository to local. +func Example_extendedCopyArtifactAndReferrersRemoteToLocal() { + src, err := remote.NewRepository(fmt.Sprintf("%s/source", remoteHost)) + if err != nil { + panic(err) + } + dst := memory.New() + ctx := context.Background() + + tagName := "latest" + // ExtendedCopy will copy the artifact tagged by "latest" along with all of its + // referrers from src to dst. + desc, err := oras.ExtendedCopy(ctx, src, tagName, dst, tagName, oras.DefaultExtendedCopyOptions) + if err != nil { + panic(err) + } + + fmt.Println(desc.Digest) + // Output: + // sha256:f396bc4d300934a39ca28ab0d5ac8a3573336d7d63c654d783a68cd1e2057662 +} diff --git a/example_test.go b/example_test.go index 91fb9da0..427451f0 100644 --- a/example_test.go +++ b/example_test.go @@ -16,341 +16,139 @@ limitations under the License. package oras_test import ( - "bytes" "context" - "encoding/json" "fmt" - "net/http" - "net/http/httptest" - "net/url" - "os" - "strconv" - "strings" - "testing" - "github.com/opencontainers/go-digest" - specs "github.com/opencontainers/image-spec/specs-go" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content/memory" + "oras.land/oras-go/v2/content/file" "oras.land/oras-go/v2/content/oci" - "oras.land/oras-go/v2/internal/spec" "oras.land/oras-go/v2/registry/remote" + "oras.land/oras-go/v2/registry/remote/auth" + "oras.land/oras-go/v2/registry/remote/retry" ) -var exampleMemoryStore oras.Target -var remoteHost string -var ( - exampleManifest, _ = json.Marshal(spec.Artifact{ - MediaType: spec.MediaTypeArtifactManifest, - ArtifactType: "example/content"}) - exampleManifestDescriptor = ocispec.Descriptor{ - MediaType: spec.MediaTypeArtifactManifest, - Digest: digest.Digest(digest.FromBytes(exampleManifest)), - Size: int64(len(exampleManifest))} - exampleSignatureManifest, _ = json.Marshal(spec.Artifact{ - MediaType: spec.MediaTypeArtifactManifest, - ArtifactType: "example/signature", - Subject: &exampleManifestDescriptor}) - exampleSignatureManifestDescriptor = ocispec.Descriptor{ - MediaType: spec.MediaTypeArtifactManifest, - Digest: digest.FromBytes(exampleSignatureManifest), - Size: int64(len(exampleSignatureManifest))} -) - -func pushBlob(ctx context.Context, mediaType string, blob []byte, target oras.Target) (desc ocispec.Descriptor, err error) { - desc = ocispec.Descriptor{ // Generate descriptor based on the media type and blob content - MediaType: mediaType, - Digest: digest.FromBytes(blob), // Calculate digest - Size: int64(len(blob)), // Include blob size - } - return desc, target.Push(ctx, desc, bytes.NewReader(blob)) // Push the blob to the registry target -} - -func generateManifestContent(config ocispec.Descriptor, layers ...ocispec.Descriptor) ([]byte, error) { - content := ocispec.Manifest{ - Config: config, // Set config blob - Layers: layers, // Set layer blobs - Versioned: specs.Versioned{SchemaVersion: 2}, - } - return json.Marshal(content) // Get json content -} - -func TestMain(m *testing.M) { - const exampleTag = "latest" - const exampleUploadUUid = "0bc84d80-837c-41d9-824e-1907463c53b3" - - // Setup example local target - exampleMemoryStore = memory.New() - layerBlob := []byte("Hello layer") - ctx := context.Background() - layerDesc, err := pushBlob(ctx, ocispec.MediaTypeImageLayer, layerBlob, exampleMemoryStore) // push layer blob - if err != nil { - panic(err) - } - configBlob := []byte("Hello config") - configDesc, err := pushBlob(ctx, ocispec.MediaTypeImageConfig, configBlob, exampleMemoryStore) // push config blob - if err != nil { - panic(err) - } - manifestBlob, err := generateManifestContent(configDesc, layerDesc) // generate a image manifest - if err != nil { - panic(err) - } - manifestDesc, err := pushBlob(ctx, ocispec.MediaTypeImageManifest, manifestBlob, exampleMemoryStore) // push manifest blob +func Example_pullFilesFromRemoteRepository() { + // 0. Create a file store + fs, err := file.New("/tmp/") if err != nil { panic(err) } - err = exampleMemoryStore.Tag(ctx, manifestDesc, exampleTag) - if err != nil { - panic(err) - } - - // Setup example remote target - httpsServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - p := r.URL.Path - m := r.Method - switch { - case strings.Contains(p, "/blobs/uploads/") && m == "POST": - w.Header().Set("Content-Type", ocispec.MediaTypeImageManifest) - w.Header().Set("Location", p+exampleUploadUUid) - w.WriteHeader(http.StatusAccepted) - case strings.Contains(p, "/blobs/uploads/"+exampleUploadUUid) && m == "GET": - w.WriteHeader(http.StatusCreated) - case strings.Contains(p, "/manifests/"+string(exampleSignatureManifestDescriptor.Digest)): - w.Header().Set("Content-Type", spec.MediaTypeArtifactManifest) - w.Header().Set("Docker-Content-Digest", string(exampleSignatureManifestDescriptor.Digest)) - w.Header().Set("Content-Length", strconv.Itoa(len(exampleSignatureManifest))) - w.Write(exampleSignatureManifest) - case strings.Contains(p, "/manifests/latest") && m == "PUT": - w.WriteHeader(http.StatusCreated) - case strings.Contains(p, "/manifests/"+string(exampleManifestDescriptor.Digest)), - strings.Contains(p, "/manifests/latest") && m == "HEAD": - w.Header().Set("Content-Type", spec.MediaTypeArtifactManifest) - w.Header().Set("Docker-Content-Digest", string(exampleManifestDescriptor.Digest)) - w.Header().Set("Content-Length", strconv.Itoa(len(exampleManifest))) - if m == "GET" { - w.Write(exampleManifest) - } - case strings.Contains(p, "/v2/source/referrers/"): - var referrers []ocispec.Descriptor - if p == "/v2/source/referrers/"+exampleManifestDescriptor.Digest.String() { - referrers = []ocispec.Descriptor{exampleSignatureManifestDescriptor} - } - result := ocispec.Index{ - Versioned: specs.Versioned{ - SchemaVersion: 2, // historical value. does not pertain to OCI or docker version - }, - MediaType: ocispec.MediaTypeImageIndex, - Manifests: referrers, - } - if err := json.NewEncoder(w).Encode(result); err != nil { - panic(err) - } - case strings.Contains(p, "/manifests/") && (m == "HEAD" || m == "GET"): - w.Header().Set("Content-Type", ocispec.MediaTypeImageManifest) - w.Header().Set("Docker-Content-Digest", string(manifestDesc.Digest)) - w.Header().Set("Content-Length", strconv.Itoa(len([]byte(manifestBlob)))) - w.Write([]byte(manifestBlob)) - case strings.Contains(p, "/blobs/") && (m == "GET" || m == "HEAD"): - arr := strings.Split(p, "/") - digest := arr[len(arr)-1] - var desc ocispec.Descriptor - var content []byte - switch digest { - case layerDesc.Digest.String(): - desc = layerDesc - content = layerBlob - case configDesc.Digest.String(): - desc = configDesc - content = configBlob - case manifestDesc.Digest.String(): - desc = manifestDesc - content = manifestBlob - } - w.Header().Set("Content-Type", desc.MediaType) - w.Header().Set("Docker-Content-Digest", digest) - w.Header().Set("Content-Length", strconv.Itoa(len([]byte(content)))) - w.Write([]byte(content)) - case strings.Contains(p, "/manifests/") && m == "PUT": - w.WriteHeader(http.StatusCreated) - } + defer fs.Close() - })) - defer httpsServer.Close() - u, err := url.Parse(httpsServer.URL) - if err != nil { - panic(err) - } - remoteHost = u.Host - http.DefaultTransport = httpsServer.Client().Transport - - os.Exit(m.Run()) -} - -func ExampleCopy_remoteToRemote() { - reg, err := remote.NewRegistry(remoteHost) - if err != nil { - panic(err) // Handle error - } + // 1. Connect to a remote repository ctx := context.Background() - src, err := reg.Repository(ctx, "source") + reg := "myregistry.example.com" + repo, err := remote.NewRepository(reg + "/myrepo") if err != nil { - panic(err) // Handle error + panic(err) } - dst, err := reg.Repository(ctx, "target") - if err != nil { - panic(err) // Handle error + // Note: The below code can be omitted if authentication is not required + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: auth.StaticCredential(reg, auth.Credential{ + Username: "username", + Password: "password", + }), } - tagName := "latest" - desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) + // 2. Copy from the remote repository to the file store + tag := "latest" + manifestDescriptor, err := oras.Copy(ctx, repo, tag, fs, tag, oras.DefaultCopyOptions) if err != nil { - panic(err) // Handle error + panic(err) } - fmt.Println(desc.Digest) - - // Output: - // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 + fmt.Println("manifest descriptor:", manifestDescriptor) } -func ExampleCopy_remoteToLocal() { - reg, err := remote.NewRegistry(remoteHost) - if err != nil { - panic(err) // Handle error - } - - ctx := context.Background() - src, err := reg.Repository(ctx, "source") - if err != nil { - panic(err) // Handle error - } - dst := memory.New() - - tagName := "latest" - desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) +func Example_pullImageFromRemoteRepository() { + // 0. Create an OCI layout store + store, err := oci.New("/tmp/oci-layout-root") if err != nil { - panic(err) // Handle error + panic(err) } - fmt.Println(desc.Digest) - - // Output: - // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 -} -func ExampleCopy_localToLocal() { - src := exampleMemoryStore - dst := memory.New() - - tagName := "latest" + // 1. Connect to a remote repository ctx := context.Background() - desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) + reg := "myregistry.example.com" + repo, err := remote.NewRepository(reg + "/myrepo") if err != nil { - panic(err) // Handle error - } - fmt.Println(desc.Digest) - - // Output: - // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 -} - -func ExampleCopy_localToOciFile() { - src := exampleMemoryStore - tempDir, err := os.MkdirTemp("", "oras_oci_example_*") - if err != nil { - panic(err) // Handle error + panic(err) } - defer os.RemoveAll(tempDir) - dst, err := oci.New(tempDir) - if err != nil { - panic(err) // Handle error + // Note: The below code can be omitted if authentication is not required + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: auth.StaticCredential(reg, auth.Credential{ + Username: "username", + Password: "password", + }), } - tagName := "latest" - ctx := context.Background() - desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) + // 2. Copy from the remote repository to the OCI layout store + tag := "latest" + manifestDescriptor, err := oras.Copy(ctx, repo, tag, store, tag, oras.DefaultCopyOptions) if err != nil { - panic(err) // Handle error + panic(err) } - fmt.Println(desc.Digest) - - // Output: - // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 + fmt.Println("manifest descriptor:", manifestDescriptor) } -func ExampleCopy_localToRemote() { - src := exampleMemoryStore - reg, err := remote.NewRegistry(remoteHost) +func Example_pushFilesToRemoteRepository() { + // 0. Create a file store + fs, err := file.New("/tmp/") if err != nil { - panic(err) // Handle error + panic(err) } + defer fs.Close() ctx := context.Background() - dst, err := reg.Repository(ctx, "target") - if err != nil { - panic(err) // Handle error - } - tagName := "latest" - desc, err := oras.Copy(ctx, src, tagName, dst, tagName, oras.DefaultCopyOptions) - if err != nil { - panic(err) // Handle error + // 1. Add files to a file store + mediaType := "example/file" + fileNames := []string{"/tmp/myfile"} + fileDescriptors := make([]v1.Descriptor, 0, len(fileNames)) + for _, name := range fileNames { + fileDescriptor, err := fs.Add(ctx, name, mediaType, "") + if err != nil { + panic(err) + } + fileDescriptors = append(fileDescriptors, fileDescriptor) + fmt.Printf("file descriptor for %s: %v\n", name, fileDescriptor) } - fmt.Println(desc.Digest) - // Output: - // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 -} - -// Example_copyArtifactManifestRemoteToLocal gives an example of copying -// an artifact manifest from a remote repository to local. -func Example_copyArtifactManifestRemoteToLocal() { - src, err := remote.NewRepository(fmt.Sprintf("%s/source", remoteHost)) + // 2. Pack the files and tag the packed manifest + artifactType := "example/files" + manifestDescriptor, err := oras.Pack(ctx, fs, artifactType, fileDescriptors, oras.DefaultPackOptions) if err != nil { panic(err) } - dst := memory.New() - ctx := context.Background() + fmt.Println("manifest descriptor:", manifestDescriptor) - exampleDigest := "sha256:70c29a81e235dda5c2cebb8ec06eafd3cca346cbd91f15ac74cefd98681c5b3d" - descriptor, err := src.Resolve(ctx, exampleDigest) - if err != nil { - panic(err) - } - err = oras.CopyGraph(ctx, src, dst, descriptor, oras.DefaultCopyGraphOptions) - if err != nil { + tag := "latest" + if err = fs.Tag(ctx, manifestDescriptor, tag); err != nil { panic(err) } - // verify that the artifact manifest described by the descriptor exists in dst - contentExists, err := dst.Exists(ctx, descriptor) + // 3. Connect to a remote repository + reg := "myregistry.example.com" + repo, err := remote.NewRepository(reg + "/myrepo") if err != nil { panic(err) } - fmt.Println(contentExists) - - // Output: - // true -} - -// Example_extendedCopyArtifactAndReferrersRemoteToLocal gives an example of -// copying an artifact along with its referrers from a remote repository to local. -func Example_extendedCopyArtifactAndReferrersRemoteToLocal() { - src, err := remote.NewRepository(fmt.Sprintf("%s/source", remoteHost)) - if err != nil { - panic(err) + // Note: The below code can be omitted if authentication is not required + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.DefaultCache, + Credential: auth.StaticCredential(reg, auth.Credential{ + Username: "username", + Password: "password", + }), } - dst := memory.New() - ctx := context.Background() - tagName := "latest" - // ExtendedCopy will copy the artifact tagged by "latest" along with all of its - // referrers from src to dst. - desc, err := oras.ExtendedCopy(ctx, src, tagName, dst, tagName, oras.DefaultExtendedCopyOptions) + // 3. Copy from the file store to the remote repository + _, err = oras.Copy(ctx, fs, tag, repo, tag, oras.DefaultCopyOptions) if err != nil { panic(err) } - - fmt.Println(desc.Digest) - // Output: - // sha256:f396bc4d300934a39ca28ab0d5ac8a3573336d7d63c654d783a68cd1e2057662 } diff --git a/larger_example_test.go b/larger_example_test.go deleted file mode 100644 index d855a6c6..00000000 --- a/larger_example_test.go +++ /dev/null @@ -1,162 +0,0 @@ -/* -Copyright The ORAS Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package oras_test - -import ( - "context" - "fmt" - - v1 "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/file" - "oras.land/oras-go/v2/content/oci" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/retry" -) - -func Example_pullFilesFromRemoteRepository() { - // 0. Create a file store - fs, err := file.New("/tmp/") - if err != nil { - panic(err) - } - defer fs.Close() - - // 1. Connect to a remote repository - ctx := context.Background() - reg := "myregistry.example.com" - repo, err := remote.NewRepository(reg + "/myrepo") - if err != nil { - panic(err) - } - // Note: The below code can be omitted if authentication is not required - repo.Client = &auth.Client{ - Client: retry.DefaultClient, - Cache: auth.DefaultCache, - Credential: auth.StaticCredential(reg, auth.Credential{ - Username: "username", - Password: "password", - }), - } - - // 2. Copy from the remote repository to the file store - tag := "latest" - manifestDescriptor, err := oras.Copy(ctx, repo, tag, fs, tag, oras.DefaultCopyOptions) - if err != nil { - panic(err) - } - fmt.Println("manifest descriptor:", manifestDescriptor) -} - -func Example_pullImageFromRemoteRepository() { - // 0. Create an OCI layout store - store, err := oci.New("/tmp/oci-layout-root") - if err != nil { - panic(err) - } - - // 1. Connect to a remote repository - ctx := context.Background() - reg := "myregistry.example.com" - repo, err := remote.NewRepository(reg + "/myrepo") - if err != nil { - panic(err) - } - // Note: The below code can be omitted if authentication is not required - repo.Client = &auth.Client{ - Client: retry.DefaultClient, - Cache: auth.DefaultCache, - Credential: auth.StaticCredential(reg, auth.Credential{ - Username: "username", - Password: "password", - }), - } - - // 2. Copy from the remote repository to the OCI layout store - tag := "latest" - manifestDescriptor, err := oras.Copy(ctx, repo, tag, store, tag, oras.DefaultCopyOptions) - if err != nil { - panic(err) - } - fmt.Println("manifest pulled:", manifestDescriptor.Digest, manifestDescriptor.MediaType) - - // 3. Fetch from OCI layout store to verify - fetched, err := content.FetchAll(ctx, store, manifestDescriptor) - if err != nil { - panic(err) - } - fmt.Printf("manifest content:\n%s", fetched) -} - -func Example_pushFilesToRemoteRepository() { - // 0. Create a file store - fs, err := file.New("/tmp/") - if err != nil { - panic(err) - } - defer fs.Close() - ctx := context.Background() - - // 1. Add files to a file store - mediaType := "example/file" - fileNames := []string{"/tmp/myfile"} - fileDescriptors := make([]v1.Descriptor, 0, len(fileNames)) - for _, name := range fileNames { - fileDescriptor, err := fs.Add(ctx, name, mediaType, "") - if err != nil { - panic(err) - } - fileDescriptors = append(fileDescriptors, fileDescriptor) - fmt.Printf("file descriptor for %s: %v\n", name, fileDescriptor) - } - - // 2. Pack the files and tag the packed manifest - artifactType := "example/files" - manifestDescriptor, err := oras.Pack(ctx, fs, artifactType, fileDescriptors, oras.DefaultPackOptions) - if err != nil { - panic(err) - } - fmt.Println("manifest descriptor:", manifestDescriptor) - - tag := "latest" - if err = fs.Tag(ctx, manifestDescriptor, tag); err != nil { - panic(err) - } - - // 3. Connect to a remote repository - reg := "myregistry.example.com" - repo, err := remote.NewRepository(reg + "/myrepo") - if err != nil { - panic(err) - } - // Note: The below code can be omitted if authentication is not required - repo.Client = &auth.Client{ - Client: retry.DefaultClient, - Cache: auth.DefaultCache, - Credential: auth.StaticCredential(reg, auth.Credential{ - Username: "username", - Password: "password", - }), - } - - // 3. Copy from the file store to the remote repository - _, err = oras.Copy(ctx, fs, tag, repo, tag, oras.DefaultCopyOptions) - if err != nil { - panic(err) - } -} From 270790f6d11ae1a058960d4bd34699b13cc561db Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Thu, 3 Aug 2023 07:54:06 +0000 Subject: [PATCH 07/10] refined display Signed-off-by: Xiaoxuan Wang --- example_copy_test.go | 4 ++-- example_test.go | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/example_copy_test.go b/example_copy_test.go index 91fb9da0..6efe6463 100644 --- a/example_copy_test.go +++ b/example_copy_test.go @@ -301,7 +301,7 @@ func ExampleCopy_localToRemote() { // sha256:7cbb44b44e8ede5a89cf193db3f5f2fd019d89697e6b87e8ed2589e60649b0d1 } -// Example_copyArtifactManifestRemoteToLocal gives an example of copying +// ExampleCopyArtifactManifestRemoteToLocal gives an example of copying // an artifact manifest from a remote repository to local. func Example_copyArtifactManifestRemoteToLocal() { src, err := remote.NewRepository(fmt.Sprintf("%s/source", remoteHost)) @@ -332,7 +332,7 @@ func Example_copyArtifactManifestRemoteToLocal() { // true } -// Example_extendedCopyArtifactAndReferrersRemoteToLocal gives an example of +// ExampleExtendedCopyArtifactAndReferrersRemoteToLocal gives an example of // copying an artifact along with its referrers from a remote repository to local. func Example_extendedCopyArtifactAndReferrersRemoteToLocal() { src, err := remote.NewRepository(fmt.Sprintf("%s/source", remoteHost)) diff --git a/example_test.go b/example_test.go index 427451f0..697c2575 100644 --- a/example_test.go +++ b/example_test.go @@ -28,6 +28,8 @@ import ( "oras.land/oras-go/v2/registry/remote/retry" ) +// ExamplePullFilesFromRemoteRepository gives an example of pulling files from +// a remote repository. func Example_pullFilesFromRemoteRepository() { // 0. Create a file store fs, err := file.New("/tmp/") @@ -62,6 +64,8 @@ func Example_pullFilesFromRemoteRepository() { fmt.Println("manifest descriptor:", manifestDescriptor) } +// ExamplePullImageFromRemoteRepository gives an example of pulling an image +// tagged "latest" from a remote repository. func Example_pullImageFromRemoteRepository() { // 0. Create an OCI layout store store, err := oci.New("/tmp/oci-layout-root") @@ -95,6 +99,8 @@ func Example_pullImageFromRemoteRepository() { fmt.Println("manifest descriptor:", manifestDescriptor) } +// ExamplePushFilesToRemoteRepository gives an example of pushing local files +// to a remote repository. func Example_pushFilesToRemoteRepository() { // 0. Create a file store fs, err := file.New("/tmp/") @@ -104,7 +110,7 @@ func Example_pushFilesToRemoteRepository() { defer fs.Close() ctx := context.Background() - // 1. Add files to a file store + // 1. Add files to the file store mediaType := "example/file" fileNames := []string{"/tmp/myfile"} fileDescriptors := make([]v1.Descriptor, 0, len(fileNames)) From 38b5211babb17ee713e8a6f74851a49a41a14086 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Thu, 3 Aug 2023 09:31:37 +0000 Subject: [PATCH 08/10] refined the doc comments Signed-off-by: Xiaoxuan Wang --- example_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example_test.go b/example_test.go index 697c2575..691df2e4 100644 --- a/example_test.go +++ b/example_test.go @@ -29,7 +29,7 @@ import ( ) // ExamplePullFilesFromRemoteRepository gives an example of pulling files from -// a remote repository. +// a remote repository to the local file system. func Example_pullFilesFromRemoteRepository() { // 0. Create a file store fs, err := file.New("/tmp/") @@ -65,7 +65,7 @@ func Example_pullFilesFromRemoteRepository() { } // ExamplePullImageFromRemoteRepository gives an example of pulling an image -// tagged "latest" from a remote repository. +// from a remote repository to an OCI Image layout folder. func Example_pullImageFromRemoteRepository() { // 0. Create an OCI layout store store, err := oci.New("/tmp/oci-layout-root") @@ -100,7 +100,7 @@ func Example_pullImageFromRemoteRepository() { } // ExamplePushFilesToRemoteRepository gives an example of pushing local files -// to a remote repository. +// to a remote repository into memory. func Example_pushFilesToRemoteRepository() { // 0. Create a file store fs, err := file.New("/tmp/") From bc6e39184b78561481d5857de7705b1f12a56ac8 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Fri, 4 Aug 2023 05:28:08 +0000 Subject: [PATCH 09/10] fixed my error Signed-off-by: Xiaoxuan Wang --- example_copy_test.go | 2 +- example_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example_copy_test.go b/example_copy_test.go index 6efe6463..c47acaff 100644 --- a/example_copy_test.go +++ b/example_copy_test.go @@ -302,7 +302,7 @@ func ExampleCopy_localToRemote() { } // ExampleCopyArtifactManifestRemoteToLocal gives an example of copying -// an artifact manifest from a remote repository to local. +// an artifact manifest from a remote repository into memory. func Example_copyArtifactManifestRemoteToLocal() { src, err := remote.NewRepository(fmt.Sprintf("%s/source", remoteHost)) if err != nil { diff --git a/example_test.go b/example_test.go index 691df2e4..82b57680 100644 --- a/example_test.go +++ b/example_test.go @@ -100,7 +100,7 @@ func Example_pullImageFromRemoteRepository() { } // ExamplePushFilesToRemoteRepository gives an example of pushing local files -// to a remote repository into memory. +// to a remote repository. func Example_pushFilesToRemoteRepository() { // 0. Create a file store fs, err := file.New("/tmp/") From c7cde4f1a7c95e24a40ec48e5ff0b2aa7a71d423 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Fri, 4 Aug 2023 06:08:52 +0000 Subject: [PATCH 10/10] one more small change Signed-off-by: Xiaoxuan Wang --- example_copy_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example_copy_test.go b/example_copy_test.go index c47acaff..b7e524a9 100644 --- a/example_copy_test.go +++ b/example_copy_test.go @@ -333,7 +333,8 @@ func Example_copyArtifactManifestRemoteToLocal() { } // ExampleExtendedCopyArtifactAndReferrersRemoteToLocal gives an example of -// copying an artifact along with its referrers from a remote repository to local. +// copying an artifact along with its referrers from a remote repository into +// memory. func Example_extendedCopyArtifactAndReferrersRemoteToLocal() { src, err := remote.NewRepository(fmt.Sprintf("%s/source", remoteHost)) if err != nil {