Skip to content

Commit

Permalink
feat: --output for oras manifest index create (#1490)
Browse files Browse the repository at this point in the history
Signed-off-by: Xiaoxuan Wang <[email protected]>
  • Loading branch information
wangxiaoxuan273 authored Sep 12, 2024
1 parent 0baec35 commit a3b0601
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 3 deletions.
27 changes: 24 additions & 3 deletions cmd/oras/root/manifest/index/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"strings"

"github.com/opencontainers/image-spec/specs-go"
Expand All @@ -44,9 +45,11 @@ var maxConfigSize int64 = 4 * 1024 * 1024 // 4 MiB
type createOptions struct {
option.Common
option.Target
option.Pretty

sources []string
extraRefs []string
sources []string
extraRefs []string
outputPath string
}

func createCmd() *cobra.Command {
Expand All @@ -70,6 +73,12 @@ Example - create an index and push it with multiple tags:
Example - create an index and push to an OCI image layout folder 'layout-dir' and tag with 'v1':
oras manifest index create layout-dir:v1 linux-amd64 sha256:99e4703fbf30916f549cd6bfa9cdbab614b5392fbe64fdee971359a77073cdf9
Example - create an index and save it locally to index.json, auto push will be disabled:
oras manifest index create --output index.json localhost:5000/hello linux-amd64 linux-arm64
Example - create an index and output the index to stdout, auto push will be disabled:
oras manifest index create localhost:5000/hello linux-arm64 --output - --pretty
`,
Args: oerrors.CheckArgs(argument.AtLeast(1), "the destination index to create."),
PreRunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -84,6 +93,7 @@ Example - create an index and push to an OCI image layout folder 'layout-dir' an
return createIndex(cmd, opts)
},
}
cmd.Flags().StringVarP(&opts.outputPath, "output", "o", "", "file `path` to write the created index to, use - for stdout")
option.ApplyFlags(&opts, cmd.Flags())
return oerrors.Command(cmd, &opts.Target)
}
Expand All @@ -108,7 +118,18 @@ func createIndex(cmd *cobra.Command, opts createOptions) error {
indexBytes, _ := json.Marshal(index)
desc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageIndex, indexBytes)
opts.Println(status.IndexPromptPacked, descriptor.ShortDigest(desc), ocispec.MediaTypeImageIndex)
return pushIndex(ctx, target, desc, indexBytes, opts.Reference, opts.extraRefs, opts.AnnotatedReference(), opts.Printer)

switch opts.outputPath {
case "":
err = pushIndex(ctx, target, desc, indexBytes, opts.Reference, opts.extraRefs, opts.AnnotatedReference(), opts.Printer)
case "-":
opts.Println("Digest:", desc.Digest)
err = opts.Output(os.Stdout, indexBytes)
default:
opts.Println("Digest:", desc.Digest)
err = os.WriteFile(opts.outputPath, indexBytes, 0666)
}
return err
}

func fetchSourceManifests(ctx context.Context, target oras.ReadOnlyTarget, opts createOptions) ([]ocispec.Descriptor, error) {
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/internal/testdata/multi_arch/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,8 @@ var (
},
}
)

// exported index
var (
CreatedIndex = `{"schemaVersion":2,"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1","size":458,"platform":{"architecture":"amd64","os":"linux"}}]}`
)
31 changes: 31 additions & 0 deletions test/e2e/suite/command/manifest_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package command
import (
"encoding/json"
"fmt"
"path/filepath"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -130,6 +131,21 @@ var _ = Describe("1.1 registry users:", func() {
ValidateIndex(content, expectedManifests)
})

It("should output created index to file", func() {
testRepo := indexTestRepo("create", "output-to-file")
CopyZOTRepo(ImageRepo, testRepo)
filePath := filepath.Join(GinkgoT().TempDir(), "createdIndex")
ORAS("manifest", "index", "create", RegistryRef(ZOTHost, testRepo, ""), string(multi_arch.LinuxAMD64.Digest), "--output", filePath).Exec()
MatchFile(filePath, multi_arch.CreatedIndex, DefaultTimeout)
})

It("should output created index to stdout", func() {
testRepo := indexTestRepo("create", "output-to-stdout")
CopyZOTRepo(ImageRepo, testRepo)
ORAS("manifest", "index", "create", RegistryRef(ZOTHost, testRepo, ""), string(multi_arch.LinuxAMD64.Digest),
"--output", "-").MatchKeyWords(multi_arch.CreatedIndex).Exec()
})

It("should fail if given a reference that does not exist in the repo", func() {
testRepo := indexTestRepo("create", "nonexist-ref")
CopyZOTRepo(ImageRepo, testRepo)
Expand Down Expand Up @@ -211,6 +227,21 @@ var _ = Describe("OCI image layout users:", func() {
ValidateIndex(content, expectedManifests)
})

It("should output created index to file", func() {
root := PrepareTempOCI(ImageRepo)
indexRef := LayoutRef(root, "output-to-file")
filePath := filepath.Join(GinkgoT().TempDir(), "createdIndex")
ORAS("manifest", "index", "create", Flags.Layout, indexRef, string(multi_arch.LinuxAMD64.Digest), "--output", filePath).Exec()
MatchFile(filePath, multi_arch.CreatedIndex, DefaultTimeout)
})

It("should output created index to stdout", func() {
root := PrepareTempOCI(ImageRepo)
indexRef := LayoutRef(root, "output-to-stdout")
ORAS("manifest", "index", "create", Flags.Layout, indexRef, string(multi_arch.LinuxAMD64.Digest),
"--output", "-").MatchKeyWords(multi_arch.CreatedIndex).Exec()
})

It("should fail if given a reference that does not exist in the repo", func() {
root := PrepareTempOCI(ImageRepo)
indexRef := LayoutRef(root, "latest")
Expand Down

0 comments on commit a3b0601

Please sign in to comment.