diff --git a/Cargo.lock b/Cargo.lock index 7932134b53..681afe1ed7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -366,6 +366,15 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -580,6 +589,7 @@ dependencies = [ "pretty_assertions", "pretty_env_logger", "regex", + "shellexpand", "update-informer", ] @@ -1605,6 +1615,15 @@ dependencies = [ "digest", ] +[[package]] +name = "shellexpand" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +dependencies = [ + "dirs", +] + [[package]] name = "siphasher" version = "0.3.10" diff --git a/git-cliff/Cargo.toml b/git-cliff/Cargo.toml index 11f036bd7a..060a1c4d1b 100644 --- a/git-cliff/Cargo.toml +++ b/git-cliff/Cargo.toml @@ -33,6 +33,7 @@ pretty_env_logger = "0.5.0" dirs-next = "2.0.0" clap_complete = "4.4.1" clap_mangen = "0.2.13" +shellexpand = "3.1.0" [dependencies.git-cliff-core] version = "1.3.0" # managed by release.sh diff --git a/git-cliff/src/args.rs b/git-cliff/src/args.rs index 1558102bbc..f534bffdf3 100644 --- a/git-cliff/src/args.rs +++ b/git-cliff/src/args.rs @@ -63,10 +63,23 @@ pub struct Opt { #[arg(short, long, action = ArgAction::Count, alias = "debug", help_heading = Some("FLAGS"))] pub verbose: u8, /// Sets the configuration file. - #[arg(short, long, env = "GIT_CLIFF_CONFIG", value_name = "PATH", default_value = DEFAULT_CONFIG)] + #[arg( + short, + long, + env = "GIT_CLIFF_CONFIG", + value_name = "PATH", + default_value = DEFAULT_CONFIG, + value_parser = Opt::parse_dir + )] pub config: PathBuf, /// Sets the working directory. - #[arg(short, long, env = "GIT_CLIFF_WORKDIR", value_name = "PATH")] + #[arg( + short, + long, + env = "GIT_CLIFF_WORKDIR", + value_name = "PATH", + value_parser = Opt::parse_dir + )] pub workdir: Option, /// Sets the git repository. #[arg( @@ -74,7 +87,8 @@ pub struct Opt { long, env = "GIT_CLIFF_REPOSITORY", value_name = "PATH", - num_args(1..) + num_args(1..), + value_parser = Opt::parse_dir )] pub repository: Option>, /// Sets the path to include related commits. @@ -102,10 +116,22 @@ pub struct Opt { )] pub with_commit: Option>, /// Prepends entries to the given changelog file. - #[arg(short, long, env = "GIT_CLIFF_PREPEND", value_name = "PATH")] + #[arg( + short, + long, + env = "GIT_CLIFF_PREPEND", + value_name = "PATH", + value_parser = Opt::parse_dir + )] pub prepend: Option, /// Writes output to the given file. - #[arg(short, long, env = "GIT_CLIFF_OUTPUT", value_name = "PATH")] + #[arg( + short, + long, + env = "GIT_CLIFF_OUTPUT", + value_name = "PATH", + value_parser = Opt::parse_dir + )] pub output: Option, /// Sets the tag for the latest version. #[arg( @@ -158,6 +184,18 @@ pub struct Opt { pub range: Option, } +impl Opt { + /// Custom string parser for directories. + /// + /// Expands the tilde (`~`) character in the beginning of the + /// input string into contents of the path returned by [`home_dir`]. + /// + /// [`home_dir`]: dirs_next::home_dir + fn parse_dir(dir: &str) -> Result { + Ok(PathBuf::from(shellexpand::tilde(dir).to_string())) + } +} + #[cfg(test)] mod tests { use super::*; @@ -167,4 +205,12 @@ mod tests { fn verify_cli() { Opt::command().debug_assert() } + + #[test] + fn path_tilde_expansion() { + let home_dir = + dirs_next::home_dir().expect("cannot retrieve home directory"); + let dir = Opt::parse_dir("~/").expect("cannot expand tilde"); + assert_eq!(home_dir, dir); + } }