1414
1515import RegexBuilder
1616
17- enum ReferenceError : Error { case unexpected( String ) }
18-
1917// https://github.com/distribution/distribution/blob/v2.7.1/reference/reference.go
2018// Split the image reference into a registry and a name part.
2119func splitReference( _ reference: String ) throws -> ( String ? , String ) {
2220 let splits = reference. split ( separator: " / " , maxSplits: 1 , omittingEmptySubsequences: false )
23- if splits. count == 0 { throw ReferenceError . unexpected ( " unexpected error " ) }
21+ if splits. count == 0 { throw ImageReference . ValidationError . unexpected ( " unexpected error " ) }
2422
2523 if splits. count == 1 { return ( nil , reference) }
2624
@@ -39,23 +37,29 @@ func splitName(_ name: String) throws -> (String, String) {
3937 if digestSplit. count == 2 { return ( String ( digestSplit [ 0 ] ) , String ( digestSplit [ 1 ] ) ) }
4038
4139 let tagSplit = name. split ( separator: " : " , maxSplits: 1 , omittingEmptySubsequences: false )
42- if tagSplit. count == 0 { throw ReferenceError . unexpected ( " unexpected error " ) }
40+ if tagSplit. count == 0 { throw ImageReference . ValidationError . unexpected ( " unexpected error " ) }
4341
4442 if tagSplit. count == 1 { return ( name, " latest " ) }
4543
4644 // assert splits == 2
4745 return ( String ( tagSplit [ 0 ] ) , String ( tagSplit [ 1 ] ) )
4846}
4947
48+ /// Repository refers a repository (image namespace) on a container registry
49+
5050/// ImageReference points to an image stored on a container registry
5151public struct ImageReference : Sendable , Equatable , CustomStringConvertible , CustomDebugStringConvertible {
5252 /// The registry which contains this image
5353 public var registry : String
5454 /// The repository which contains this image
55- public var repository : String
55+ public var repository : Repository
5656 /// The tag identifying the image.
5757 public var reference : String
5858
59+ public enum ValidationError : Error {
60+ case unexpected( String )
61+ }
62+
5963 /// Creates an ImageReference from an image reference string.
6064 /// - Parameters:
6165 /// - reference: The reference to parse.
@@ -72,19 +76,20 @@ public struct ImageReference: Sendable, Equatable, CustomStringConvertible, Cust
7276 // moby/moby assumes that these names refer to images in `library`: `library/swift` or `library/swift:slim`.
7377 // This special case only applies when using Docker Hub, so `example.com/swift` is not expanded `example.com/library/swift`
7478 if self . registry == " index.docker.io " && !repository. contains ( " / " ) {
75- self . repository = " library/ \( repository) "
79+ self . repository = try Repository ( " library/ \( repository) " )
7680 } else {
77- self . repository = repository
81+ self . repository = try Repository ( repository)
7882 }
7983 self . reference = reference
8084 }
8185
8286 /// Creates an ImageReference from separate registry, repository and reference strings.
87+ /// Used only in tests.
8388 /// - Parameters:
8489 /// - registry: The registry which stores the image data.
8590 /// - repository: The repository within the registry which holds the image.
8691 /// - reference: The tag identifying the image.
87- public init ( registry: String , repository: String , reference: String ) {
92+ init ( registry: String , repository: Repository , reference: String ) {
8893 self . registry = registry
8994 self . repository = repository
9095 self . reference = reference
@@ -104,3 +109,32 @@ public struct ImageReference: Sendable, Equatable, CustomStringConvertible, Cust
104109 " ImageReference(registry: \( registry) , repository: \( repository) , reference: \( reference) ) "
105110 }
106111}
112+
113+ extension ImageReference {
114+ public struct Repository : Sendable , Equatable , CustomStringConvertible , CustomDebugStringConvertible {
115+ var value : String
116+
117+ public enum ValidationError : Error {
118+ case emptyString
119+ }
120+
121+ public init ( _ rawValue: String ) throws {
122+ // Reference handling in github.com/distribution reports empty and uppercase as specific errors.
123+ // All other errors caused are reported as generic format errors.
124+ guard rawValue. count > 0 else {
125+ throw ValidationError . emptyString
126+ }
127+
128+ value = rawValue
129+ }
130+
131+ public var description : String {
132+ value
133+ }
134+
135+ /// Printable description of an ImageReference in a form suitable for debugging.
136+ public var debugDescription : String {
137+ " Repository( \( value) ) "
138+ }
139+ }
140+ }
0 commit comments