@@ -20,6 +20,20 @@ pub enum EngineType {
2020 Other ,
2121}
2222
23+ impl EngineType {
24+ /// Returns `true` if the engine type is [`Podman`](Self::Podman) or [`PodmanRemote`](Self::PodmanRemote).
25+ #[ must_use]
26+ pub fn is_podman ( & self ) -> bool {
27+ matches ! ( self , Self :: Podman | Self :: PodmanRemote )
28+ }
29+
30+ /// Returns `true` if the engine type is [`Docker`](EngineType::Docker).
31+ #[ must_use]
32+ pub fn is_docker ( & self ) -> bool {
33+ matches ! ( self , Self :: Docker )
34+ }
35+ }
36+
2337#[ derive( Clone , Debug , PartialEq , Eq ) ]
2438pub struct Engine {
2539 pub kind : EngineType ,
@@ -117,82 +131,97 @@ fn get_engine_info(
117131 EngineType :: Other
118132 } ;
119133
120- let mut cmd = Command :: new ( ce) ;
121- cmd. args ( & [ "version" , "-f" , "{{ .Server.Os }},,,{{ .Server.Arch }}" ] ) ;
122-
123- let out = cmd. run_and_get_output ( msg_info) ?;
124-
125- let stdout = out. stdout ( ) ?. to_lowercase ( ) ;
126-
127- let osarch = stdout
128- . trim ( )
129- . split_once ( ",,," )
130- . map ( |( os, arch) | -> Result < _ > { Ok ( ( ContainerOs :: new ( os) ?, Architecture :: new ( arch) ?) ) } )
131- . transpose ( ) ;
132-
133- let osarch = match ( kind, osarch) {
134- ( _, Ok ( Some ( osarch) ) ) => Some ( osarch) ,
135- ( EngineType :: PodmanRemote | EngineType :: Podman , Ok ( None ) ) => get_podman_info ( ce, msg_info) ?,
136- ( _, Err ( e) ) => {
137- return Err ( e. wrap_err ( format ! (
138- "command `{}` returned unexpected data" ,
139- cmd. command_pretty( msg_info, |_| false )
140- ) ) ) ;
134+ // this can fail: podman can give partial output
135+ // linux,,,Error: template: version:1:15: executing "version" at <.Arch>:
136+ // can't evaluate field Arch in type *define.Version
137+ let os_arch_server = engine_info (
138+ ce,
139+ & [ "version" , "-f" , "{{ .Server.Os }},,,{{ .Server.Arch }}" ] ,
140+ ",,," ,
141+ msg_info,
142+ ) ;
143+
144+ let ( os_arch_other, os_arch_server_result) = match os_arch_server {
145+ Ok ( Some ( os_arch) ) => ( Ok ( Some ( os_arch) ) , None ) ,
146+ result => {
147+ if kind. is_podman ( ) {
148+ ( get_podman_info ( ce, msg_info) , result. err ( ) )
149+ } else {
150+ ( get_custom_info ( ce, msg_info) , result. err ( ) )
151+ }
141152 }
142- ( EngineType :: Docker | EngineType :: Other , Ok ( None ) ) => None ,
143153 } ;
144154
145- let osarch = if osarch. is_some ( ) {
146- osarch
147- } else if !out. status . success ( ) {
148- get_custom_info ( ce, msg_info) . with_error ( || {
149- cmd. status_result ( msg_info, out. status , Some ( & out) )
150- . expect_err ( "status_result should error" )
151- } ) ?
152- } else {
153- get_custom_info ( ce, msg_info) ?
155+ let os_arch = match ( os_arch_other, os_arch_server_result) {
156+ ( Ok ( os_arch) , _) => os_arch,
157+ ( Err ( e) , Some ( server_err) ) => return Err ( server_err. to_section_report ( ) . with_error ( || e) ) ,
158+ ( Err ( e) , None ) => return Err ( e. to_section_report ( ) ) ,
154159 } ;
155160
156- let ( os, arch) = osarch . map_or ( <_ >:: default ( ) , |( os, arch) | ( Some ( os) , Some ( arch) ) ) ;
161+ let ( os, arch) = os_arch . map_or ( <_ >:: default ( ) , |( os, arch) | ( Some ( os) , Some ( arch) ) ) ;
157162 Ok ( ( kind, arch, os) )
158163}
159164
160- fn get_podman_info (
165+ #[ derive( Debug , thiserror:: Error ) ]
166+ pub enum EngineInfoError {
167+ #[ error( transparent) ]
168+ Eyre ( eyre:: Report ) ,
169+ #[ error( "could not get os and arch" ) ]
170+ CommandError ( #[ from] CommandError ) ,
171+ }
172+
173+ impl EngineInfoError {
174+ pub fn to_section_report ( self ) -> eyre:: Report {
175+ match self {
176+ EngineInfoError :: Eyre ( e) => e,
177+ EngineInfoError :: CommandError ( e) => {
178+ e. to_section_report ( ) . wrap_err ( "could not get os and arch" )
179+ }
180+ }
181+ }
182+ }
183+
184+ /// Get engine info
185+ fn engine_info (
161186 ce : & Path ,
187+ args : & [ & str ] ,
188+ sep : & str ,
162189 msg_info : & mut MessageInfo ,
163- ) -> Result < Option < ( ContainerOs , Architecture ) > > {
190+ ) -> Result < Option < ( ContainerOs , Architecture ) > , EngineInfoError > {
164191 let mut cmd = Command :: new ( ce) ;
165- cmd. args ( & [ "info" , "-f" , "{{ .Version.OsArch }}" ] ) ;
166- cmd. run_and_get_stdout ( msg_info)
167- . map ( |s| {
168- s. to_lowercase ( )
169- . trim ( )
170- . split_once ( '/' )
171- . map ( |( os, arch) | -> Result < _ > {
172- Ok ( ( ContainerOs :: new ( os) ?, Architecture :: new ( arch) ?) )
173- } )
174- } )
175- . wrap_err ( "could not determine os and architecture of vm" ) ?
192+ cmd. args ( args) ;
193+ let out = cmd
194+ . run_and_get_output ( msg_info)
195+ . map_err ( EngineInfoError :: Eyre ) ?;
196+
197+ cmd. status_result ( msg_info, out. status , Some ( & out) ) ?;
198+
199+ out. stdout ( ) ?
200+ . to_lowercase ( )
201+ . trim ( )
202+ . split_once ( sep)
203+ . map ( |( os, arch) | -> Result < _ > { Ok ( ( ContainerOs :: new ( os) ?, Architecture :: new ( arch) ?) ) } )
176204 . transpose ( )
205+ . map_err ( EngineInfoError :: Eyre )
206+ }
207+
208+ fn get_podman_info (
209+ ce : & Path ,
210+ msg_info : & mut MessageInfo ,
211+ ) -> Result < Option < ( ContainerOs , Architecture ) > , EngineInfoError > {
212+ engine_info ( ce, & [ "info" , "-f" , "{{ .Version.OsArch }}" ] , "/" , msg_info)
177213}
178214
179215fn get_custom_info (
180216 ce : & Path ,
181217 msg_info : & mut MessageInfo ,
182- ) -> Result < Option < ( ContainerOs , Architecture ) > > {
183- let mut cmd = Command :: new ( ce) ;
184- cmd. args ( & [ "info" , "-f" , "{{ .Client.Os }},,,{{ .Client.Arch }}" ] ) ;
185- cmd. run_and_get_stdout ( msg_info)
186- . map ( |s| {
187- s. to_lowercase ( )
188- . trim ( )
189- . split_once ( ",,," )
190- . map ( |( os, arch) | -> Result < _ > {
191- Ok ( ( ContainerOs :: new ( os) ?, Architecture :: new ( arch) ?) )
192- } )
193- } )
194- . unwrap_or_default ( )
195- . transpose ( )
218+ ) -> Result < Option < ( ContainerOs , Architecture ) > , EngineInfoError > {
219+ engine_info (
220+ ce,
221+ & [ "version" , "-f" , "{{ .Client.Os }},,,{{ .Client.Arch }}" ] ,
222+ ",,," ,
223+ msg_info,
224+ )
196225}
197226
198227pub fn get_container_engine ( ) -> Result < PathBuf , which:: Error > {
0 commit comments