From 4d692b0c1fd6ec4abc06118db76ed776a9f690f3 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Oct 2025 14:46:30 +0200 Subject: [PATCH] Use `OsStr::as_encoded_bytes` This should allow for better cross-platform support, esp. for Windows. --- .github/workflows/build.yml | 28 +++++++++++++++++++++++++--- README.md | 2 +- src/lib.rs | 10 ++-------- tests/test_bash.rs | 4 ---- tests/test_fish.rs | 5 ----- tests/test_sh.rs | 4 ---- tests/test_ux.rs | 2 +- 7 files changed, 29 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 47d6145..10cc147 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,16 +8,27 @@ on: jobs: test: name: Test - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable # Make sure we have all the target shells installed. - - run: sudo apt-get install -y bash dash fish zsh + - name: Install shells (Ubuntu) + if: runner.os == 'Linux' + run: sudo apt-get install -y bash dash fish zsh + - name: Install shells (Windows) + if: runner.os == 'Windows' + run: | + choco install git -y --no-progress + choco install fish -y --no-progress # Record shell versions. Almost unbelievably, it's not possible to get the # version of Dash from `dash` itself, so we skip it here. Since `sh` might # be `dash`, we also do not try to get its version. - - name: Shell versions + - name: Shell versions (Ubuntu) + if: runner.os == 'Linux' run: | for shell in sh dash; do for path in $(type -ap "$shell"); do @@ -30,6 +41,17 @@ jobs: printf "%10s @ %-30q: %s\n" "$shell" "$path" "$version" done done + - name: Shell versions (Windows) + if: runner.os == 'Windows' + shell: bash + run: | + for shell in bash fish; do + if command -v "$shell" &> /dev/null; then + path=$(command -v "$shell") + version=$("$shell" --version | head -n 1) + printf "%10s @ %-30s: %s\n" "$shell" "$path" "$version" + fi + done # Test in debug mode first. - run: cargo test # Test in release mode too, to defend against, for example, use of diff --git a/README.md b/README.md index 6025cc5..e5ef50e 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ It can take as input many different string and byte string types: - [`&str`] and [`String`] - [`&bstr::BStr`][`bstr::BStr`] and [`bstr::BString`] - [`&[u8]`][`slice`] and [`Vec`] -- [`&OsStr`][`OsStr`] and [`OsString`] (on UNIX) +- [`&OsStr`][`OsStr`] and [`OsString`] - [`&Path`][`Path`] and [`PathBuf`] and produce output as (or push into) the following types: diff --git a/src/lib.rs b/src/lib.rs index a1504ec..dc084a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -176,19 +176,15 @@ impl<'a> From<&'a String> for Quotable<'a> { } } -#[cfg(unix)] impl<'a> From<&'a OsStr> for Quotable<'a> { fn from(source: &'a OsStr) -> Quotable<'a> { - use std::os::unix::ffi::OsStrExt; - source.as_bytes().into() + source.as_encoded_bytes().into() } } -#[cfg(unix)] impl<'a> From<&'a OsString> for Quotable<'a> { fn from(source: &'a OsString) -> Quotable<'a> { - use std::os::unix::ffi::OsStrExt; - source.as_bytes().into() + source.as_encoded_bytes().into() } } @@ -208,14 +204,12 @@ impl<'a> From<&'a bstr::BString> for Quotable<'a> { } } -#[cfg(unix)] impl<'a> From<&'a Path> for Quotable<'a> { fn from(source: &'a Path) -> Quotable<'a> { source.as_os_str().into() } } -#[cfg(unix)] impl<'a> From<&'a PathBuf> for Quotable<'a> { fn from(source: &'a PathBuf) -> Quotable<'a> { source.as_os_str().into() diff --git a/tests/test_bash.rs b/tests/test_bash.rs index f1f00f5..71cc849 100644 --- a/tests/test_bash.rs +++ b/tests/test_bash.rs @@ -81,7 +81,6 @@ mod bash_impl { assert_eq!(buffer, b"$'-_=/,.+'"); } - #[cfg(unix)] #[test_matrix( (script_bytes, script_text), ("bash", "zsh") @@ -96,7 +95,6 @@ mod bash_impl { } } - #[cfg(unix)] fn script_bytes() -> (OsString, OsString) { use std::os::unix::ffi::{OsStrExt, OsStringExt}; // It doesn't seem possible to roundtrip NUL, probably because it is the @@ -113,7 +111,6 @@ mod bash_impl { (input, script) } - #[cfg(unix)] fn script_text() -> (OsString, OsString) { use std::os::unix::ffi::OsStringExt; // NOTE: Do NOT use `echo` here; in most/all shells it interprets @@ -127,7 +124,6 @@ mod bash_impl { (resources::UTF8_SAMPLE.into(), script) } - #[cfg(unix)] #[test_matrix(("bash", "zsh"))] fn test_roundtrip_utf8_full(shell: &str) { use std::os::unix::ffi::OsStringExt; diff --git a/tests/test_fish.rs b/tests/test_fish.rs index 4c0e027..3d925f6 100644 --- a/tests/test_fish.rs +++ b/tests/test_fish.rs @@ -128,7 +128,6 @@ mod fish_impl { assert_eq!(buffer, b"-_'=/,.+'"); } - #[cfg(unix)] #[test_matrix((script_bytes, script_text))] fn test_roundtrip(prepare: fn() -> (OsString, OsString)) { use std::os::unix::ffi::OsStringExt; @@ -141,7 +140,6 @@ mod fish_impl { } } - #[cfg(unix)] fn script_bytes() -> (OsString, OsString) { use std::os::unix::ffi::{OsStrExt, OsStringExt}; // It doesn't seem possible to roundtrip NUL, probably because it is the @@ -155,7 +153,6 @@ mod fish_impl { (input, script) } - #[cfg(unix)] fn script_text() -> (OsString, OsString) { use std::os::unix::ffi::OsStringExt; // Unlike many/most other shells, `echo` is safe here because backslash @@ -166,7 +163,6 @@ mod fish_impl { (resources::UTF8_SAMPLE.into(), script) } - #[cfg(unix)] #[test] fn test_roundtrip_utf8_full() { use std::os::unix::ffi::OsStringExt; @@ -190,7 +186,6 @@ mod fish_impl { } } - #[cfg(unix)] #[test] /// IIRC, this caught bugs not found by `test_roundtrip_utf8_full`, and it /// was much easier to figure out what the failures meant. For now it stays! diff --git a/tests/test_sh.rs b/tests/test_sh.rs index 424f190..1855dbf 100644 --- a/tests/test_sh.rs +++ b/tests/test_sh.rs @@ -105,7 +105,6 @@ mod sh_impl { type InvokeShell = fn(&Path, &OsStr) -> Result; - #[cfg(unix)] #[test_matrix( (script_bytes, script_text), @@ -126,7 +125,6 @@ mod sh_impl { } } - #[cfg(unix)] fn script_bytes() -> (OsString, OsString) { use std::os::unix::ffi::{OsStrExt, OsStringExt}; // It doesn't seem possible to roundtrip NUL, probably because it is the @@ -143,7 +141,6 @@ mod sh_impl { (input, script) } - #[cfg(unix)] fn script_text() -> (OsString, OsString) { use std::os::unix::ffi::OsStringExt; // NOTE: Do NOT use `echo` here; in most/all shells it interprets @@ -158,7 +155,6 @@ mod sh_impl { (input, script) } - #[cfg(unix)] #[test_matrix( (("sh", invoke_shell), ("dash", invoke_shell), diff --git a/tests/test_ux.rs b/tests/test_ux.rs index 646fed6..c2f290d 100644 --- a/tests/test_ux.rs +++ b/tests/test_ux.rs @@ -1,4 +1,4 @@ -#![cfg(all(unix, feature = "bash", feature = "bstr"))] +#![cfg(all(any(unix, windows), feature = "bash", feature = "bstr"))] use bstr::{BString, ByteSlice}; use std::{ffi::OsString, os::unix::ffi::OsStringExt};