@@ -4,21 +4,117 @@ import (
44"bytes"
55"context"
66"encoding/json"
7+ "fmt"
78"io"
9+ "os"
10+ "path/filepath"
811"strings"
912
1013oci "github.com/opencontainers/image-spec/specs-go/v1"
1114"github.com/supercontainers/compspec-go/pkg/types"
15+ "github.com/supercontainers/compspec-go/pkg/utils"
1216"oras.land/oras-go/v2/content"
1317"oras.land/oras-go/v2/registry/remote"
1418"sigs.k8s.io/yaml"
1519)
1620
21+ // toFilename converts the uri of an image to a filename
22+ func toFilename (uri string ) string {
23+ for _ , repl := range []string {"/" , ":" } {
24+ uri = strings .ReplaceAll (uri , repl , "-" )
25+ }
26+ return fmt .Sprintf ("%s.json" , uri )
27+ }
28+
29+ // LoadFromCache loads the compatibility request from cache
30+ func LoadFromCache (uri , cache string ) (types.CompatibilityRequest , error ) {
31+ var request types.CompatibilityRequest
32+ var err error
33+ cachePath := filepath .Join (cache , toFilename (uri ))
34+ exists , err := utils .PathExists (cachePath )
35+ if err != nil {
36+ return request , err
37+ }
38+ if exists {
39+ fd , err := os .Open (cachePath )
40+ b , err := io .ReadAll (fd )
41+ if err != nil {
42+ return request , err
43+ }
44+ defer fd .Close ()
45+
46+ err = json .Unmarshal (b , & request )
47+ }
48+ return request , err
49+ }
50+
1751// Oras will provide an interface to retrieve an artifact, specifically
1852// a compatibillity spec artifact media type
1953// LoadArtifact retrieves the artifact from the url string
2054// and returns based on the media type
21- func LoadArtifact (uri string , mediaType string ) (types.CompatibilityRequest , error ) {
55+ func LoadArtifact (
56+ uri string ,
57+ mediaType string ,
58+ cache string ,
59+ ) (types.CompatibilityRequest , error ) {
60+
61+ request := types.CompatibilityRequest {}
62+ var err error
63+
64+ // If cache is desired and we have the artifact
65+ if cache != "" {
66+
67+ // Must exist
68+ exists , err := utils .PathExists (cache )
69+ if err != nil {
70+ return request , err
71+ }
72+ if ! exists {
73+ return request , fmt .Errorf ("Cache path %s does not exist" , cache )
74+ }
75+ request , err := LoadFromCache (uri , cache )
76+ if err != nil {
77+ return request , err
78+ }
79+ }
80+
81+ // If we didn't get matches, load from registry
82+ if request .Kind == "" {
83+ request , err = LoadFromRegistry (uri , mediaType )
84+
85+ // If we loaded it and have a cache, save to cache
86+ if cache != "" {
87+ err = SaveToCache (request , uri , cache )
88+ }
89+ }
90+ return request , err
91+ }
92+
93+ // Save to cache
94+ func SaveToCache (request types.CompatibilityRequest , uri , cache string ) error {
95+ cachePath := filepath .Join (cache , toFilename (uri ))
96+ exists , err := utils .PathExists (cachePath )
97+ if err != nil {
98+ return err
99+ }
100+
101+ // Don't overwrite
102+ if exists {
103+ return nil
104+ }
105+ content , err := json .Marshal (request )
106+ if err != nil {
107+ return err
108+ }
109+ err = os .WriteFile (cachePath , content , 0644 )
110+ if err != nil {
111+ return err
112+ }
113+ return nil
114+ }
115+
116+ // Load the artifact from a registry
117+ func LoadFromRegistry (uri , mediaType string ) (types.CompatibilityRequest , error ) {
22118request := types.CompatibilityRequest {}
23119ctx := context .Background ()
24120repo , err := remote .NewRepository (uri )
0 commit comments