Skip to content
This repository was archived by the owner on Jan 15, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions cmd/oci-image-tool/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var bundleTypes = []string{

type bundleCmd struct {
typ string // the type to bundle, can be empty string
ref string
refs []string
root string
platform string
}
Expand All @@ -43,11 +43,15 @@ func createHandle(context *cli.Context) error {

v := bundleCmd{
typ: context.String("type"),
ref: context.String("ref"),
refs: context.StringSlice("ref"),
root: context.String("rootfs"),
platform: context.String("platform"),
}

if len(v.refs) == 0 {
return fmt.Errorf("ref must be provided")
}

if v.typ == "" {
typ, err := image.Autodetect(context.Args()[0])
if err != nil {
Expand All @@ -59,13 +63,13 @@ func createHandle(context *cli.Context) error {
var err error
switch v.typ {
case image.TypeImageLayout:
err = image.CreateRuntimeBundleLayout(context.Args()[0], context.Args()[1], v.ref, v.root, v.platform)
err = image.CreateRuntimeBundleLayout(context.Args()[0], context.Args()[1], v.root, v.platform, v.refs)

case image.TypeImageZip:
err = image.CreateRuntimeBundleZip(context.Args()[0], context.Args()[1], v.ref, v.root, v.platform)
err = image.CreateRuntimeBundleZip(context.Args()[0], context.Args()[1], v.root, v.platform, v.refs)

case image.TypeImage:
err = image.CreateRuntimeBundleFile(context.Args()[0], context.Args()[1], v.ref, v.root, v.platform)
err = image.CreateRuntimeBundleFile(context.Args()[0], context.Args()[1], v.root, v.platform, v.refs)

default:
err = fmt.Errorf("cannot create %q", v.typ)
Expand All @@ -87,10 +91,9 @@ var createCommand = cli.Command{
strings.Join(bundleTypes, ","),
),
},
cli.StringFlag{
cli.StringSliceFlag{
Name: "ref",
Value: "v1.0",
Usage: "The ref pointing to the manifest of the OCI image. This must be present in the 'refs' subdirectory of the image.",
Usage: "A set of ref specify the search criteria for the validated reference, format is A=B. Only support 'name', 'platform.os' and 'digest' three cases.",
},
cli.StringFlag{
Name: "rootfs",
Expand Down
19 changes: 11 additions & 8 deletions cmd/oci-image-tool/unpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var unpackTypes = []string{

type unpackCmd struct {
typ string // the type to unpack, can be empty string
ref string
refs []string
platform string
}

Expand All @@ -42,10 +42,14 @@ func unpackHandle(context *cli.Context) error {

v := unpackCmd{
typ: context.String("type"),
ref: context.String("ref"),
refs: context.StringSlice("ref"),
platform: context.String("platform"),
}

if len(v.refs) == 0 {
return fmt.Errorf("ref must be provided")
}

if v.typ == "" {
typ, err := image.Autodetect(context.Args()[0])
if err != nil {
Expand All @@ -57,13 +61,13 @@ func unpackHandle(context *cli.Context) error {
var err error
switch v.typ {
case image.TypeImageLayout:
err = image.UnpackLayout(context.Args()[0], context.Args()[1], v.ref, v.platform)
err = image.UnpackLayout(context.Args()[0], context.Args()[1], v.platform, v.refs)

case image.TypeImageZip:
err = image.UnpackZip(context.Args()[0], context.Args()[1], v.ref, v.platform)
err = image.UnpackZip(context.Args()[0], context.Args()[1], v.platform, v.refs)

case image.TypeImage:
err = image.UnpackFile(context.Args()[0], context.Args()[1], v.ref, v.platform)
err = image.UnpackFile(context.Args()[0], context.Args()[1], v.platform, v.refs)

default:
err = fmt.Errorf("cannot unpack %q", v.typ)
Expand All @@ -84,10 +88,9 @@ var unpackCommand = cli.Command{
strings.Join(unpackTypes, ","),
),
},
cli.StringFlag{
cli.StringSliceFlag{
Name: "ref",
Value: "v1.0",
Usage: "The ref pointing to the manifest of the OCI image. This must be present in the 'refs' subdirectory of the image.",
Usage: "A set of ref specify the search criteria for the validated reference, format is A=B. Only support 'name', 'platform.os' and 'digest' three cases.",
},
cli.StringFlag{
Name: "platform",
Expand Down
4 changes: 2 additions & 2 deletions cmd/oci-image-tool/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func validatePath(name string) error {
}

if len(v.refs) != 0 {
fmt.Printf("WARNING: type %q does not support refs, which are only appropriate if type is image or imageLayout.\n", typ)
fmt.Printf("WARNING: type %q does not support ref, which are only appropriate if type is image or imageLayout.\n", typ)
}

f, err := os.Open(name)
Expand Down Expand Up @@ -143,7 +143,7 @@ var validateCommand = cli.Command{
},
cli.StringSliceFlag{
Name: "ref",
Usage: "A set of refs pointing to the manifests to be validated. Each reference must be present in the refs subdirectory of the image. Only applicable if type is image or imageLayout.",
Usage: "A set of ref specify the search criteria for the validated reference. Format is A=B. Only support 'name', 'platform.os' and 'digest' three cases. Only applicable if type is image or imageLayout.",
},
},
}
68 changes: 46 additions & 22 deletions image/descriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ import (
"io"
"os"
"path/filepath"
"strings"

"github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)

const indexPath = "index.json"

func listReferences(w walker) (map[string]*v1.Descriptor, error) {
refs := make(map[string]*v1.Descriptor)
func listReferences(w walker) ([]v1.Descriptor, error) {
var descs []v1.Descriptor
var index v1.Index

if err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
Expand All @@ -39,25 +40,21 @@ func listReferences(w walker) (map[string]*v1.Descriptor, error) {
if err := json.NewDecoder(r).Decode(&index); err != nil {
return err
}

for i := 0; i < len(index.Manifests); i++ {
if index.Manifests[i].Annotations[v1.AnnotationRefName] != "" {
refs[index.Manifests[i].Annotations[v1.AnnotationRefName]] = &index.Manifests[i]
}
}
descs = index.Manifests

return nil
}); err != nil {
return nil, err
}
return refs, nil

return descs, nil
}

func findDescriptor(w walker, name string) (*v1.Descriptor, error) {
var d v1.Descriptor
func findDescriptor(w walker, names []string) ([]v1.Descriptor, error) {
var descs []v1.Descriptor
var index v1.Index

switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
if err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
if info.IsDir() || filepath.Clean(path) != indexPath {
return nil
}
Expand All @@ -66,22 +63,49 @@ func findDescriptor(w walker, name string) (*v1.Descriptor, error) {
return err
}

for i := 0; i < len(index.Manifests); i++ {
if index.Manifests[i].Annotations[v1.AnnotationRefName] == name {
d = index.Manifests[i]
return errEOW
descs = index.Manifests
for _, name := range names {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following code is totally duplicate with part code of validate() in image/image.go
Maybe we can create a common or utility function by taking advantage of it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, PTAL.

argsParts := strings.Split(name, "=")
if len(argsParts) != 2 {
return fmt.Errorf("each ref must contain two parts")
}

switch argsParts[0] {
case "name":
for i := 0; i < len(descs); i++ {
if descs[i].Annotations[v1.AnnotationRefName] != argsParts[1] {
descs = append(descs[:i], descs[i+1:]...)
}
}
case "platform.os":
for i := 0; i < len(descs); i++ {
if descs[i].Platform != nil && index.Manifests[i].Platform.OS != argsParts[1] {
descs = append(descs[:i], descs[i+1:]...)
}
}
case "digest":
for i := 0; i < len(descs); i++ {
if string(descs[i].Digest) != argsParts[1] {
descs = append(descs[:i], descs[i+1:]...)
}
}
default:
return fmt.Errorf("criteria %q unimplemented", argsParts[0])
}
}

return nil
}); err {
case nil:
return nil, fmt.Errorf("index.json: descriptor %q not found", name)
case errEOW:
return &d, nil
default:
}); err != nil {
return nil, err
}

if len(descs) == 0 {
return nil, fmt.Errorf("index.json: descriptor retrieved by refs %v is not match", names)
} else if len(descs) > 1 {
return nil, fmt.Errorf("index.json: descriptor retrieved by refs %v is not unique", names)
}

return descs, nil
}

func validateDescriptor(d *v1.Descriptor, w walker, mts []string) error {
Expand Down
Loading