@@ -9,7 +9,7 @@ use nom::{
99 bytes:: tag,
1010 character:: complete:: { alphanumeric1, digit1} ,
1111 combinator:: { complete, opt, recognize} ,
12- multi:: separated_list1,
12+ multi:: { many_m_n , many1 , separated_list0 , separated_list1} ,
1313 sequence:: { preceded, terminated} ,
1414} ;
1515use oci_distribution:: {
@@ -127,18 +127,31 @@ impl FromStr for DockerImageUrl {
127127 type Err = Report ;
128128
129129 fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
130- let mut parser = complete ( (
131- opt ( terminated (
130+ // see https://ktomk.github.io/pipelines/doc/DOCKER-NAME-TAG.html#syntax
131+ let host = opt ( terminated (
132+ alt ( (
133+ recognize ( ( separated_list1 ( tag ( "." ) , alphanumeric1) , tag ( ":" ) , digit1) ) ,
134+ recognize ( separated_list1 ( tag ( "." ) , alphanumeric1) ) ,
135+ ) ) ,
136+ tag ( "/" ) ,
137+ ) ) ;
138+ let image = recognize ( separated_list0 (
139+ tag ( "/" ) ,
140+ separated_list0 (
132141 alt ( (
133- recognize ( ( separated_list1 ( tag ( "." ) , alphanumeric1) , tag ( ":" ) , digit1) ) ,
134- recognize ( separated_list1 ( tag ( "." ) , alphanumeric1) ) ,
142+ tag ( "." ) ,
143+ recognize ( many_m_n ( 1 , 2 , tag ( "_" ) ) ) ,
144+ recognize ( many1 ( tag ( "-" ) ) ) ,
135145 ) ) ,
136- tag ( "/" ) ,
137- ) ) ,
138- alt ( ( recognize ( ( alphanumeric1, tag ( "/" ) , alphanumeric1) ) , alphanumeric1) ) ,
139- opt ( preceded ( tag ( ":" ) , alphanumeric1) ) ,
140- opt ( preceded ( tag ( "@sha256:" ) , alphanumeric1) ) ,
146+ alphanumeric1,
147+ ) ,
148+ ) ) ;
149+ let docker_tag = opt ( preceded (
150+ tag ( ":" ) ,
151+ recognize ( separated_list0 ( alt ( ( tag ( "." ) , tag ( "-" ) ) ) , alphanumeric1) ) ,
141152 ) ) ;
153+ let digest = opt ( preceded ( tag ( "@sha256:" ) , alphanumeric1) ) ;
154+ let mut parser = complete ( ( host, image, docker_tag, digest) ) ;
142155 let parsed: DockerParseType = parser. parse ( s) ;
143156 match parsed {
144157 Ok ( result) => Ok ( DockerImageUrl {
@@ -178,3 +191,26 @@ impl Display for DockerImageUrl {
178191 Ok ( ( ) )
179192 }
180193}
194+
195+ #[ cfg( test) ]
196+ mod tests {
197+ use rstest:: rstest;
198+
199+ use super :: * ;
200+
201+ #[ rstest]
202+ #[ case( "ubuntu" , ( None , "ubuntu" , None , None ) ) ]
203+ #[ case( "docker.io/library/hello-world:latest@sha256:deadbeef" , ( Some ( "docker.io" ) , "library/hello-world" , Some ( "latest" ) , Some ( "deadbeef" ) ) ) ]
204+ #[ case( "ghcr.io/swissdatasciencecenter/renku-frontend-buildpacks/run-image:0.2.1" , ( Some ( "ghcr.io" ) , "swissdatasciencecenter/renku-frontend-buildpacks/run-image" , Some ( "0.2.1" ) , None ) ) ]
205+ #[ case( "test.ghcr.io/a/b/c/d/e:a-1.f-2" , ( Some ( "test.ghcr.io" ) , "a/b/c/d/e" , Some ( "a-1.f-2" ) , None ) ) ]
206+ fn test_docker_parsing (
207+ #[ case] docker_url : & str ,
208+ #[ case] expected : ( Option < & str > , & str , Option < & str > , Option < & str > ) ,
209+ ) {
210+ let image = DockerImageUrl :: from_str ( docker_url) . expect ( "couldn't parse image" ) ;
211+ assert_eq ! ( image. registry, expected. 0 . map( |s| s. to_owned( ) ) ) ;
212+ assert_eq ! ( image. image. as_str( ) , expected. 1 ) ;
213+ assert_eq ! ( image. tag, expected. 2 . map( |s| s. to_owned( ) ) ) ;
214+ assert_eq ! ( image. digest, expected. 3 . map( |s| s. to_owned( ) ) ) ;
215+ }
216+ }
0 commit comments