github.com/opcr-io/oras-go/v2@v2.0.0-20231122155130-eb4260d8a0ae/content/graph.go (about) 1 /* 2 Copyright The ORAS Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package content 17 18 import ( 19 "context" 20 "encoding/json" 21 22 "github.com/opcr-io/oras-go/v2/internal/docker" 23 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 24 ) 25 26 // PredecessorFinder finds out the nodes directly pointing to a given node of a 27 // directed acyclic graph. 28 // In other words, returns the "parents" of the current descriptor. 29 // PredecessorFinder is an extension of Storage. 30 type PredecessorFinder interface { 31 // Predecessors returns the nodes directly pointing to the current node. 32 Predecessors(ctx context.Context, node ocispec.Descriptor) ([]ocispec.Descriptor, error) 33 } 34 35 // GraphStorage represents a CAS that supports direct predecessor node finding. 36 type GraphStorage interface { 37 Storage 38 PredecessorFinder 39 } 40 41 // ReadOnlyGraphStorage represents a read-only GraphStorage. 42 type ReadOnlyGraphStorage interface { 43 ReadOnlyStorage 44 PredecessorFinder 45 } 46 47 // Successors returns the nodes directly pointed by the current node. 48 // In other words, returns the "children" of the current descriptor. 49 func Successors(ctx context.Context, fetcher Fetcher, node ocispec.Descriptor) ([]ocispec.Descriptor, error) { 50 switch node.MediaType { 51 case docker.MediaTypeManifest: 52 content, err := FetchAll(ctx, fetcher, node) 53 if err != nil { 54 return nil, err 55 } 56 // OCI manifest schema can be used to marshal docker manifest 57 var manifest ocispec.Manifest 58 if err := json.Unmarshal(content, &manifest); err != nil { 59 return nil, err 60 } 61 return append([]ocispec.Descriptor{manifest.Config}, manifest.Layers...), nil 62 case ocispec.MediaTypeImageManifest: 63 content, err := FetchAll(ctx, fetcher, node) 64 if err != nil { 65 return nil, err 66 } 67 var manifest ocispec.Manifest 68 if err := json.Unmarshal(content, &manifest); err != nil { 69 return nil, err 70 } 71 var nodes []ocispec.Descriptor 72 if manifest.Subject != nil { 73 nodes = append(nodes, *manifest.Subject) 74 } 75 nodes = append(nodes, manifest.Config) 76 return append(nodes, manifest.Layers...), nil 77 case docker.MediaTypeManifestList, ocispec.MediaTypeImageIndex: 78 content, err := FetchAll(ctx, fetcher, node) 79 if err != nil { 80 return nil, err 81 } 82 83 // docker manifest list and oci index are equivalent for successors. 84 var index ocispec.Index 85 if err := json.Unmarshal(content, &index); err != nil { 86 return nil, err 87 } 88 return index.Manifests, nil 89 } 90 return nil, nil 91 }