Skip to content

Commit d2fb46f

Browse files
committed
spin plugins list --json
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
1 parent abba523 commit d2fb46f

File tree

1 file changed

+61
-4
lines changed

1 file changed

+61
-4
lines changed

Diff for: src/commands/plugins.rs

+61-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#![allow(clippy::almost_swapped)]
33

44
use anyhow::{anyhow, Context, Result};
5-
use clap::{Parser, Subcommand};
5+
use clap::{Parser, Subcommand, ValueEnum};
66
use semver::Version;
77
use 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")]
622+
pub format: ListFormat,
623+
}
624+
625+
#[derive(ValueEnum, Clone, Debug)]
626+
pub enum ListFormat {
627+
Plain,
628+
Json,
619629
}
620630

621631
impl 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 {
670692
pub 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")]
698+
pub format: ListFormat,
673699
}
674700

675701
impl 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_else(|| 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
735792
fn elements_at<T>(source: Vec<T>, indexes: Vec<usize>) -> Vec<T> {
736793
source

0 commit comments

Comments
 (0)