@@ -8,48 +8,101 @@ import (
88 "github.com/containers/storage"
99)
1010
11+
12+ func splitNameTag (ref string ) (string , string ) {
13+ lastColon := strings .LastIndex (ref , ":" )
14+ lastSlash := strings .LastIndex (ref , "/" )
15+
16+ // Only pick tag as last content after ":" and non empty
17+ if lastColon > lastSlash && lastColon != - 1 {
18+ return ref [:lastColon ], ref [lastColon + 1 :]
19+ }
20+
21+ // we did not find a tag
22+ return ref , "latest"
23+ }
24+
25+
26+ func hasRegistry (name string ) bool {
27+ first := name
28+
29+ // find first slash and keep what is before it
30+ i := strings .IndexRune (name , '/' )
31+ if i != - 1 {
32+ first = name [:i ]
33+ }
34+
35+ isLocalhost := (first == "localhost" )
36+ hasDomain := strings .Contains (first , "." )
37+ hasPort := strings .Contains (first , ":" )
38+
39+ return isLocalhost || hasDomain || hasPort
40+ }
41+
42+
43+
1144// We get fully qualified name with more robust Resolve()
1245func CanonicalImageName (ref string ) (string , error ) {
13- parts := strings .Split (ref , ":" )
14- name := parts [0 ]
46+ name , tag := splitNameTag (ref )
1547
16- // default to "latest"
17- tag := "latest"
18- if len (parts ) == 2 && parts [1 ] != "" {
19- tag = parts [1 ]
48+ if hasRegistry (name ) {
49+ return fmt .Sprintf ("%s:%s" , name , tag ), nil
2050 }
2151
2252 if shortnames .IsShortName (ref ) {
2353 resolved , err := shortnames .Resolve (nil , ref )
2454 if err != nil {
2555 return "" , fmt .Errorf ("failed to resolve short name %q: %w" , ref , err )
2656 }
57+
2758 if len (resolved .PullCandidates ) == 0 {
2859 return "" , fmt .Errorf ("no resolution candidates found for short name %q" , ref )
2960 }
30- candidate := resolved .PullCandidates [0 ] // take first candidate
31- return candidate .Value .String (), nil // Already includes tag
61+
62+ // take first candidate
63+ candidate := resolved .PullCandidates [0 ]
64+ // Candidate already includes tag
65+ return candidate .Value .String (), nil
3266 }
3367
3468 return fmt .Sprintf ("%s:%s" , name , tag ), nil
3569}
3670
37- func FindImage (store storage.Store , name string ) (storage.Image , error ){
38- canonical , err := CanonicalImageName (name )
39- if err != nil {
40- return storage.Image {}, fmt .Errorf ("Resolving canonical name %q: %w" , name , err )
41- }
42- imgs , err := store .Images ()
43- if err != nil {
44- return storage.Image {}, fmt .Errorf ("Liust iamges: %w" , err )
45- }
46- for _ , img := range imgs {
47- for _ , tag := range img .Names {
48- if tag == name || tag == canonical {
49- return img , nil
50- }
51- }
52- }
53- return storage.Image {}, fmt .Errorf ("Image not found: %q" , name )
71+ func FindImage (store storage.Store , name string ) (storage.Image , error ) {
72+ imgs , err := store .Images ()
73+ if err != nil {
74+ return storage.Image {}, fmt .Errorf ("List images: %w" , err )
75+ }
76+
77+ base , tag := splitNameTag (name )
78+
79+ // Build candidate name options
80+ normalized := fmt .Sprintf ("%s:%s" , base , tag )
81+
82+ localhostName := ""
83+ if ! hasRegistry (base ) {
84+ localhostName = fmt .Sprintf ("localhost/%s:%s" , base , tag )
85+ }
86+
87+ canonical := ""
88+ if fq , err := CanonicalImageName (name ); err == nil {
89+ canonical = fq
90+ }
91+
92+ // loop over all images and its name for a match
93+ for _ , img := range imgs {
94+ for _ , n := range img .Names {
95+ isExactName := (n == name )
96+ isNormalized := (n == normalized )
97+ isLocalhost := (n == localhostName )
98+ isCanonical := (n == canonical )
99+
100+ if isExactName || isNormalized || isLocalhost || isCanonical {
101+ return img , nil
102+ }
103+ }
104+ }
105+
106+ return storage.Image {}, fmt .Errorf ("Image not found: %q" , name )
54107}
55108
0 commit comments