diff --git a/crates/wash-lib/src/cli/mod.rs b/crates/wash-lib/src/cli/mod.rs index 60828310..545ede04 100644 --- a/crates/wash-lib/src/cli/mod.rs +++ b/crates/wash-lib/src/cli/mod.rs @@ -43,6 +43,7 @@ pub mod get; pub mod inspect; pub mod link; pub mod output; +pub mod par; pub mod registry; pub mod spy; pub mod start; diff --git a/crates/wash-lib/src/cli/par.rs b/crates/wash-lib/src/cli/par.rs new file mode 100644 index 00000000..cfb0dfe4 --- /dev/null +++ b/crates/wash-lib/src/cli/par.rs @@ -0,0 +1,59 @@ +use anyhow::{anyhow, Context, Result}; +use provider_archive::ProviderArchive; +use std::path::PathBuf; + +pub struct ParCreateArgs { + pub capid: String, + pub vendor: String, + pub revision: Option, + pub version: Option, + pub schema: Option, + pub name: String, + pub arch: String, +} + +pub async fn create_provider_archive( + ParCreateArgs { + capid, + vendor, + revision, + version, + schema, + name, + arch, + }: ParCreateArgs, + binary_bytes: &[u8], +) -> Result { + let mut par = ProviderArchive::new(&capid, &name, &vendor, revision, version); + + par.add_library(&arch, binary_bytes) + .map_err(convert_error)?; + + if let Some(ref schema) = schema { + let bytes = std::fs::read(schema)?; + par.set_schema( + serde_json::from_slice::(&bytes) + .with_context(|| "Unable to parse JSON from file contents".to_string())?, + ) + .map_err(convert_error) + .with_context(|| format!("Error parsing JSON schema from file '{:?}'", schema))?; + } + + Ok(par) +} + +pub async fn insert_provider_binary( + arch: String, + binary_bytes: &[u8], + mut par: ProviderArchive, +) -> Result { + par.add_library(&arch, binary_bytes) + .map_err(convert_error)?; + + Ok(par) +} + +/// Converts error from Send + Sync error to standard anyhow error +pub fn convert_error(e: Box) -> anyhow::Error { + anyhow!(e.to_string()) +} diff --git a/src/par.rs b/src/par.rs index a22e7fda..fe3a632b 100644 --- a/src/par.rs +++ b/src/par.rs @@ -1,13 +1,15 @@ -use std::{collections::HashMap, fs::File, io::prelude::*, path::PathBuf}; +use std::fs::File; +use std::io::Read; +use std::{collections::HashMap, path::PathBuf}; -use crate::util::convert_error; use anyhow::{anyhow, bail, Context, Result}; use clap::{Parser, Subcommand}; use log::warn; use nkeys::KeyPairType; use provider_archive::ProviderArchive; use serde_json::json; -use wash_lib::cli::{extract_keypair, inspect, CommandOutput, OutputKind}; +use wash_lib::cli::par::{convert_error, create_provider_archive, insert_provider_binary}; +use wash_lib::cli::{extract_keypair, inspect, par, CommandOutput, OutputKind}; const GZIP_MAGIC: [u8; 2] = [0x1f, 0x8b]; @@ -204,6 +206,21 @@ impl From for inspect::InspectCliCommand { } } } + +impl From for par::ParCreateArgs { + fn from(cmd: CreateCommand) -> Self { + par::ParCreateArgs { + capid: cmd.capid, + vendor: cmd.vendor, + revision: cmd.revision, + version: cmd.version, + schema: cmd.schema, + name: cmd.name, + arch: cmd.arch, + } + } +} + pub(crate) async fn handle_command( command: ParCliCommand, output_kind: OutputKind, @@ -223,20 +240,12 @@ pub(crate) async fn handle_create( cmd: CreateCommand, output_kind: OutputKind, ) -> Result { - let mut par = ProviderArchive::new( - &cmd.capid, - &cmd.name, - &cmd.vendor, - cmd.revision, - cmd.version, - ); - let mut f = File::open(cmd.binary.clone())?; let mut lib = Vec::new(); f.read_to_end(&mut lib)?; let issuer = extract_keypair( - cmd.issuer, + cmd.issuer.clone(), Some(cmd.binary.clone()), cmd.directory.clone(), KeyPairType::Account, @@ -244,18 +253,16 @@ pub(crate) async fn handle_create( output_kind, )?; let subject = extract_keypair( - cmd.subject, + cmd.subject.clone(), Some(cmd.binary.clone()), - cmd.directory, + cmd.directory.clone(), KeyPairType::Service, cmd.disable_keygen, output_kind, )?; - par.add_library(&cmd.arch, &lib).map_err(convert_error)?; - let extension = if cmd.compress { ".par.gz" } else { ".par" }; - let outfile = match cmd.destination { + let outfile = match cmd.destination.clone() { Some(path) => path, None => format!( "{}{}", @@ -267,16 +274,8 @@ pub(crate) async fn handle_create( extension ), }; - if let Some(ref schema) = cmd.schema { - let bytes = std::fs::read(schema)?; - par.set_schema( - serde_json::from_slice::(&bytes) - .with_context(|| "Unable to parse JSON from file contents".to_string())?, - ) - .map_err(convert_error) - .with_context(|| format!("Error parsing JSON schema from file '{:?}'", schema))?; - } + let mut par = create_provider_archive(cmd.clone().into(), &lib).await?; par.write(&outfile, &issuer, &subject, cmd.compress) .await .map_err(|e| anyhow!("{}", e)) @@ -304,33 +303,32 @@ pub(crate) async fn handle_insert( let mut f = File::open(cmd.archive.clone())?; f.read_to_end(&mut buf)?; - let mut par = ProviderArchive::try_load(&buf) - .await - .map_err(convert_error)?; + let mut f = File::open(cmd.binary.clone())?; + let mut lib = Vec::new(); + f.read_to_end(&mut lib)?; let issuer = extract_keypair( - cmd.issuer, - Some(cmd.binary.clone()), + cmd.issuer.clone(), + Some(cmd.binary.clone().to_owned()), cmd.directory.clone(), KeyPairType::Account, cmd.disable_keygen, output_kind, )?; let subject = extract_keypair( - cmd.subject, - Some(cmd.binary.clone()), - cmd.directory, + cmd.subject.clone(), + Some(cmd.binary.clone().to_owned()), + cmd.directory.clone(), KeyPairType::Service, cmd.disable_keygen, output_kind, )?; - let mut f = File::open(cmd.binary.clone())?; - let mut lib = Vec::new(); - f.read_to_end(&mut lib)?; - - par.add_library(&cmd.arch, &lib).map_err(convert_error)?; + let mut par = ProviderArchive::try_load(&buf) + .await + .map_err(convert_error)?; + par = insert_provider_binary(cmd.arch, &lib, par).await?; par.write(&cmd.archive, &issuer, &subject, is_compressed(&buf)?) .await .map_err(convert_error)?; diff --git a/src/util.rs b/src/util.rs index 3fc796de..03e651be 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,6 @@ use std::{fs::File, io::Read, path::PathBuf}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result}; use term_table::{Table, TableStyle}; use wash_lib::config::DEFAULT_NATS_TIMEOUT_MS; @@ -25,11 +25,6 @@ pub(crate) fn default_timeout_ms() -> u64 { DEFAULT_NATS_TIMEOUT_MS } -/// Converts error from Send + Sync error to standard anyhow error -pub(crate) fn convert_error(e: Box) -> anyhow::Error { - anyhow!(e.to_string()) -} - /// Transform a json string (e.g. "{"hello": "world"}") into msgpack bytes pub(crate) fn json_str_to_msgpack_bytes(payload: &str) -> Result> { let json = serde_json::from_str::(payload)?;