22#![ allow( clippy:: almost_swapped) ]
33
44use anyhow:: { anyhow, Context , Result } ;
5- use clap:: { Parser , Subcommand } ;
5+ use clap:: { Parser , Subcommand , ValueEnum } ;
66use semver:: Version ;
77use spin_plugins:: {
88 error:: Error ,
@@ -616,6 +616,16 @@ pub struct List {
616616 /// Filter the list to plugins containing this string.
617617 #[ clap( long = "filter" ) ]
618618 pub filter : Option < String > ,
619+
620+ /// The format in which to list the templates.
621+ #[ clap( value_enum, long = "format" , default_value = "plain" , hide = true ) ]
622+ pub format : ListFormat ,
623+ }
624+
625+ #[ derive( ValueEnum , Clone , Debug ) ]
626+ pub enum ListFormat {
627+ Plain ,
628+ Json ,
619629}
620630
621631impl List {
@@ -636,11 +646,13 @@ impl List {
636646 plugins. retain ( |p| p. name . contains ( filter) ) ;
637647 }
638648
639- Self :: print ( & plugins) ;
640- Ok ( ( ) )
649+ match self . format {
650+ ListFormat :: Plain => Self :: print_plain ( & plugins) ,
651+ ListFormat :: Json => Self :: print_json ( & plugins) ,
652+ }
641653 }
642654
643- fn print ( plugins : & [ PluginDescriptor ] ) {
655+ fn print_plain ( plugins : & [ PluginDescriptor ] ) -> anyhow :: Result < ( ) > {
644656 if plugins. is_empty ( ) {
645657 println ! ( "No plugins found" ) ;
646658 } else {
@@ -662,6 +674,16 @@ impl List {
662674 println ! ( "{} {}{}{}" , p. name, p. version, installed, compat) ;
663675 }
664676 }
677+
678+ Ok ( ( ) )
679+ }
680+
681+ fn print_json ( plugins : & [ PluginDescriptor ] ) -> anyhow:: Result < ( ) > {
682+ let json_vals: Vec < _ > = plugins. iter ( ) . map ( json_list_format) . collect ( ) ;
683+
684+ let json_text = serde_json:: to_string_pretty ( & json_vals) ?;
685+ println ! ( "{}" , json_text) ;
686+ Ok ( ( ) )
665687 }
666688}
667689
@@ -670,6 +692,10 @@ impl List {
670692pub struct Search {
671693 /// The text to search for. If omitted, all plugins are returned.
672694 pub filter : Option < String > ,
695+
696+ /// The format in which to list the plugins.
697+ #[ clap( value_enum, long = "format" , default_value = "plain" , hide = true ) ]
698+ pub format : ListFormat ,
673699}
674700
675701impl Search {
@@ -679,6 +705,7 @@ impl Search {
679705 all : true ,
680706 summary : false ,
681707 filter : self . filter . clone ( ) ,
708+ format : self . format . clone ( ) ,
682709 } ;
683710
684711 list_cmd. run ( ) . await
@@ -731,6 +758,36 @@ impl PluginDescriptor {
731758 }
732759}
733760
761+ #[ derive( serde:: Serialize ) ]
762+ #[ serde( rename_all = "camelCase" ) ]
763+ struct PluginJsonFormat {
764+ name : String ,
765+ installed : bool ,
766+ version : String ,
767+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
768+ installed_version : Option < String > ,
769+ }
770+
771+ fn json_list_format ( plugin : & PluginDescriptor ) -> PluginJsonFormat {
772+ let installed_version = if plugin. installed {
773+ Some (
774+ plugin
775+ . installed_version
776+ . clone ( )
777+ . unwrap_or ( plugin. version . clone ( ) ) ,
778+ )
779+ } else {
780+ None
781+ } ;
782+
783+ PluginJsonFormat {
784+ name : plugin. name . clone ( ) ,
785+ installed : plugin. installed ,
786+ version : plugin. version . clone ( ) ,
787+ installed_version,
788+ }
789+ }
790+
734791// Auxiliar function for Upgrade::upgrade_multiselect
735792fn elements_at < T > ( source : Vec < T > , indexes : Vec < usize > ) -> Vec < T > {
736793 source
0 commit comments