@@ -30,6 +30,9 @@ pub enum Error {
3030 #[ error( "i/o error" ) ]
3131 /// An input/output error
3232 Io ( #[ from] std:: io:: Error ) ,
33+ #[ error( "skopeo spawn error: {}" , . 0 ) ]
34+ /// An error spawning skopeo
35+ SkopeoSpawnError ( #[ source] std:: io:: Error ) ,
3336 #[ error( "serialization error" ) ]
3437 /// Returned when serialization or deserialization fails
3538 SerDe ( #[ from] serde_json:: Error ) ,
@@ -324,7 +327,10 @@ impl ImageProxy {
324327 None ,
325328 ) ?;
326329 c. stdin ( Stdio :: from ( theirsock) ) ;
327- let child = c. spawn ( ) ?;
330+ let child = match c. spawn ( ) {
331+ Ok ( c) => c,
332+ Err ( error) => return Err ( Error :: SkopeoSpawnError ( error) ) ,
333+ } ;
328334 tracing:: debug!( "Spawned skopeo pid={:?}" , child. id( ) ) ;
329335 // Here we use std sync API via thread because tokio installs
330336 // a SIGCHLD handler which can conflict with e.g. the glib one
@@ -687,4 +693,19 @@ mod tests {
687693 . unwrap ( ) ;
688694 validate ( c, & [ "--authfile" , "/proc/self/fd/100" ] , & [ ] ) ;
689695 }
696+
697+ #[ tokio:: test]
698+ async fn skopeo_not_found ( ) {
699+ let mut config = ImageProxyConfig {
700+ ..ImageProxyConfig :: default ( )
701+ } ;
702+ config. skopeo_cmd = Some ( Command :: new ( "no-skopeo" ) ) ;
703+
704+ let res = ImageProxy :: new_with_config ( config) . await ;
705+ assert ! ( matches!( res, Err ( Error :: SkopeoSpawnError ( _) ) ) ) ;
706+ assert_eq ! (
707+ res. err( ) . unwrap( ) . to_string( ) ,
708+ "skopeo spawn error: No such file or directory (os error 2)"
709+ ) ;
710+ }
690711}
0 commit comments