Skip to content

Commit

Permalink
Properly handle envs when outputting cmd_str (#14)
Browse files Browse the repository at this point in the history
* handle cmd string with env

* format

* more err handling on fs::create_p_dir

* fix clippy
  • Loading branch information
kurtlawrence authored Aug 30, 2023
1 parent d8432fd commit 4fe5b85
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 62 deletions.
1 change: 0 additions & 1 deletion macros/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ fn cargs_expanding() {
assert_eq!(a, ["hello/path".to_string(), "a literal".to_string()]);
}


#[test]
fn cmd_smoketest() {
let a = format!("{:?}", cmd!(ls));
Expand Down
4 changes: 2 additions & 2 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl Args {
pub fn finish(&mut self) -> Result<()> {
let mut x = true;
let idx = self.idx;
while let Some(_) = self.peek_str() {
while self.peek_str().is_some() {
x = false;
self.advance_pos();
}
Expand Down Expand Up @@ -240,7 +240,7 @@ impl Args {
/// assert_eq!(&args.req::<String>("filepath").unwrap(), "fst.txt");
/// assert_eq!(args.peek_str(), Some("24h"));
/// ```
pub fn peek_str<'a>(&'a mut self) -> Option<&'a str> {
pub fn peek_str(&mut self) -> Option<&str> {
if self.idx >= self.seen.len() {
self.seen.extend(self.incoming.next());
}
Expand Down
67 changes: 41 additions & 26 deletions src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ impl CommandExecute for Command {
}

/// Methods on [`Command`] which take `self`.
///
///
/// This is useful with [`cargs!`](crate::prelude::cargs).
///
///
/// # Example
/// ```rust
/// # use rust_script_ext::prelude::*;
Expand Down Expand Up @@ -215,9 +215,10 @@ impl CommandBuilder for Command {
}

fn with_env<K, V>(mut self, key: K, val: V) -> Self
where
K: AsRef<OsStr>,
V: AsRef<OsStr> {
where
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
self.env(key, val);
self
}
Expand Down Expand Up @@ -246,23 +247,26 @@ pub trait CommandString {
impl CommandString for Command {
fn cmd_str(&self) -> String {
// note that the debug format is unstable and need careful testing/handling
// dbg!(self);
let x = format!("{self:?}");
let prg = x
.split_once(' ')
.map(|x| x.0)
.unwrap_or(&x)
.trim_matches('"');
// println!("{prg}");
// let prg = x
// .split_once("program:")
// .expect("known format")
// .1
// .split_once(",")
// .expect("known format")
// .0
// .trim()
// .trim_matches('"');
let x = format!("{self:#?}");
// eprintln!("{x}");

let prg = if cfg!(windows) {
x.split_once(' ')
.map(|x| x.0)
.unwrap_or(&x)
.trim_matches('"')
} else {
x.split_once("program:")
.expect("known format")
.1
.split_once(',')
.expect("known format")
.0
.trim()
.trim_matches('"')
};

// eprintln!("{prg}");

self.get_args()
.fold(prg.to_string(), |s, a| s + " " + &*a.to_string_lossy())
Expand Down Expand Up @@ -296,7 +300,6 @@ mod tests {
}

#[test]
#[cfg(unix)]
fn cmd_execute() {
let x = cmd!(ls).execute_str(Quiet).unwrap();
let mut x = x.trim().split('\n').collect::<Vec<_>>();
Expand All @@ -309,18 +312,30 @@ mod tests {
"Cargo.toml",
"LICENSE",
"README.md",
"local.rs",
"macros",
"src",
"target",
"template.rs",
]
);

let x = cmd!(ls "foo").execute_str(Verbose).unwrap_err();
let x = cmd!(ls: "foo").execute_str(Verbose).unwrap_err();
assert_snapshot!("execute-err", pretty_print_err(x));

let x = cmd!(watcmd "foo").execute_str(Verbose).unwrap_err();
let x = cmd!(watcmd: "foo").execute_str(Verbose).unwrap_err();
assert_snapshot!("unknown-cmd", pretty_print_err(x));
}
#[test]
fn cmd_naming_with_env() {
let x = cmd!(ls).with_env("YO", "zog").cmd_str();
assert_eq!(&x, "ls");

let x = cmd!(ls: foo, bar).with_env("YO", "zog").cmd_str();
assert_eq!(&x, "ls foo bar");

let x = cmd!(ls: foo, bar)
.with_envs([("YO", "zog"), ("JO", "bar")])
.cmd_str();
assert_eq!(&x, "ls foo bar");
}
}
4 changes: 2 additions & 2 deletions src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl File {
/// Opens a file in write-only mode.
///
/// This function will create a file if it does not exist, and will truncate it if it does.
///
///
/// **If the parent directory does not exist, it will be created.**
pub fn create(path: impl Into<PathBuf>) -> Result<Self> {
let path = path.into();
Expand Down Expand Up @@ -131,7 +131,7 @@ impl File {
fn create_p_dir(path: &Path) {
if let Some(p) = path.parent() {
if let Err(e) = std::fs::create_dir_all(p) {
eprintln!("failed to create parent directory '{}'", p.display());
eprintln!("failed to create parent directory '{}': {e}", p.display());
}
}
}
Expand Down
62 changes: 31 additions & 31 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
//! These patterns include file reading, argument parsing, error handling.
//!
//! # Argument Parsing
//!
//!
//! A rudimentary argument parser is provided, simply call [`args`](args::args).
//!
//! The parsing is meant to be simple, tailored to script usage. For fully featured CLI apps,
//! consider importing [`clap`](https://docs.rs/clap/latest/clap/index.html).
//!
//! # Error Handling
//!
//!
//! Error handling uses the [`miette`] crate.
//! A `Result` type alias is exposed, and [`IntoDiagnostic`](prelude::IntoDiagnostic) can be used
//! to convert errors.
Expand All @@ -31,32 +31,32 @@
//!
//! Running commands is done through `std::process::Command`.
//! There are a few helper traits and macros to assist in:
//!
//!
//! 1. Building a `Command`, and
//! 2. Executing a command.
//!
//!
//! Building commands can leverage the [`cmd!`](crate::prelude::cmd) macro.
//! This can be used to succintly build a command with arguments.
//!
//!
//! ```rust
//! # use rust_script_ext::prelude::*;
//! let x = 1.0;
//! let cmd = cmd!(./my-script.sh: foo/bar, --verbose, {x + 2.14});
//! assert_eq!(&cmd.cmd_str(), "./my-script.sh foo/bar --verbose 3.14");
//! ```
//!
//!
//! The [`CommandExecute`](crate::prelude::CommandExecute) trait provides some methods which
//! can execute a command and automatically collect the output, along with providing verbose
//! error messages if something fails.
//!
//!
//! ```rust,no_run
//! # use rust_script_ext::prelude::*;
//! // Verbose means also print stdout/stderr to terminal as execution occurs
//! cmd!(ls: src).execute_str(Verbose).unwrap();
//! ```
//!
//! # Serialisation
//!
//!
//! [`Serialize`](::serde::Serialize), [`Deserialize`](::serde::Deserialize),
//! and [`DeserializeOwned`](::serde::de::DeserializeOwned) are all exposed.
//! Because of some path quirks with re-exported proc-macros, all derived values need to be tagged
Expand All @@ -74,23 +74,23 @@
//! ```
//!
//! # Date and Time
//!
//!
//! Date and time is handled by exposing the [`time`](::time) crate.
//! For _duration_, [`humantime`](::humantime) is used, exposing its `Duration` directly. This is
//! done for duration parsing similar to what is experienced in unix tools.
//!
//!
//! # Number formatting
//!
//!
//! [`numfmt::Formatter`] is exposed (as [`NumFmt`](prelude::NumFmt)) which can be used
//! to format numbers in a nice way. The `numfmt` module documentation describes ways to
//! build a formatter, along with the syntax for parsing a format string.
//!
//!
//! # Progress reporting
//!
//!
//! [`how-u-doin`](::howudoin) can be used to show progress of a longer running script.
//!
//!
//! # Tabular printing
//!
//!
//! Tables can be printed neatly with [`TablePrinter`](prelude::TablePrinter), which is just
//! exposing [`comfy-table`](::comfy_table).
#![warn(missing_docs)]
Expand Down Expand Up @@ -122,7 +122,7 @@ pub mod prelude {
pub use super::args::{args, Args};

pub use super::cmd::{
CommandExecute, CommandString, CommandBuilder,
CommandBuilder, CommandExecute, CommandString,
Output::{self, *},
};

Expand All @@ -149,23 +149,23 @@ pub mod prelude {
// publically document cargs! and cmd! here

/// Construct a `[String]` array from a list of arguments.
///
///
/// This macro is primarily for use with [`cmd!`](cmd), but can also be independently
/// used, a great location is [`Command::args`](std::process::Command::args).
///
///
/// Arguments are delimited by commas, any text between delimiters is stringified and
/// passed through.
/// Arguments wrapped in braces (`{ ... }`) are treated as expressions to be evaluated.
/// This effectively writes `{ ... }.to_string()`.
///
///
/// ```plaintext
/// arg1, arg2/foo, {expr}
/// ```
///
///
/// # Example
/// ```rust
/// # use rust_script_ext::prelude::*;
///
///
/// let x = "hello";
/// let c = cargs!(foo, bar/zog, {x}, {1 + 2});
/// assert_eq!(c, [
Expand All @@ -178,47 +178,47 @@ pub mod prelude {
pub use ::macros::cargs;

/// Helper to construct a [`Command`] with arguments.
///
///
/// The macro uses the syntax:
/// ```plaintext
/// cmd: arg1, arg2
/// ```
///
///
/// That is, the command path, optionally followed by a colon (`:`) followed by one or
/// more _comma delimited_ arguments.
///
///
/// Note that `cmd!` defers to [`cargs!`](cargs) to parse the arguments.
///
///
/// The macro is powerful enough to support raw path identifiers:
/// ```rust
/// # use rust_script_ext::prelude::*;
/// let c = cmd!(ls); // no args
/// assert_eq!(&c.cmd_str(), "ls");
///
///
/// let c = cmd!(ls: foo/bar, zog);
/// assert_eq!(&c.cmd_str(), "ls foo/bar zog");
///
///
/// let c = cmd!(./local-script.sh: foo/bar, zog);
/// assert_eq!(&c.cmd_str(), "./local-script.sh foo/bar zog");
/// ```
///
///
/// Literals are supported:
/// ```rust
/// # use rust_script_ext::prelude::*;
/// let c = cmd!(ls: "foo bar", 1.23);
/// assert_eq!(&c.cmd_str(), r#"ls "foo bar" 1.23"#);
/// ```
///
///
/// Arguments wrapped in braces (`{ ... }`) are treated as expressions to be evaluated.
/// This effectively writes `{ ... }.to_string()`.
///
///
/// ```rust
/// # use rust_script_ext::prelude::*;
/// let h = "hello";
/// let c = cmd!(ls: {h}, {format!("world")});
/// assert_eq!(&c.cmd_str(), "ls hello world");
/// ```
///
///
/// [`Command`]: std::process::Command
pub use ::macros::cmd;
}
Expand Down

0 comments on commit 4fe5b85

Please sign in to comment.