From 053aedd8336302668a2f6316ac6530b62115478a Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Thu, 27 Oct 2022 15:32:54 -0700 Subject: [PATCH 01/16] Add write output utilities Co-authored-by: Savannah Jackson --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/utils.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 02c27b8..53b9655 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + [[package]] name = "arrayref" version = "0.3.6" @@ -445,6 +451,7 @@ dependencies = [ name = "fission" version = "0.1.0" dependencies = [ + "anyhow", "base64 0.13.0", "bs58", "clap", diff --git a/Cargo.toml b/Cargo.toml index b1e2e4c..8d05ff0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.66" bs58 = "0.4.0" base64 = "0.13.0" clap = { version = "3.2.12", features = ["derive"] } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..7cd3105 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,53 @@ +use anyhow::{anyhow, Result}; +use std::io::{self, Write}; +use std::process::Output; + +pub struct OutputOptions { + verbose: bool, + quiet: bool, + error: bool, +} + +impl OutputOptions { + fn verbose() -> OutputOptions { + OutputOptions { + verbose: true, + quiet: false, + error: false, + } + } + + fn default() -> OutputOptions { + OutputOptions { + verbose: false, + quiet: false, + error: false, + } + } + + fn quiet() -> OutputOptions { + OutputOptions { + verbose: false, + quiet: true, + error: false, + } + } +} + +pub fn write_output(output: &Output) -> Result<()> { + let mut options = OutputOptions::verbose(); + + if output.stdout != [] { + print_output(std::str::from_utf8(&output.stdout)?, &options)?; + } + if output.stderr != [] { + options.error = true; + print_output(std::str::from_utf8(&output.stdout)?, &options)?; + } + Ok(()) +} + +pub fn print_output(output: &str, options: &OutputOptions) -> Result<()> { + println!("{}", output); + Ok(()) +} From 1812fdd34bcb5f14466675f7a5f11511443f8bed Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Wed, 2 Nov 2022 10:15:29 -0700 Subject: [PATCH 02/16] Add prepare arguments helper --- src/legacy.rs | 14 ++++++++++++++ src/lib.rs | 2 ++ 2 files changed, 16 insertions(+) create mode 100644 src/legacy.rs diff --git a/src/legacy.rs b/src/legacy.rs new file mode 100644 index 0000000..639217f --- /dev/null +++ b/src/legacy.rs @@ -0,0 +1,14 @@ +use std::iter::once; + +/// Convert argument tuples to a vector of argument strings. +/// +/// This function is glue to reformat args parsed by CLAP for +/// Command::args (https://doc.rust-lang.org/std/process/struct.Command.html#method.args). +/// +/// It keeps optional arguments CLAP parsed as Some(arg) and drops None arguments. +pub fn prepare_args(args: &[(&str, Option<&String>)]) -> Vec { + args.iter() + .filter(|tup| tup.1.is_some()) + .flat_map(|tup| once(tup.0.to_string()).chain(once(tup.1.unwrap().to_string()))) + .collect() +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 52958ec..dac0599 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,3 @@ pub mod cmd; +pub mod legacy; +pub mod utils; From 50e5afea1c849e022c93aa74684a9cbb209a82f4 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Wed, 2 Nov 2022 10:16:49 -0700 Subject: [PATCH 03/16] Add wrapped setup command --- src/cmd/setup.rs | 25 +++++++++++++++++++++++-- src/main.rs | 21 ++++++++++++++++++++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/cmd/setup.rs b/src/cmd/setup.rs index 9f9eebf..5388e27 100644 --- a/src/cmd/setup.rs +++ b/src/cmd/setup.rs @@ -1,8 +1,29 @@ +use anyhow::Result; use clap::Args; +use std::process::Command; +use crate::legacy::prepare_args; #[derive(Args)] struct Setup {} -pub fn run_command(username: Option) { - todo!("setup --username={:?}", username) +pub fn run_command( + username: Option, + email: Option, + keyfile: Option, + os: Option, +) -> Result<()> { + let args = prepare_args(&[ + ("-u", username.as_ref()), + ("-e", email.as_ref()), + ("-k", keyfile.as_ref()), + ("os", os.as_ref()), + ]); + + Command::new("fission") + .arg("setup") + .args(args) + .spawn()? + .wait()?; + + Ok(()) } diff --git a/src/main.rs b/src/main.rs index a56fa27..6f21168 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,17 @@ enum Commands { Setup { #[clap(short, long, value_parser, help = "The username to register")] username: Option, + #[clap(short, long, value_parser, help = "The email address for the account")] + email: Option, + #[clap( + short, + long = "with-key", + value_parser, + help = "A root keyfile to import" + )] + keyfile: Option, + #[clap(short, long, value_parser, help = "Override OS detection")] + os: Option, }, #[clap(about = "User application management")] User(User), @@ -33,7 +44,15 @@ fn main() { match cli.command { Commands::App(a) => run_app_command(a), Commands::Generate(g) => run_generate_command(g), - Commands::Setup { username } => run_setup_command(username), + Commands::Setup { + username, + email, + keyfile, + os, + } => match run_setup_command(username, email, keyfile, os) { + Ok(()) => (), + Err(_err) => eprintln!("💥 Failed to execute setup command."), + }, Commands::User(u) => run_user_command(u), } } From 3bd84cd5a6c9f0ef361f2413f22132c1e8bd09b8 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Wed, 2 Nov 2022 10:47:25 -0700 Subject: [PATCH 04/16] Add wrapped user whoami command --- src/cmd/user.rs | 11 +++++++++-- src/main.rs | 7 ++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/cmd/user.rs b/src/cmd/user.rs index 6999707..b8a3bd3 100644 --- a/src/cmd/user.rs +++ b/src/cmd/user.rs @@ -1,4 +1,6 @@ +use anyhow::Result; use clap::{Args, Subcommand}; +use std::process::Command; #[derive(Args)] pub struct User { @@ -17,13 +19,18 @@ pub enum UserCommands { Whoami, } -pub fn run_command(u: User) { +pub fn run_command(u: User) -> Result<()> { match u.command { UserCommands::Login { username: _ } => { todo!("login") } UserCommands::Whoami => { - todo!("whoami") + Command::new("fission") + .args(["user", "whoami"]) + .spawn()? + .wait()?; + + Ok(()) } } } diff --git a/src/main.rs b/src/main.rs index 6f21168..ba4631b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,11 @@ fn main() { Ok(()) => (), Err(_err) => eprintln!("💥 Failed to execute setup command."), }, - Commands::User(u) => run_user_command(u), + Commands::User(u) => match run_user_command(u) { + Ok(()) => (), + Err(_err) => eprintln!( + "💥 Failed to execute user command.", + ), + }, } } From b1a485ba7084ed94509bd1ba15cb35c50b78429b Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Wed, 2 Nov 2022 11:05:33 -0700 Subject: [PATCH 05/16] Add wrapped user login command --- src/cmd/user.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/cmd/user.rs b/src/cmd/user.rs index b8a3bd3..9e67992 100644 --- a/src/cmd/user.rs +++ b/src/cmd/user.rs @@ -1,3 +1,4 @@ +use crate::legacy::prepare_args; use anyhow::Result; use clap::{Args, Subcommand}; use std::process::Command; @@ -21,8 +22,16 @@ pub enum UserCommands { pub fn run_command(u: User) -> Result<()> { match u.command { - UserCommands::Login { username: _ } => { - todo!("login") + UserCommands::Login { username } => { + let args = prepare_args(&[("-u", username.as_ref())]); + + Command::new("fission") + .args(["user", "login"]) + .args(args) + .spawn()? + .wait()?; + + Ok(()) } UserCommands::Whoami => { Command::new("fission") From e1ebdff9c0cad31f87bc68b3b6acfb5f68b201f5 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Wed, 2 Nov 2022 11:42:54 -0700 Subject: [PATCH 06/16] Add whoami shortcut --- src/cmd/user.rs | 2 +- src/main.rs | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/cmd/user.rs b/src/cmd/user.rs index 9e67992..d4773d9 100644 --- a/src/cmd/user.rs +++ b/src/cmd/user.rs @@ -6,7 +6,7 @@ use std::process::Command; #[derive(Args)] pub struct User { #[clap(subcommand)] - command: UserCommands, + pub command: UserCommands, } #[derive(Subcommand)] diff --git a/src/main.rs b/src/main.rs index ba4631b..dc58013 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use fission::cmd::{ app::{run_command as run_app_command, App}, generate::{run_command as run_generate_command, Generate}, setup::run_command as run_setup_command, - user::{run_command as run_user_command, User}, + user::{run_command as run_user_command, User, UserCommands}, }; #[derive(Parser)] @@ -37,6 +37,10 @@ enum Commands { }, #[clap(about = "User application management")] User(User), + + // Shortcuts + #[clap(about = "Display current user")] + Whoami, } fn main() { let cli = Cli::parse(); @@ -55,9 +59,15 @@ fn main() { }, Commands::User(u) => match run_user_command(u) { Ok(()) => (), - Err(_err) => eprintln!( - "💥 Failed to execute user command.", - ), + Err(_err) => eprintln!("💥 Failed to execute user command.",), + }, + + // Shortcuts + Commands::Whoami => match run_user_command(User { + command: UserCommands::Whoami, + }) { + Ok(()) => (), + Err(_err) => eprintln!("💥 Failed to execute whoami command.",), }, } } From d389c50719b69e224582ee9a589b293cd49c438c Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Wed, 2 Nov 2022 14:27:43 -0700 Subject: [PATCH 07/16] Add wrapped app register command --- src/cmd/app.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 5 ++++- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/cmd/app.rs b/src/cmd/app.rs index 6cfb98d..e5a1170 100644 --- a/src/cmd/app.rs +++ b/src/cmd/app.rs @@ -42,7 +42,38 @@ pub enum AppCommands { watch: bool, }, #[clap(about = "Initialize an existing app")] - Register, + Register { + #[clap( + short, + long = "app-dir", + help = "The file path to initialize the app in (app config, etc.)", + default_value = ".", + value_name = "PATH" + )] + app_dir: String, + #[clap( + short, + long = "build-dir", + help = "The file path of the assets or directory to sync", + value_name = "PATH" + )] + build_dir: Option, + #[clap(short, long = "name", help = "Optional app name")] + name: Option, + #[clap( + long = "ipfs-bin", + help = "Path to IPFS binary [default: `which ipfs`]", + value_name = "BIN_PATH" + )] + ipfs_bin: Option, + #[clap( + long = "ipfs-timeout", + help = "IPFS timeout", + default_value = "1800", + value_name = "SECONDS" + )] + ipfs_timeout: String, + }, } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ArgEnum)] @@ -51,7 +82,7 @@ pub enum Potency { Destroy, SuperUser, } -pub fn run_command(a: App) { +pub fn run_command(a: App) -> Result<()> { match a.command { AppCommands::Delegate { app_name: _, @@ -65,8 +96,28 @@ pub fn run_command(a: App) { AppCommands::Publish { open: _, watch: _ } => { todo!("publish") } - AppCommands::Register => { - todo!("register") + AppCommands::Register { + app_dir, + build_dir, + name, + ipfs_bin, + ipfs_timeout, + } => { + let args = prepare_args(&[ + ("-a", Some(app_dir).as_ref()), + ("-b", build_dir.as_ref()), + ("-n", name.as_ref()), + ("--ipfs-bin", ipfs_bin.as_ref()), + ("--ipfs-timeout", Some(ipfs_timeout).as_ref()), + ]); + + Command::new("fission") + .args(["app", "register"]) + .args(args) + .spawn()? + .wait()?; + + Ok(()) } } } diff --git a/src/main.rs b/src/main.rs index dc58013..e398c02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,7 +46,10 @@ fn main() { let cli = Cli::parse(); match cli.command { - Commands::App(a) => run_app_command(a), + Commands::App(a) => match run_app_command(a) { + Ok(()) => (), + Err(_err) => eprintln!("💥 Failed to execute app command."), + }, Commands::Generate(g) => run_generate_command(g), Commands::Setup { username, From 5fec1bcce4cf4e0e53ac5309bcb261850bf95e39 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Wed, 2 Nov 2022 15:13:58 -0700 Subject: [PATCH 08/16] Add prepare flags helper --- src/legacy.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/legacy.rs b/src/legacy.rs index 639217f..9c9a210 100644 --- a/src/legacy.rs +++ b/src/legacy.rs @@ -1,5 +1,18 @@ use std::iter::once; +/// Convert flag tuples to a vector of flag strings +/// +/// This function is glue to reformat flags parsed by CLAP for +/// Command::args (https://doc.rust-lang.org/std/process/struct.Command.html#method.args). +/// +/// It keeps flags CLAP parsed as True and drops False flags. +pub fn prepare_flags(flags: &[(&str, &bool)]) -> Vec { + flags.iter() + .filter(|tup| *tup.1) + .flat_map(|tup| once(tup.0.to_string())) + .collect() +} + /// Convert argument tuples to a vector of argument strings. /// /// This function is glue to reformat args parsed by CLAP for From fd8466d929517dc87b136f9d7809b66c2a155f8b Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Wed, 2 Nov 2022 15:15:18 -0700 Subject: [PATCH 09/16] Add wrapped app publish command --- src/cmd/app.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/cmd/app.rs b/src/cmd/app.rs index e5a1170..ae2e2f4 100644 --- a/src/cmd/app.rs +++ b/src/cmd/app.rs @@ -1,4 +1,7 @@ +use crate::legacy::{prepare_args, prepare_flags}; +use anyhow::Result; use clap::{ArgEnum, Args, Subcommand}; +use std::process::Command; #[derive(Args)] pub struct App { @@ -36,10 +39,43 @@ pub enum AppCommands { }, #[clap(about = "Upload the working directory")] Publish { + #[clap( + help = "The file path of the assets or directory to sync", + default_value = "./" + )] + path: String, #[clap(short, long, help = "Open your default browser after publish")] open: bool, #[clap(short, long, help = "Watch for changes & automatically trigger upload")] watch: bool, + #[clap( + long = "ipfs-bin", + help = "Path to IPFS binary [default: `which ipfs`]", + value_name = "BIN_PATH" + )] + ipfs_bin: Option, + #[clap( + long = "ipfs-timeout", + help = "IPFS timeout", + default_value = "1800", + value_name = "SECONDS" + )] + ipfs_timeout: String, + + #[clap( + long = "update-data", + help = "Upload the data", + default_value = "True", + value_name = "ARG" + )] + update_data: String, + #[clap( + long = "udpate-dns", + help = "Update DNS", + default_value = "True", + value_name = "ARG" + )] + update_dns: String, }, #[clap(about = "Initialize an existing app")] Register { @@ -93,8 +129,36 @@ pub fn run_command(a: App) -> Result<()> { } => { todo!("delegate") } - AppCommands::Publish { open: _, watch: _ } => { - todo!("publish") + AppCommands::Publish { + path, + open, + watch, + ipfs_bin, + ipfs_timeout, + update_data, + update_dns, + } => { + let flags = prepare_flags(&[ + ("-o", &open), + ("-w", &watch) + ]); + + let args = prepare_args(&[ + ("--ipfs-bin", ipfs_bin.as_ref()), + ("--ipfs-timeout", Some(ipfs_timeout).as_ref()), + ("--update-data", Some(update_data).as_ref()), + ("--update-dns", Some(update_dns).as_ref()), + ]); + + Command::new("fission") + .args(["app", "publish"]) + .arg(path) + .args(flags) + .args(args) + .spawn()? + .wait()?; + + Ok(()) } AppCommands::Register { app_dir, From 5d35b2bffd538e42eeb83c6678c9c193b375ac00 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Thu, 3 Nov 2022 09:22:31 -0700 Subject: [PATCH 10/16] Add wrapped app info command --- src/cmd/app.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cmd/app.rs b/src/cmd/app.rs index ae2e2f4..5964b11 100644 --- a/src/cmd/app.rs +++ b/src/cmd/app.rs @@ -37,6 +37,8 @@ pub enum AppCommands { #[clap(short, long, help = "Only output the UCAN on success")] quiet: bool, }, + #[clap(about = "Detail about the current app")] + Info, #[clap(about = "Upload the working directory")] Publish { #[clap( @@ -129,6 +131,14 @@ pub fn run_command(a: App) -> Result<()> { } => { todo!("delegate") } + AppCommands::Info => { + Command::new("fission") + .args(["app", "info"]) + .spawn()? + .wait()?; + + Ok(()) + } AppCommands::Publish { path, open, @@ -138,10 +148,7 @@ pub fn run_command(a: App) -> Result<()> { update_data, update_dns, } => { - let flags = prepare_flags(&[ - ("-o", &open), - ("-w", &watch) - ]); + let flags = prepare_flags(&[("-o", &open), ("-w", &watch)]); let args = prepare_args(&[ ("--ipfs-bin", ipfs_bin.as_ref()), From b609a1eac7eea6e8bb4fffeedab73bc145fcaf0c Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Thu, 3 Nov 2022 11:01:06 -0700 Subject: [PATCH 11/16] Add wrapped app delegate command --- src/cmd/app.rs | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/cmd/app.rs b/src/cmd/app.rs index 5964b11..b76ffdc 100644 --- a/src/cmd/app.rs +++ b/src/cmd/app.rs @@ -13,15 +13,14 @@ pub struct App { pub enum AppCommands { #[clap(about = "Delegate capability to an audience DID")] Delegate { - #[clap(short, long, value_parser, help = "The target app")] + #[clap(short, long, value_name = "NAME", help = "The target app")] app_name: Option, - #[clap(short, long, value_parser, help = "An audience DID")] + #[clap(short, long, help = "An audience DID")] did: Option, #[clap( short, long, - arg_enum, - value_parser, + value_enum, default_value = "append", help = "The potency to delegate" )] @@ -120,16 +119,43 @@ pub enum Potency { Destroy, SuperUser, } + +impl Potency { + fn to_string(&self) -> String { + match self { + Potency::Append => "Append".to_string(), + Potency::Destroy => "Destroy".to_string(), + Potency::SuperUser => "Super_User".to_string(), + } + } +} + pub fn run_command(a: App) -> Result<()> { match a.command { AppCommands::Delegate { - app_name: _, - did: _, - potency: _, - lifetime: _, - quiet: _, + app_name, + did, + lifetime, + potency, + quiet, } => { - todo!("delegate") + let flags = prepare_flags(&[("-q", &quiet)]); + + let args = prepare_args(&[ + ("-a", app_name.as_ref()), + ("-d", did.as_ref()), + ("-l", Some(lifetime.to_string()).as_ref()), + ("-p", Some(potency.to_string()).as_ref()), + ]); + + Command::new("fission") + .args(["app", "delegate"]) + .args(flags) + .args(args) + .spawn()? + .wait()?; + + Ok(()) } AppCommands::Info => { Command::new("fission") From 7df9355efae0eb04acef131722b3cdfd055b9bc0 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Fri, 4 Nov 2022 09:46:52 -0700 Subject: [PATCH 12/16] Fix typo in arg name --- src/cmd/app.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/app.rs b/src/cmd/app.rs index b76ffdc..6bc22c4 100644 --- a/src/cmd/app.rs +++ b/src/cmd/app.rs @@ -71,7 +71,7 @@ pub enum AppCommands { )] update_data: String, #[clap( - long = "udpate-dns", + long = "update-dns", help = "Update DNS", default_value = "True", value_name = "ARG" From 797e079199433aca67a7fa1018d9da1586f66c04 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Fri, 4 Nov 2022 10:41:04 -0700 Subject: [PATCH 13/16] Add global verbose flag --- src/cmd/app.rs | 32 +++++++++++++++++++++++--------- src/cmd/setup.rs | 5 ++++- src/cmd/user.rs | 18 ++++++++++++++---- src/main.rs | 16 ++++++++++++---- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/cmd/app.rs b/src/cmd/app.rs index 6bc22c4..bd234bc 100644 --- a/src/cmd/app.rs +++ b/src/cmd/app.rs @@ -28,16 +28,20 @@ pub enum AppCommands { #[clap( short, long, - value_parser, default_value_t = 300, help = "Lifetime in seconds before UCAN expires" )] lifetime: u16, #[clap(short, long, help = "Only output the UCAN on success")] quiet: bool, + #[clap(from_global)] + verbose: bool, }, #[clap(about = "Detail about the current app")] - Info, + Info { + #[clap(from_global)] + verbose: bool, + }, #[clap(about = "Upload the working directory")] Publish { #[clap( @@ -62,7 +66,6 @@ pub enum AppCommands { value_name = "SECONDS" )] ipfs_timeout: String, - #[clap( long = "update-data", help = "Upload the data", @@ -77,6 +80,8 @@ pub enum AppCommands { value_name = "ARG" )] update_dns: String, + #[clap(from_global)] + verbose: bool, }, #[clap(about = "Initialize an existing app")] Register { @@ -110,6 +115,8 @@ pub enum AppCommands { value_name = "SECONDS" )] ipfs_timeout: String, + #[clap(from_global)] + verbose: bool, }, } @@ -138,9 +145,10 @@ pub fn run_command(a: App) -> Result<()> { lifetime, potency, quiet, + verbose, } => { + // N.B. The wrapped app delegate command does not accept verbose let flags = prepare_flags(&[("-q", &quiet)]); - let args = prepare_args(&[ ("-a", app_name.as_ref()), ("-d", did.as_ref()), @@ -150,16 +158,19 @@ pub fn run_command(a: App) -> Result<()> { Command::new("fission") .args(["app", "delegate"]) - .args(flags) .args(args) + .args(flags) .spawn()? .wait()?; Ok(()) } - AppCommands::Info => { + AppCommands::Info { verbose } => { + let flags = prepare_flags(&[("-v", &verbose)]); + Command::new("fission") .args(["app", "info"]) + .args(flags) .spawn()? .wait()?; @@ -173,9 +184,9 @@ pub fn run_command(a: App) -> Result<()> { ipfs_timeout, update_data, update_dns, + verbose, } => { - let flags = prepare_flags(&[("-o", &open), ("-w", &watch)]); - + let flags = prepare_flags(&[("-o", &open), ("-w", &watch), ("-v", &verbose)]); let args = prepare_args(&[ ("--ipfs-bin", ipfs_bin.as_ref()), ("--ipfs-timeout", Some(ipfs_timeout).as_ref()), @@ -186,8 +197,8 @@ pub fn run_command(a: App) -> Result<()> { Command::new("fission") .args(["app", "publish"]) .arg(path) - .args(flags) .args(args) + .args(flags) .spawn()? .wait()?; @@ -199,7 +210,9 @@ pub fn run_command(a: App) -> Result<()> { name, ipfs_bin, ipfs_timeout, + verbose, } => { + let flags = prepare_flags(&[("-v", &verbose)]); let args = prepare_args(&[ ("-a", Some(app_dir).as_ref()), ("-b", build_dir.as_ref()), @@ -211,6 +224,7 @@ pub fn run_command(a: App) -> Result<()> { Command::new("fission") .args(["app", "register"]) .args(args) + .args(flags) .spawn()? .wait()?; diff --git a/src/cmd/setup.rs b/src/cmd/setup.rs index 5388e27..cabfe36 100644 --- a/src/cmd/setup.rs +++ b/src/cmd/setup.rs @@ -1,7 +1,7 @@ +use crate::legacy::{prepare_args, prepare_flags}; use anyhow::Result; use clap::Args; use std::process::Command; -use crate::legacy::prepare_args; #[derive(Args)] struct Setup {} @@ -11,7 +11,9 @@ pub fn run_command( email: Option, keyfile: Option, os: Option, + verbose: bool, ) -> Result<()> { + let flags = prepare_flags(&[("-v", &verbose)]); let args = prepare_args(&[ ("-u", username.as_ref()), ("-e", email.as_ref()), @@ -22,6 +24,7 @@ pub fn run_command( Command::new("fission") .arg("setup") .args(args) + .args(flags) .spawn()? .wait()?; diff --git a/src/cmd/user.rs b/src/cmd/user.rs index d4773d9..ee96f97 100644 --- a/src/cmd/user.rs +++ b/src/cmd/user.rs @@ -1,4 +1,4 @@ -use crate::legacy::prepare_args; +use crate::legacy::{prepare_args, prepare_flags}; use anyhow::Result; use clap::{Args, Subcommand}; use std::process::Command; @@ -15,27 +15,37 @@ pub enum UserCommands { Login { #[clap(short, long, value_parser, help = "Username")] username: Option, + #[clap(from_global)] + verbose: bool, }, #[clap(about = "Display current user")] - Whoami, + Whoami { + #[clap(from_global)] + verbose: bool, + }, } pub fn run_command(u: User) -> Result<()> { match u.command { - UserCommands::Login { username } => { + UserCommands::Login { username, verbose } => { + let flags = prepare_flags(&[("-v", &verbose)]); let args = prepare_args(&[("-u", username.as_ref())]); Command::new("fission") .args(["user", "login"]) .args(args) + .args(flags) .spawn()? .wait()?; Ok(()) } - UserCommands::Whoami => { + UserCommands::Whoami { verbose } => { + let flags = prepare_flags(&[("-v", &verbose)]); + Command::new("fission") .args(["user", "whoami"]) + .args(flags) .spawn()? .wait()?; diff --git a/src/main.rs b/src/main.rs index e398c02..ca0d42d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,8 @@ use fission::cmd::{ #[derive(Parser)] #[clap(author, version, about="Fission makes developing, deploying, updating, and iterating on web apps quick and easy.", long_about = None)] struct Cli { + #[clap(short, long, global = true, help = "Print detailed output")] + verbose: bool, #[clap(subcommand)] command: Commands, } @@ -34,13 +36,18 @@ enum Commands { keyfile: Option, #[clap(short, long, value_parser, help = "Override OS detection")] os: Option, + #[clap(from_global)] + verbose: bool, }, #[clap(about = "User application management")] User(User), // Shortcuts #[clap(about = "Display current user")] - Whoami, + Whoami { + #[clap(from_global)] + verbose: bool, + }, } fn main() { let cli = Cli::parse(); @@ -56,7 +63,8 @@ fn main() { email, keyfile, os, - } => match run_setup_command(username, email, keyfile, os) { + verbose, + } => match run_setup_command(username, email, keyfile, os, verbose) { Ok(()) => (), Err(_err) => eprintln!("💥 Failed to execute setup command."), }, @@ -66,8 +74,8 @@ fn main() { }, // Shortcuts - Commands::Whoami => match run_user_command(User { - command: UserCommands::Whoami, + Commands::Whoami { verbose } => match run_user_command(User { + command: UserCommands::Whoami { verbose }, }) { Ok(()) => (), Err(_err) => eprintln!("💥 Failed to execute whoami command.",), From c7945ed2b3e1d695d0dd917dce7d5506a9758008 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Fri, 4 Nov 2022 20:18:13 -0700 Subject: [PATCH 14/16] Add missing -- --- src/cmd/setup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/setup.rs b/src/cmd/setup.rs index cabfe36..d38ad74 100644 --- a/src/cmd/setup.rs +++ b/src/cmd/setup.rs @@ -18,7 +18,7 @@ pub fn run_command( ("-u", username.as_ref()), ("-e", email.as_ref()), ("-k", keyfile.as_ref()), - ("os", os.as_ref()), + ("--os", os.as_ref()), ]); Command::new("fission") From 27af3393af7e657f70ef111ea9bb4f2276e6cb81 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Mon, 7 Nov 2022 11:43:41 -0800 Subject: [PATCH 15/16] Add global remote argument --- src/cmd/app.rs | 18 +++++++++++++++++- src/cmd/setup.rs | 2 ++ src/cmd/user.rs | 12 +++++++++--- src/main.rs | 13 ++++++++++--- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/cmd/app.rs b/src/cmd/app.rs index bd234bc..a2c4304 100644 --- a/src/cmd/app.rs +++ b/src/cmd/app.rs @@ -36,11 +36,15 @@ pub enum AppCommands { quiet: bool, #[clap(from_global)] verbose: bool, + #[clap(from_global)] + remote: Option, }, #[clap(about = "Detail about the current app")] Info { #[clap(from_global)] verbose: bool, + #[clap(from_global)] + remote: Option, }, #[clap(about = "Upload the working directory")] Publish { @@ -82,6 +86,8 @@ pub enum AppCommands { update_dns: String, #[clap(from_global)] verbose: bool, + #[clap(from_global)] + remote: Option, }, #[clap(about = "Initialize an existing app")] Register { @@ -117,6 +123,8 @@ pub enum AppCommands { ipfs_timeout: String, #[clap(from_global)] verbose: bool, + #[clap(from_global)] + remote: Option, }, } @@ -146,6 +154,7 @@ pub fn run_command(a: App) -> Result<()> { potency, quiet, verbose, + remote, } => { // N.B. The wrapped app delegate command does not accept verbose let flags = prepare_flags(&[("-q", &quiet)]); @@ -154,6 +163,7 @@ pub fn run_command(a: App) -> Result<()> { ("-d", did.as_ref()), ("-l", Some(lifetime.to_string()).as_ref()), ("-p", Some(potency.to_string()).as_ref()), + ("-R", remote.as_ref()), ]); Command::new("fission") @@ -165,11 +175,13 @@ pub fn run_command(a: App) -> Result<()> { Ok(()) } - AppCommands::Info { verbose } => { + AppCommands::Info { verbose, remote} => { let flags = prepare_flags(&[("-v", &verbose)]); + let args = prepare_args(&[("-R", remote.as_ref())]); Command::new("fission") .args(["app", "info"]) + .args(args) .args(flags) .spawn()? .wait()?; @@ -185,6 +197,7 @@ pub fn run_command(a: App) -> Result<()> { update_data, update_dns, verbose, + remote, } => { let flags = prepare_flags(&[("-o", &open), ("-w", &watch), ("-v", &verbose)]); let args = prepare_args(&[ @@ -192,6 +205,7 @@ pub fn run_command(a: App) -> Result<()> { ("--ipfs-timeout", Some(ipfs_timeout).as_ref()), ("--update-data", Some(update_data).as_ref()), ("--update-dns", Some(update_dns).as_ref()), + ("-R", remote.as_ref()), ]); Command::new("fission") @@ -211,6 +225,7 @@ pub fn run_command(a: App) -> Result<()> { ipfs_bin, ipfs_timeout, verbose, + remote, } => { let flags = prepare_flags(&[("-v", &verbose)]); let args = prepare_args(&[ @@ -219,6 +234,7 @@ pub fn run_command(a: App) -> Result<()> { ("-n", name.as_ref()), ("--ipfs-bin", ipfs_bin.as_ref()), ("--ipfs-timeout", Some(ipfs_timeout).as_ref()), + ("-R", remote.as_ref()), ]); Command::new("fission") diff --git a/src/cmd/setup.rs b/src/cmd/setup.rs index d38ad74..e308f46 100644 --- a/src/cmd/setup.rs +++ b/src/cmd/setup.rs @@ -12,6 +12,7 @@ pub fn run_command( keyfile: Option, os: Option, verbose: bool, + remote: Option, ) -> Result<()> { let flags = prepare_flags(&[("-v", &verbose)]); let args = prepare_args(&[ @@ -19,6 +20,7 @@ pub fn run_command( ("-e", email.as_ref()), ("-k", keyfile.as_ref()), ("--os", os.as_ref()), + ("-R", remote.as_ref()), ]); Command::new("fission") diff --git a/src/cmd/user.rs b/src/cmd/user.rs index ee96f97..ee935db 100644 --- a/src/cmd/user.rs +++ b/src/cmd/user.rs @@ -17,19 +17,23 @@ pub enum UserCommands { username: Option, #[clap(from_global)] verbose: bool, + #[clap(from_global)] + remote: Option, }, #[clap(about = "Display current user")] Whoami { #[clap(from_global)] verbose: bool, + #[clap(from_global)] + remote: Option, }, } pub fn run_command(u: User) -> Result<()> { match u.command { - UserCommands::Login { username, verbose } => { + UserCommands::Login { username, verbose, remote } => { let flags = prepare_flags(&[("-v", &verbose)]); - let args = prepare_args(&[("-u", username.as_ref())]); + let args = prepare_args(&[("-u", username.as_ref()), ("-R", remote.as_ref())]); Command::new("fission") .args(["user", "login"]) @@ -40,11 +44,13 @@ pub fn run_command(u: User) -> Result<()> { Ok(()) } - UserCommands::Whoami { verbose } => { + UserCommands::Whoami { verbose, remote } => { let flags = prepare_flags(&[("-v", &verbose)]); + let args = prepare_args(&[("-R", remote.as_ref())]); Command::new("fission") .args(["user", "whoami"]) + .args(args) .args(flags) .spawn()? .wait()?; diff --git a/src/main.rs b/src/main.rs index ca0d42d..baa6261 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,8 @@ use fission::cmd::{ struct Cli { #[clap(short, long, global = true, help = "Print detailed output")] verbose: bool, + #[clap(short = 'R', long, global = true, hide = true)] + remote: Option, #[clap(subcommand)] command: Commands, } @@ -38,6 +40,8 @@ enum Commands { os: Option, #[clap(from_global)] verbose: bool, + #[clap(short = 'R', long, global = true, hide = true)] + remote: Option, }, #[clap(about = "User application management")] User(User), @@ -47,6 +51,8 @@ enum Commands { Whoami { #[clap(from_global)] verbose: bool, + #[clap(short = 'R', long, global = true, hide = true)] + remote: Option, }, } fn main() { @@ -64,7 +70,8 @@ fn main() { keyfile, os, verbose, - } => match run_setup_command(username, email, keyfile, os, verbose) { + remote + } => match run_setup_command(username, email, keyfile, os, verbose, remote) { Ok(()) => (), Err(_err) => eprintln!("💥 Failed to execute setup command."), }, @@ -74,8 +81,8 @@ fn main() { }, // Shortcuts - Commands::Whoami { verbose } => match run_user_command(User { - command: UserCommands::Whoami { verbose }, + Commands::Whoami { verbose, remote } => match run_user_command(User { + command: UserCommands::Whoami { verbose, remote }, }) { Ok(()) => (), Err(_err) => eprintln!("💥 Failed to execute whoami command.",), From 4f48f7cd56f972129f89af87ce34507285d4d33f Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Tue, 8 Nov 2022 11:20:54 -0800 Subject: [PATCH 16/16] Convert prepare helpers to use HashMap --- src/cmd/app.rs | 44 ++++++++++++++++++++++++++------------------ src/cmd/setup.rs | 11 ++++++----- src/cmd/user.rs | 20 +++++++++++++------- src/legacy.rs | 37 +++++++++++++++++++------------------ 4 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/cmd/app.rs b/src/cmd/app.rs index a2c4304..1d68360 100644 --- a/src/cmd/app.rs +++ b/src/cmd/app.rs @@ -1,7 +1,7 @@ use crate::legacy::{prepare_args, prepare_flags}; use anyhow::Result; use clap::{ArgEnum, Args, Subcommand}; -use std::process::Command; +use std::{collections::HashMap, process::Command}; #[derive(Args)] pub struct App { @@ -156,32 +156,34 @@ pub fn run_command(a: App) -> Result<()> { verbose, remote, } => { - // N.B. The wrapped app delegate command does not accept verbose - let flags = prepare_flags(&[("-q", &quiet)]); - let args = prepare_args(&[ + let args = prepare_args(&HashMap::from([ ("-a", app_name.as_ref()), ("-d", did.as_ref()), ("-l", Some(lifetime.to_string()).as_ref()), ("-p", Some(potency.to_string()).as_ref()), - ("-R", remote.as_ref()), - ]); + ])); + let remote = prepare_args(&HashMap::from([("-R", remote.as_ref())])); + + // N.B. The wrapped app delegate command does not accept verbose + let flags = prepare_flags(&HashMap::from([("-q", quiet)])); Command::new("fission") .args(["app", "delegate"]) .args(args) + .args(remote) .args(flags) .spawn()? .wait()?; Ok(()) } - AppCommands::Info { verbose, remote} => { - let flags = prepare_flags(&[("-v", &verbose)]); - let args = prepare_args(&[("-R", remote.as_ref())]); + AppCommands::Info { verbose, remote } => { + let remote = prepare_args(&HashMap::from([("-R", remote.as_ref())])); + let flags = prepare_flags(&HashMap::from([("-v", verbose)])); Command::new("fission") .args(["app", "info"]) - .args(args) + .args(remote) .args(flags) .spawn()? .wait()?; @@ -199,19 +201,24 @@ pub fn run_command(a: App) -> Result<()> { verbose, remote, } => { - let flags = prepare_flags(&[("-o", &open), ("-w", &watch), ("-v", &verbose)]); - let args = prepare_args(&[ + let args = prepare_args(&HashMap::from([ ("--ipfs-bin", ipfs_bin.as_ref()), ("--ipfs-timeout", Some(ipfs_timeout).as_ref()), ("--update-data", Some(update_data).as_ref()), ("--update-dns", Some(update_dns).as_ref()), - ("-R", remote.as_ref()), - ]); + ])); + let remote = prepare_args(&HashMap::from([("-R", remote.as_ref())])); + let flags = prepare_flags(&HashMap::from([ + ("-o", open), + ("-w", watch), + ("-v", verbose), + ])); Command::new("fission") .args(["app", "publish"]) .arg(path) .args(args) + .args(remote) .args(flags) .spawn()? .wait()?; @@ -227,19 +234,20 @@ pub fn run_command(a: App) -> Result<()> { verbose, remote, } => { - let flags = prepare_flags(&[("-v", &verbose)]); - let args = prepare_args(&[ + let args = prepare_args(&HashMap::from([ ("-a", Some(app_dir).as_ref()), ("-b", build_dir.as_ref()), ("-n", name.as_ref()), ("--ipfs-bin", ipfs_bin.as_ref()), ("--ipfs-timeout", Some(ipfs_timeout).as_ref()), - ("-R", remote.as_ref()), - ]); + ])); + let remote = prepare_args(&HashMap::from([("-R", remote.as_ref())])); + let flags = prepare_flags(&HashMap::from([("-v", verbose)])); Command::new("fission") .args(["app", "register"]) .args(args) + .args(remote) .args(flags) .spawn()? .wait()?; diff --git a/src/cmd/setup.rs b/src/cmd/setup.rs index e308f46..4168e46 100644 --- a/src/cmd/setup.rs +++ b/src/cmd/setup.rs @@ -1,7 +1,7 @@ use crate::legacy::{prepare_args, prepare_flags}; use anyhow::Result; use clap::Args; -use std::process::Command; +use std::{collections::HashMap, process::Command}; #[derive(Args)] struct Setup {} @@ -14,18 +14,19 @@ pub fn run_command( verbose: bool, remote: Option, ) -> Result<()> { - let flags = prepare_flags(&[("-v", &verbose)]); - let args = prepare_args(&[ + let args = prepare_args(&HashMap::from([ ("-u", username.as_ref()), ("-e", email.as_ref()), ("-k", keyfile.as_ref()), ("--os", os.as_ref()), - ("-R", remote.as_ref()), - ]); + ])); + let remote = prepare_args(&HashMap::from([("-R", remote.as_ref())])); + let flags = prepare_flags(&HashMap::from([("-v", verbose)])); Command::new("fission") .arg("setup") .args(args) + .args(remote) .args(flags) .spawn()? .wait()?; diff --git a/src/cmd/user.rs b/src/cmd/user.rs index ee935db..4db1c16 100644 --- a/src/cmd/user.rs +++ b/src/cmd/user.rs @@ -1,7 +1,7 @@ use crate::legacy::{prepare_args, prepare_flags}; use anyhow::Result; use clap::{Args, Subcommand}; -use std::process::Command; +use std::{collections::HashMap, process::Command}; #[derive(Args)] pub struct User { @@ -31,13 +31,19 @@ pub enum UserCommands { pub fn run_command(u: User) -> Result<()> { match u.command { - UserCommands::Login { username, verbose, remote } => { - let flags = prepare_flags(&[("-v", &verbose)]); - let args = prepare_args(&[("-u", username.as_ref()), ("-R", remote.as_ref())]); + UserCommands::Login { + username, + verbose, + remote, + } => { + let args = prepare_args(&HashMap::from([("-u", username.as_ref())])); + let remote = prepare_args(&HashMap::from([("-R", remote.as_ref())])); + let flags = prepare_flags(&HashMap::from([("-v", verbose)])); Command::new("fission") .args(["user", "login"]) .args(args) + .args(remote) .args(flags) .spawn()? .wait()?; @@ -45,12 +51,12 @@ pub fn run_command(u: User) -> Result<()> { Ok(()) } UserCommands::Whoami { verbose, remote } => { - let flags = prepare_flags(&[("-v", &verbose)]); - let args = prepare_args(&[("-R", remote.as_ref())]); + let remote = prepare_args(&HashMap::from([("-R", remote.as_ref())])); + let flags = prepare_flags(&HashMap::from([("-v", verbose)])); Command::new("fission") .args(["user", "whoami"]) - .args(args) + .args(remote) .args(flags) .spawn()? .wait()?; diff --git a/src/legacy.rs b/src/legacy.rs index 9c9a210..6a07ecd 100644 --- a/src/legacy.rs +++ b/src/legacy.rs @@ -1,27 +1,28 @@ -use std::iter::once; +use std::{collections::HashMap, iter::once}; -/// Convert flag tuples to a vector of flag strings -/// +/// Convert flags to a vector of flag strings +/// /// This function is glue to reformat flags parsed by CLAP for /// Command::args (https://doc.rust-lang.org/std/process/struct.Command.html#method.args). -/// +/// /// It keeps flags CLAP parsed as True and drops False flags. -pub fn prepare_flags(flags: &[(&str, &bool)]) -> Vec { - flags.iter() - .filter(|tup| *tup.1) - .flat_map(|tup| once(tup.0.to_string())) - .collect() +pub fn prepare_flags(flags: &HashMap<&str, bool>) -> Vec { + flags + .iter() + .filter(|tup| *tup.1) + .flat_map(|tup| once(tup.0.to_string())) + .collect() } -/// Convert argument tuples to a vector of argument strings. -/// +/// Convert arguments to a vector of argument strings. +/// /// This function is glue to reformat args parsed by CLAP for /// Command::args (https://doc.rust-lang.org/std/process/struct.Command.html#method.args). -/// +/// /// It keeps optional arguments CLAP parsed as Some(arg) and drops None arguments. -pub fn prepare_args(args: &[(&str, Option<&String>)]) -> Vec { - args.iter() - .filter(|tup| tup.1.is_some()) - .flat_map(|tup| once(tup.0.to_string()).chain(once(tup.1.unwrap().to_string()))) - .collect() -} \ No newline at end of file +pub fn prepare_args(args: &HashMap<&str, Option<&String>>) -> Vec { + args.iter() + .filter(|tup| tup.1.is_some()) + .flat_map(|tup| once(tup.0.to_string()).chain(once(tup.1.unwrap().to_string()))) + .collect() +}