@@ -139,29 +139,37 @@ struct BoundImage {
139
139
140
140
impl BoundImage {
141
141
fn new ( image : String , auth_file : Option < String > ) -> Result < BoundImage > {
142
- validate_spec_value ( & image) . context ( "Invalid image value" ) ?;
142
+ let image = parse_spec_value ( & image) . context ( "Invalid image value" ) ?;
143
143
144
- if let Some ( auth_file) = & auth_file {
145
- validate_spec_value ( auth_file) . context ( "Invalid auth_file value" ) ?;
146
- }
144
+ let auth_file = if let Some ( auth_file) = & auth_file {
145
+ Some ( parse_spec_value ( auth_file) . context ( "Invalid auth_file value" ) ?)
146
+ } else {
147
+ None
148
+ } ;
147
149
148
150
Ok ( BoundImage { image, auth_file } )
149
151
}
150
152
}
151
153
152
- fn validate_spec_value ( value : & String ) -> Result < ( ) > {
153
- let mut number_of_percents = 0 ;
154
- for char in value. chars ( ) {
155
- if char == '%' {
156
- number_of_percents += 1 ;
157
- } else if number_of_percents % 2 != 0 {
158
- anyhow:: bail!( "Systemd specifiers are not supported by bound bootc images: {value}" ) ;
159
- } else {
160
- number_of_percents = 0 ;
154
+ fn parse_spec_value ( value : & str ) -> Result < String > {
155
+ let mut it = value. chars ( ) ;
156
+ let mut ret = String :: new ( ) ;
157
+ while let Some ( c) = it. next ( ) {
158
+ if c != '%' {
159
+ ret. push ( c) ;
160
+ continue ;
161
+ }
162
+ let c = it. next ( ) . ok_or_else ( || anyhow:: anyhow!( "Unterminated %" ) ) ?;
163
+ match c {
164
+ '%' => {
165
+ ret. push ( '%' ) ;
166
+ }
167
+ _ => {
168
+ anyhow:: bail!( "Systemd specifiers are not supported by bound bootc images: {value}" )
169
+ }
161
170
}
162
171
}
163
-
164
- Ok ( ( ) )
172
+ Ok ( ret)
165
173
}
166
174
167
175
#[ cfg( test) ]
@@ -229,22 +237,59 @@ mod tests {
229
237
}
230
238
231
239
#[ test]
232
- fn test_validate_spec_value ( ) -> Result < ( ) > {
233
- //should not return an error with no % characters
234
- let value = String :: from ( "[Image]\n Image=quay.io/foo/foo:latest" ) ;
235
- validate_spec_value ( & value) . unwrap ( ) ;
240
+ fn test_parse_spec_value ( ) -> Result < ( ) > {
241
+ //should parse string with no % characters
242
+ let value = String :: from ( "quay.io/foo/foo:latest" ) ;
243
+ assert_eq ! ( parse_spec_value( & value) . unwrap( ) , value) ;
244
+
245
+ //should parse string with % followed by another %
246
+ let value = String :: from ( "quay.io/foo/%%foo:latest" ) ;
247
+ assert_eq ! ( parse_spec_value( & value) . unwrap( ) , "quay.io/foo/%foo:latest" ) ;
248
+
249
+ //should parse string with multiple separate %%
250
+ let value = String :: from ( "quay.io/foo/%%foo:%%latest" ) ;
251
+ assert_eq ! (
252
+ parse_spec_value( & value) . unwrap( ) ,
253
+ "quay.io/foo/%foo:%latest"
254
+ ) ;
255
+
256
+ //should parse the string with %% at the start or end
257
+ let value = String :: from ( "%%quay.io/foo/foo:latest%%" ) ;
258
+ assert_eq ! (
259
+ parse_spec_value( & value) . unwrap( ) ,
260
+ "%quay.io/foo/foo:latest%"
261
+ ) ;
262
+
263
+ //should not return an error with multiple %% in a row
264
+ let value = String :: from ( "quay.io/foo/%%%%foo:latest" ) ;
265
+ assert_eq ! (
266
+ parse_spec_value( & value) . unwrap( ) ,
267
+ "quay.io/foo/%%foo:latest"
268
+ ) ;
236
269
237
270
//should return error when % is NOT followed by another %
238
- let value = String :: from ( "[Image]\n Image=quay.io/foo/%foo:latest" ) ;
239
- assert ! ( validate_spec_value( & value) . is_err( ) ) ;
271
+ let value = String :: from ( "quay.io/foo/%foo:latest" ) ;
272
+ assert ! ( parse_spec_value( & value) . is_err( ) ) ;
273
+
274
+ //should return an error when %% is followed by a specifier
275
+ let value = String :: from ( "quay.io/foo/%%%foo:latest" ) ;
276
+ assert ! ( parse_spec_value( & value) . is_err( ) ) ;
277
+
278
+ //should return an error when there are two specifiers
279
+ let value = String :: from ( "quay.io/foo/%f%ooo:latest" ) ;
280
+ assert ! ( parse_spec_value( & value) . is_err( ) ) ;
281
+
282
+ //should return an error with a specifier at the start
283
+ let value = String :: from ( "%fquay.io/foo/foo:latest" ) ;
284
+ assert ! ( parse_spec_value( & value) . is_err( ) ) ;
240
285
241
- //should not return an error when % is followed by another %
242
- let value = String :: from ( "[Image] \n Image= quay.io/foo/%% foo:latest" ) ;
243
- validate_spec_value ( & value) . unwrap ( ) ;
286
+ //should return an error with a specifier at the end
287
+ let value = String :: from ( "quay.io/foo/foo:latest%f " ) ;
288
+ assert ! ( parse_spec_value ( & value) . is_err ( ) ) ;
244
289
245
- //should not return an error when %% is followed by a specifier
246
- let value = String :: from ( "[Image] \n Image= quay.io/foo/%%% foo:latest" ) ;
247
- assert ! ( validate_spec_value ( & value) . is_err( ) ) ;
290
+ //should return an error with a single % at the end
291
+ let value = String :: from ( "quay.io/foo/foo:latest% " ) ;
292
+ assert ! ( parse_spec_value ( & value) . is_err( ) ) ;
248
293
249
294
Ok ( ( ) )
250
295
}
0 commit comments