11use std:: collections:: { BTreeMap , BTreeSet } ;
22
3+ use clap:: builder:: PossibleValue ;
34use clap:: { Args , Subcommand } ;
45use cross:: docker:: { self , CROSS_CUSTOM_DOCKERFILE_IMAGE_PREFIX } ;
56use cross:: shell:: MessageInfo ;
@@ -26,6 +27,9 @@ pub struct ListImages {
2627 /// Container engine (such as docker or podman).
2728 #[ clap( long) ]
2829 pub engine : Option < String > ,
30+ /// Output format
31+ #[ clap( long, default_value = "human" ) ]
32+ pub format : OutputFormat ,
2933 /// Only list images for specific target(s). By default, list all targets.
3034 pub targets : Vec < String > ,
3135}
@@ -36,6 +40,25 @@ impl ListImages {
3640 }
3741}
3842
43+ #[ derive( Clone , Debug ) ]
44+ pub enum OutputFormat {
45+ Human ,
46+ Json ,
47+ }
48+
49+ impl clap:: ValueEnum for OutputFormat {
50+ fn value_variants < ' a > ( ) -> & ' a [ Self ] {
51+ & [ Self :: Human , Self :: Json ]
52+ }
53+
54+ fn to_possible_value ( & self ) -> Option < PossibleValue > {
55+ match self {
56+ OutputFormat :: Human => Some ( PossibleValue :: new ( "human" ) ) ,
57+ OutputFormat :: Json => Some ( PossibleValue :: new ( "json" ) ) ,
58+ }
59+ }
60+ }
61+
3962#[ derive( Args , Debug ) ]
4063pub struct RemoveImages {
4164 /// If not provided, remove all images.
@@ -118,7 +141,7 @@ impl Images {
118141 }
119142}
120143
121- #[ derive( Debug , PartialOrd , Ord , PartialEq , Eq ) ]
144+ #[ derive( Debug , PartialOrd , Ord , PartialEq , Eq , serde :: Serialize ) ]
122145struct Image {
123146 repository : String ,
124147 tag : String ,
@@ -258,7 +281,9 @@ fn get_image_target(
258281}
259282
260283pub fn list_images (
261- ListImages { targets, .. } : ListImages ,
284+ ListImages {
285+ targets, format, ..
286+ } : ListImages ,
262287 engine : & docker:: Engine ,
263288 msg_info : & mut MessageInfo ,
264289) -> cross:: Result < ( ) > {
@@ -281,45 +306,55 @@ pub fn list_images(
281306 let mut keys: Vec < & str > = map. keys ( ) . map ( |k| k. as_ref ( ) ) . collect ( ) ;
282307 keys. sort_unstable ( ) ;
283308
284- let print_string =
285- |col1 : & str , col2 : & str , fill : char , info : & mut MessageInfo | -> cross:: Result < ( ) > {
286- let mut row = String :: new ( ) ;
287- row. push ( '|' ) ;
288- row. push ( fill) ;
289- row. push_str ( col1) ;
290- let spaces = max_target_len. max ( col1. len ( ) ) + 1 - col1. len ( ) ;
291- for _ in 0 ..spaces {
292- row. push ( fill) ;
293- }
294- row. push ( '|' ) ;
295- row. push ( fill) ;
296- row. push_str ( col2) ;
297- let spaces = max_image_len. max ( col2. len ( ) ) + 1 - col2. len ( ) ;
298- for _ in 0 ..spaces {
299- row. push ( fill) ;
309+ match format {
310+ OutputFormat :: Json => {
311+ msg_info. info ( format_args ! ( "{}" , serde_json:: to_string( & map) ?) ) ?;
312+ }
313+ OutputFormat :: Human => {
314+ let print_string =
315+ |col1 : & str , col2 : & str , fill : char , info : & mut MessageInfo | -> cross:: Result < ( ) > {
316+ let mut row = String :: new ( ) ;
317+ row. push ( '|' ) ;
318+ row. push ( fill) ;
319+ row. push_str ( col1) ;
320+ let spaces = max_target_len. max ( col1. len ( ) ) + 1 - col1. len ( ) ;
321+ for _ in 0 ..spaces {
322+ row. push ( fill) ;
323+ }
324+ row. push ( '|' ) ;
325+ row. push ( fill) ;
326+ row. push_str ( col2) ;
327+ let spaces = max_image_len. max ( col2. len ( ) ) + 1 - col2. len ( ) ;
328+ for _ in 0 ..spaces {
329+ row. push ( fill) ;
330+ }
331+ row. push ( '|' ) ;
332+ info. print ( row)
333+ } ;
334+
335+ if targets. len ( ) != 1 {
336+ print_string ( "Targets" , "Images" , ' ' , msg_info) ?;
337+ print_string ( "-------" , "------" , '-' , msg_info) ?;
300338 }
301- row. push ( '|' ) ;
302- info. print ( row)
303- } ;
304-
305- if targets. len ( ) != 1 {
306- print_string ( "Targets" , "Images" , ' ' , msg_info) ?;
307- print_string ( "-------" , "------" , '-' , msg_info) ?;
308- }
309339
310- let print_single =
311- |_: & str , image : & Image , info : & mut MessageInfo | -> cross:: Result < ( ) > { info. print ( image) } ;
312- let print_table = |target : & str , image : & Image , info : & mut MessageInfo | -> cross:: Result < ( ) > {
313- let name = image. name ( ) ;
314- print_string ( target, & name, ' ' , info)
315- } ;
316-
317- for target in keys {
318- for image in map. get ( target) . expect ( "map must have key" ) . iter ( ) {
319- if targets. len ( ) == 1 {
320- print_single ( target, image, msg_info) ?;
321- } else {
322- print_table ( target, image, msg_info) ?;
340+ let print_single = |_: & str ,
341+ image : & Image ,
342+ info : & mut MessageInfo |
343+ -> cross:: Result < ( ) > { info. print ( image) } ;
344+ let print_table =
345+ |target : & str , image : & Image , info : & mut MessageInfo | -> cross:: Result < ( ) > {
346+ let name = image. name ( ) ;
347+ print_string ( target, & name, ' ' , info)
348+ } ;
349+
350+ for target in keys {
351+ for image in map. get ( target) . expect ( "map must have key" ) . iter ( ) {
352+ if targets. len ( ) == 1 {
353+ print_single ( target, image, msg_info) ?;
354+ } else {
355+ print_table ( target, image, msg_info) ?;
356+ }
357+ }
323358 }
324359 }
325360 }
0 commit comments