From `gix-testtools`, where it was originally placed. This also adapts and improves the original description from the commit message that had introduced the subcommand, to make clear when it makes sense to use this (given that operating systems and shells already supply facilities for listing environment variables).
Unified · Split
| @@ -73,6 +73,23 @@ pub enum Subcommands { · 72 unmodified lines | |||
| 73 | /// current repository. Its main use is checking that fixture scripts are have correct modes. | 73 | /// current repository. Its main use is checking that fixture scripts are have correct modes. |
| 74 | #[clap(visible_alias = "cm")] | 74 | #[clap(visible_alias = "cm")] |
| 75 | CheckMode {}, | 75 | CheckMode {}, |
| 76 | /// Print environment variables as `NAME=value` lines. | ||
| 77 | /// | ||
| 78 | /// It is useful to be able to observe environment variables that are set when running code | ||
| 79 | /// with tools such as `cargo` or `cross`. Commands like `cargo run -p internal-tools -- env` | ||
| 80 | /// include environment changes from `cargo` itself. With `cross`, changes are more extensive, | ||
| 81 | /// due to the effect of `build.env.passthrough`, container customization, and existing special | ||
| 82 | /// cases in wrapper scripts shipped in default `cross` containers (such as to `LD_PRELOAD`). | ||
| 83 | /// | ||
| 84 | /// Since one use for checking environment variables is to investigate the effects of | ||
| 85 | /// environments that contain variable names or values that are not valid Unicode, this avoids | ||
| 86 | /// requiring that environment variables all be Unicode. Any name or value that is not Unicode | ||
| 87 | /// is shown in its Rust debug representation. This is always quoted, and to decrease ambiguity | ||
| 88 | /// any name or (more likely) value that contains literal double quotes is likewise shown in | ||
| 89 | /// its debug representation so that it is always clear if a quotation mark is just for | ||
| 90 | /// display. Each name and value is otherwise shown literally. | ||
| 91 | #[clap(visible_alias = "e")] | ||
| 92 | Env {}, | ||
| 76 | } | 93 | } |
| 77 | 94 | ||
| 78 | #[derive(Clone)] | 95 | #[derive(Clone)] |
| @@ -0,0 +1,15 @@ | |||
| 1 | pub(super) mod function { | ||
| 2 | pub fn env() -> anyhow::Result<()> { | ||
| 3 | for (name, value) in std::env::vars_os() { | ||
| 4 | println!("{}={}", repr(&name), repr(&value)); | ||
| 5 | } | ||
| 6 | Ok(()) | ||
| 7 | } | ||
| 8 | |||
| 9 | fn repr(text: &std::ffi::OsStr) -> String { | ||
| 10 | text.to_str() | ||
| 11 | .filter(|s| !s.contains('"')) | ||
| 12 | .map(ToOwned::to_owned) | ||
| 13 | .unwrap_or_else(|| format!("{text:?}")) | ||
| 14 | } | ||
| 15 | } | ||
| @@ -6,3 +6,6 @@ pub use git_to_sh::function::git_to_sh; · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | pub mod check_mode; | 7 | pub mod check_mode; |
| 8 | pub use check_mode::function::check_mode; | 8 | pub use check_mode::function::check_mode; |
| 9 | |||
| 10 | pub mod env; | ||
| 11 | pub use env::function::env; | ||
| @@ -32,6 +32,7 @@ fn main() -> anyhow::Result<()> { · 31 unmodified lines | |||
| 32 | patterns, | 32 | patterns, |
| 33 | } => commands::copy_royal(dry_run, &worktree_root, destination_dir, patterns), | 33 | } => commands::copy_royal(dry_run, &worktree_root, destination_dir, patterns), |
| 34 | Subcommands::CheckMode {} => commands::check_mode(), | 34 | Subcommands::CheckMode {} => commands::check_mode(), |
| 35 | Subcommands::Env {} => commands::env(), | ||
| 35 | } | 36 | } |
| 36 | } | 37 | } |
| 37 | 38 | ||
| @@ -9,19 +9,6 @@ fn bash_program() -> io::Result<()> { · 8 unmodified lines | |||
| 9 | Ok(()) | 9 | Ok(()) |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | fn env() -> io::Result<()> { | ||
| 13 | fn repr(text: &std::ffi::OsStr) -> String { | ||
| 14 | text.to_str() | ||
| 15 | .filter(|s| !s.contains('"')) | ||
| 16 | .map(ToOwned::to_owned) | ||
| 17 | .unwrap_or_else(|| format!("{text:?}")) | ||
| 18 | } | ||
| 19 | for (name, value) in std::env::vars_os() { | ||
| 20 | println!("{}={}", repr(&name), repr(&value)); | ||
| 21 | } | ||
| 22 | Ok(()) | ||
| 23 | } | ||
| 24 | |||
| 25 | fn mess_in_the_middle(path: PathBuf) -> io::Result<()> { | 12 | fn mess_in_the_middle(path: PathBuf) -> io::Result<()> { |
| 26 | let mut file = fs::OpenOptions::new().read(false).write(true).open(path)?; | 13 | let mut file = fs::OpenOptions::new().read(false).write(true).open(path)?; |
| 27 | file.seek(io::SeekFrom::Start(file.metadata()?.len() / 2))?; | 14 | file.seek(io::SeekFrom::Start(file.metadata()?.len() / 2))?; |
| @@ -40,7 +27,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { · 12 unmodified lines | |||
| 40 | let scmd = args.next().expect("sub command"); | 27 | let scmd = args.next().expect("sub command"); |
| 41 | match &*scmd { | 28 | match &*scmd { |
| 42 | "bash-program" | "bp" => bash_program()?, | 29 | "bash-program" | "bp" => bash_program()?, |
| 43 | "env" => env()?, | ||
| 44 | "mess-in-the-middle" => mess_in_the_middle(PathBuf::from(args.next().expect("path to file to mess with")))?, | 30 | "mess-in-the-middle" => mess_in_the_middle(PathBuf::from(args.next().expect("path to file to mess with")))?, |
| 45 | #[cfg(unix)] | 31 | #[cfg(unix)] |
| 46 | "umask" => umask()?, | 32 | "umask" => umask()?, |