44// Grammar
55//
66// reference := name [ ":" tag ] [ "@" digest ]
7- // name := [hostname '/'] component ['/' component]*
8- // hostname := hostcomponent ['.' hostcomponent ]* [':' port-number]
9- // hostcomponent := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
7+ // name := [domain '/'] path- component ['/' path- component]*
8+ // domain := domain-component ['.' domain-component ]* [':' port-number]
9+ // domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
1010// port-number := /[0-9]+/
11- // component := alpha-numeric [separator alpha-numeric]*
11+ // path- component := alpha-numeric [separator alpha-numeric]*
1212// alpha-numeric := /[a-z0-9]+/
1313// separator := /[_.]|__|[-]*/
1414//
@@ -126,23 +126,56 @@ type Digested interface {
126126}
127127
128128// Canonical reference is an object with a fully unique
129- // name including a name with hostname and digest
129+ // name including a name with domain and digest
130130type Canonical interface {
131131 Named
132132 Digest () digest.Digest
133133}
134134
135+ // NamedRepository is a reference to a repository with a name.
136+ // A NamedRepository has both domain and path components.
137+ type NamedRepository interface {
138+ Named
139+ Domain () string
140+ Path () string
141+ }
142+
143+ // Domain returns the domain part of the Named reference
144+ func Domain (named Named ) string {
145+ if r , ok := named .(NamedRepository ); ok {
146+ return r .Domain ()
147+ }
148+ domain , _ := splitDomain (named .Name ())
149+ return domain
150+ }
151+
152+ // Path returns the name without the domain part of the Named reference
153+ func Path (named Named ) (name string ) {
154+ if r , ok := named .(NamedRepository ); ok {
155+ return r .Path ()
156+ }
157+ _ , path := splitDomain (named .Name ())
158+ return path
159+ }
160+
161+ func splitDomain (name string ) (string , string ) {
162+ match := anchoredNameRegexp .FindStringSubmatch (name )
163+ if len (match ) != 3 {
164+ return "" , name
165+ }
166+ return match [1 ], match [2 ]
167+ }
168+
135169// SplitHostname splits a named reference into a
136170// hostname and name string. If no valid hostname is
137171// found, the hostname is empty and the full value
138172// is returned as name
173+ // DEPRECATED: Use Domain or Path
139174func SplitHostname (named Named ) (string , string ) {
140- name := named .Name ()
141- match := anchoredNameRegexp .FindStringSubmatch (name )
142- if len (match ) != 3 {
143- return "" , name
175+ if r , ok := named .(NamedRepository ); ok {
176+ return r .Domain (), r .Path ()
144177 }
145- return match [ 1 ], match [ 2 ]
178+ return splitDomain ( named . Name ())
146179}
147180
148181// Parse parses s and returns a syntactically valid Reference.
@@ -164,9 +197,20 @@ func Parse(s string) (Reference, error) {
164197 return nil , ErrNameTooLong
165198 }
166199
200+ var repo repository
201+
202+ nameMatch := anchoredNameRegexp .FindStringSubmatch (matches [1 ])
203+ if nameMatch != nil && len (nameMatch ) == 3 {
204+ repo .domain = nameMatch [1 ]
205+ repo .path = nameMatch [2 ]
206+ } else {
207+ repo .domain = ""
208+ repo .path = matches [1 ]
209+ }
210+
167211 ref := reference {
168- name : matches [ 1 ] ,
169- tag : matches [2 ],
212+ repository : repo ,
213+ tag : matches [2 ],
170214 }
171215 if matches [3 ] != "" {
172216 var err error
@@ -207,10 +251,15 @@ func WithName(name string) (Named, error) {
207251 if len (name ) > NameTotalLengthMax {
208252 return nil , ErrNameTooLong
209253 }
210- if ! anchoredNameRegexp .MatchString (name ) {
254+
255+ match := anchoredNameRegexp .FindStringSubmatch (name )
256+ if match == nil || len (match ) != 3 {
211257 return nil , ErrReferenceInvalidFormat
212258 }
213- return repository (name ), nil
259+ return repository {
260+ domain : match [1 ],
261+ path : match [2 ],
262+ }, nil
214263}
215264
216265// WithTag combines the name from "name" and the tag from "tag" to form a
@@ -219,16 +268,23 @@ func WithTag(name Named, tag string) (NamedTagged, error) {
219268 if ! anchoredTagRegexp .MatchString (tag ) {
220269 return nil , ErrTagInvalidFormat
221270 }
271+ var repo repository
272+ if r , ok := name .(NamedRepository ); ok {
273+ repo .domain = r .Domain ()
274+ repo .path = r .Path ()
275+ } else {
276+ repo .path = name .Name ()
277+ }
222278 if canonical , ok := name .(Canonical ); ok {
223279 return reference {
224- name : name . Name () ,
280+ repository : repo ,
225281 tag : tag ,
226282 digest : canonical .Digest (),
227283 }, nil
228284 }
229285 return taggedReference {
230- name : name . Name () ,
231- tag : tag ,
286+ repository : repo ,
287+ tag : tag ,
232288 }, nil
233289}
234290
@@ -238,16 +294,23 @@ func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
238294 if ! anchoredDigestRegexp .MatchString (digest .String ()) {
239295 return nil , ErrDigestInvalidFormat
240296 }
297+ var repo repository
298+ if r , ok := name .(NamedRepository ); ok {
299+ repo .domain = r .Domain ()
300+ repo .path = r .Path ()
301+ } else {
302+ repo .path = name .Name ()
303+ }
241304 if tagged , ok := name .(Tagged ); ok {
242305 return reference {
243- name : name . Name () ,
306+ repository : repo ,
244307 tag : tagged .Tag (),
245308 digest : digest ,
246309 }, nil
247310 }
248311 return canonicalReference {
249- name : name . Name () ,
250- digest : digest ,
312+ repository : repo ,
313+ digest : digest ,
251314 }, nil
252315}
253316
@@ -267,7 +330,7 @@ func TrimNamed(ref Named) Named {
267330}
268331
269332func getBestReferenceType (ref reference ) Reference {
270- if ref .name == "" {
333+ if ref .repository . path == "" {
271334 // Allow digest only references
272335 if ref .digest != "" {
273336 return digestReference (ref .digest )
@@ -277,34 +340,30 @@ func getBestReferenceType(ref reference) Reference {
277340 if ref .tag == "" {
278341 if ref .digest != "" {
279342 return canonicalReference {
280- name : ref .name ,
281- digest : ref .digest ,
343+ repository : ref .repository ,
344+ digest : ref .digest ,
282345 }
283346 }
284- return repository ( ref .name )
347+ return ref .repository
285348 }
286349 if ref .digest == "" {
287350 return taggedReference {
288- name : ref .name ,
289- tag : ref .tag ,
351+ repository : ref .repository ,
352+ tag : ref .tag ,
290353 }
291354 }
292355
293356 return ref
294357}
295358
296359type reference struct {
297- name string
360+ repository
298361 tag string
299362 digest digest.Digest
300363}
301364
302365func (r reference ) String () string {
303- return r .name + ":" + r .tag + "@" + r .digest .String ()
304- }
305-
306- func (r reference ) Name () string {
307- return r .name
366+ return r .Name () + ":" + r .tag + "@" + r .digest .String ()
308367}
309368
310369func (r reference ) Tag () string {
@@ -315,14 +374,28 @@ func (r reference) Digest() digest.Digest {
315374 return r .digest
316375}
317376
318- type repository string
377+ type repository struct {
378+ domain string
379+ path string
380+ }
319381
320382func (r repository ) String () string {
321- return string ( r )
383+ return r . Name ( )
322384}
323385
324386func (r repository ) Name () string {
325- return string (r )
387+ if r .domain == "" {
388+ return r .path
389+ }
390+ return r .domain + "/" + r .path
391+ }
392+
393+ func (r repository ) Domain () string {
394+ return r .domain
395+ }
396+
397+ func (r repository ) Path () string {
398+ return r .path
326399}
327400
328401type digestReference digest.Digest
@@ -336,33 +409,25 @@ func (d digestReference) Digest() digest.Digest {
336409}
337410
338411type taggedReference struct {
339- name string
340- tag string
412+ repository
413+ tag string
341414}
342415
343416func (t taggedReference ) String () string {
344- return t .name + ":" + t .tag
345- }
346-
347- func (t taggedReference ) Name () string {
348- return t .name
417+ return t .Name () + ":" + t .tag
349418}
350419
351420func (t taggedReference ) Tag () string {
352421 return t .tag
353422}
354423
355424type canonicalReference struct {
356- name string
425+ repository
357426 digest digest.Digest
358427}
359428
360429func (c canonicalReference ) String () string {
361- return c .name + "@" + c .digest .String ()
362- }
363-
364- func (c canonicalReference ) Name () string {
365- return c .name
430+ return c .Name () + "@" + c .digest .String ()
366431}
367432
368433func (c canonicalReference ) Digest () digest.Digest {
0 commit comments