From 545c7df917af7862917ea1fffd6ed58416caf1ef Mon Sep 17 00:00:00 2001 From: Thorsten Hans Date: Thu, 1 Oct 2026 07:01:49 +0200 Subject: [PATCH 1/2] feat: Add --init flag allowing users to scaffold the toml Signed-off-by: Thorsten Hans --- README.md | 10 ++++-- src/main.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 60aca55..ab20d28 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,18 @@ cargo build --release ## Preparation -For your plugin, create a `spin-pluginify.toml` file with the following content: +You can scaffold a new `spin-pluginify.toml` manifest using `--init`: + +```bash +spin pluginify --init --name --package <./PATH/TO/EXECUTABLE> +``` + +This creates a `spin-pluginify.toml` file with reasonable defaults. Alternatively, you can manually create a `spin-pluginify.toml` file with the following content: ```toml name = "" version = "0.1" -spin_compatibility = ">=0.7" +spin_compatibility = ">=4.0.0" license = "Apache-2.0" package = "<./PATH/TO/EXECUTABLE>" # optional - if present these files will be added to the plugin tar file diff --git a/src/main.rs b/src/main.rs index a838f32..152c613 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,17 +60,52 @@ struct PluginifyCommand { /// Install the plugin when done. #[clap(short, long)] install: bool, + + /// Scaffold a new spin-pluginify manifest. + #[clap( + name = "INIT", + long = "init", + conflicts_with = "FILE", + conflicts_with = "BINARY", + conflicts_with = "MERGE", + conflicts_with = "install", + requires = "NAME", + requires = "PACKAGE" + )] + init: bool, + + /// The name of the plugin (requires --init). + #[clap( + name = "NAME", + short = 'n', + long = "name", + help_heading = "Init Options", + requires = "INIT" + )] + name: Option, + + /// Path to the plugin executable (requires --init). + #[clap( + name = "PACKAGE", + short = 'p', + long = "package", + help_heading = "Init Options", + requires = "INIT" + )] + package: Option, } fn main() -> Result<(), Error> { let cmd = PluginifyCommand::parse(); - if cmd.merge { - cmd.run_merge() - } else { - cmd.run_local() + match (cmd.init, cmd.merge) { + (true, _) => cmd.run_init(), + (_, true) => cmd.run_merge(), + _ => cmd.run_local(), } + } + impl PluginifyCommand { fn packaging_settings(&self) -> Result { if let Some(binary) = self.immediate.as_ref() { @@ -98,6 +133,42 @@ impl PluginifyCommand { Ok(ps) } + fn run_init(&self) -> Result<(), Error> { + let output_path = PathBuf::from("spin-pluginify.toml"); + + if output_path.exists() { + anyhow::bail!( + "Manifest file `{}` already exists", + output_path.display() + ); + } + + let name = self.name.clone().context("plugin name is required")?; + let package = self.package.clone().context("package path is required")?; + + let manifest = InitManifest { + name, + version: "0.1.0".to_string(), + spin_compatibility: ">=4.0.0".to_string(), + license: "Apache-2.0".to_string(), + package, + }; + + let toml_string = toml::to_string_pretty(&manifest) + .context("failed to serialize manifest to TOML")?; + + if self.verbose { + eprintln!("Scaffolded manifest content:\n{toml_string}"); + } + + std::fs::write(&output_path, &toml_string) + .with_context(|| format!("failed to write manifest to `{}`", output_path.display()))?; + + println!("Created `{}`", output_path.display()); + + Ok(()) + } + fn run_local(&self) -> Result<(), Error> { let ps = self.packaging_settings()?; @@ -327,6 +398,15 @@ fn file_digest_string(path: &PathBuf) -> Result { Ok(digest_string) } +#[derive(Debug, serde::Serialize)] +struct InitManifest { + name: String, + version: String, + spin_compatibility: String, + license: String, + package: PathBuf, +} + #[derive(Debug, serde::Deserialize)] #[serde(rename_all = "snake_case")] struct PackagingSettings { @@ -382,4 +462,4 @@ fn try_infer_version(file: impl AsRef) -> anyhow::Result { } Err(anyhow!("`spin pluginify` doesn't know how to infer version from `{filed}`")) -} +} \ No newline at end of file From c442a35e12a25a10e1341b94c3e769697df6a134 Mon Sep 17 00:00:00 2001 From: Thorsten Hans Date: Thu, 1 Oct 2026 22:27:00 +0200 Subject: [PATCH 2/2] chore: review feedback applied Signed-off-by: Thorsten Hans --- src/main.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/main.rs b/src/main.rs index 152c613..996f4b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -146,12 +146,15 @@ impl PluginifyCommand { let name = self.name.clone().context("plugin name is required")?; let package = self.package.clone().context("package path is required")?; - let manifest = InitManifest { + let manifest = PackagingSettings { name, - version: "0.1.0".to_string(), + package, spin_compatibility: ">=4.0.0".to_string(), license: "Apache-2.0".to_string(), - package, + version: PluginVersion::Exact("0.1.0".to_string()), + description: None, + homepage: None, + assets: None, }; let toml_string = toml::to_string_pretty(&manifest) @@ -398,16 +401,7 @@ fn file_digest_string(path: &PathBuf) -> Result { Ok(digest_string) } -#[derive(Debug, serde::Serialize)] -struct InitManifest { - name: String, - version: String, - spin_compatibility: String, - license: String, - package: PathBuf, -} - -#[derive(Debug, serde::Deserialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] struct PackagingSettings { name: String, @@ -427,7 +421,7 @@ impl PackagingSettings { } } -#[derive(Clone, Debug, serde::Deserialize)] +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(untagged)] enum PluginVersion { Exact(String),