From b15911d0a6d97b3b9b1da988a90666c6e313e530 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Wed, 3 Jan 2024 13:22:06 +0100 Subject: [PATCH 1/2] allow using --file - to read from stdin --- cli/src/utils.rs | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/cli/src/utils.rs b/cli/src/utils.rs index 82f202a92b..ce4677c031 100644 --- a/cli/src/utils.rs +++ b/cli/src/utils.rs @@ -21,7 +21,7 @@ pub struct FileOrUrl { pub url: Option, /// The path to the encoded metadata file. #[clap(long, value_parser)] - pub file: Option, + pub file: Option, /// Specify the metadata version. /// /// - "latest": Use the latest stable version available. @@ -33,6 +33,26 @@ pub struct FileOrUrl { pub version: Option, } +/// if `--path -` is provided, read bytes for metadata from stdin +const STDIN_PATH_NAME: &str = "-"; +#[derive(Debug, Clone)] +pub enum PathOrStdIn { + Path(PathBuf), + StdIn, +} + +impl FromStr for PathOrStdIn { + type Err = ::Err; + + fn from_str(s: &str) -> Result { + if s == STDIN_PATH_NAME { + Ok(PathOrStdIn::StdIn) + } else { + PathBuf::from_str(s).map(PathOrStdIn::Path) + } + } +} + impl FileOrUrl { /// Fetch the metadata bytes. pub async fn fetch(&self) -> color_eyre::Result> { @@ -42,12 +62,20 @@ impl FileOrUrl { eyre::bail!("specify one of `--url` or `--file` but not both") } // Load from --file path - (Some(path), None, None) => { + (Some(PathOrStdIn::Path(path)), None, None) => { let mut file = fs::File::open(path)?; let mut bytes = Vec::new(); file.read_to_end(&mut bytes)?; Ok(bytes) } + (Some(PathOrStdIn::StdIn), None, None) => { + let res = std::io::stdin().bytes().collect::, _>>(); + + match res { + Ok(bytes) => Ok(bytes), + Err(err) => eyre::bail!("reading bytes from stdin (`--file -`) failed: {err}"), + } + } // Cannot load the metadata from the file and specify a version to fetch. (Some(_), None, Some(_)) => { // Note: we could provide the ability to convert between metadata versions @@ -92,16 +120,23 @@ impl FromStr for FileOrUrl { type Err = &'static str; fn from_str(s: &str) -> Result { + if s == STDIN_PATH_NAME { + return Ok(FileOrUrl { + url: None, + file: Some(PathOrStdIn::StdIn), + version: None, + }); + } let path = std::path::Path::new(s); if path.exists() { Ok(FileOrUrl { url: None, - file: Some(PathBuf::from(s)), + file: Some(PathOrStdIn::Path(PathBuf::from(s))), version: None, }) } else { Url::parse(s) - .map_err(|_| "no path or uri could be crated") + .map_err(|_| "no path or uri could be created.") .map(|uri| FileOrUrl { url: Some(uri), file: None, From 6566ffd2503aea5877b0465b551fcc899fcfc640 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Wed, 3 Jan 2024 17:04:23 +0100 Subject: [PATCH 2/2] add test for path and url parsing --- cli/src/utils.rs | 93 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/cli/src/utils.rs b/cli/src/utils.rs index ce4677c031..f96d24a7ef 100644 --- a/cli/src/utils.rs +++ b/cli/src/utils.rs @@ -33,7 +33,29 @@ pub struct FileOrUrl { pub version: Option, } -/// if `--path -` is provided, read bytes for metadata from stdin +impl FromStr for FileOrUrl { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + if let Ok(path) = PathOrStdIn::from_str(s) { + Ok(FileOrUrl { + url: None, + file: Some(path), + version: None, + }) + } else { + Url::parse(s) + .map_err(|_| "Parsing Path or Uri failed.") + .map(|uri| FileOrUrl { + url: Some(uri), + file: None, + version: None, + }) + } + } +} + +/// If `--path -` is provided, read bytes for metadata from stdin const STDIN_PATH_NAME: &str = "-"; #[derive(Debug, Clone)] pub enum PathOrStdIn { @@ -42,13 +64,19 @@ pub enum PathOrStdIn { } impl FromStr for PathOrStdIn { - type Err = ::Err; + type Err = &'static str; fn from_str(s: &str) -> Result { + let s = s.trim(); if s == STDIN_PATH_NAME { Ok(PathOrStdIn::StdIn) } else { - PathBuf::from_str(s).map(PathOrStdIn::Path) + let path = std::path::Path::new(s); + if path.exists() { + Ok(PathOrStdIn::Path(PathBuf::from(path))) + } else { + Err("Path does not exist.") + } } } } @@ -116,32 +144,49 @@ pub fn with_indent(s: String, indent: usize) -> String { .join("\n") } -impl FromStr for FileOrUrl { - type Err = &'static str; +#[cfg(test)] +mod tests { + use crate::utils::{FileOrUrl, PathOrStdIn}; + use std::str::FromStr; - fn from_str(s: &str) -> Result { - if s == STDIN_PATH_NAME { - return Ok(FileOrUrl { + #[test] + fn parsing() { + assert!(matches!( + FileOrUrl::from_str("-"), + Ok(FileOrUrl { url: None, file: Some(PathOrStdIn::StdIn), - version: None, - }); - } - let path = std::path::Path::new(s); - if path.exists() { + version: None + }) + ),); + + assert!(matches!( + FileOrUrl::from_str(" - "), Ok(FileOrUrl { url: None, - file: Some(PathOrStdIn::Path(PathBuf::from(s))), - version: None, + file: Some(PathOrStdIn::StdIn), + version: None }) - } else { - Url::parse(s) - .map_err(|_| "no path or uri could be created.") - .map(|uri| FileOrUrl { - url: Some(uri), - file: None, - version: None, - }) - } + ),); + + assert!(matches!( + FileOrUrl::from_str("./src/main.rs"), + Ok(FileOrUrl { + url: None, + file: Some(PathOrStdIn::Path(_)), + version: None + }) + ),); + + assert!(FileOrUrl::from_str("./src/i_dont_exist.rs").is_err()); + + assert!(matches!( + FileOrUrl::from_str("https://github.com/paritytech/subxt"), + Ok(FileOrUrl { + url: Some(_), + file: None, + version: None + }) + )); } }