diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..830816a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Force LF-only for all test files to avoid Windows breakage +test-cases/** text eol=lf diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 72070e6..cca0a25 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,10 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] + defaults: + run: + shell: bash steps: - name: Checkout uses: actions/checkout@v6 @@ -47,12 +50,25 @@ jobs: cd rust cargo build --release --all-targets - - name: Package binaries + - name: Package binaries (Unix-like) + if: runner.os != 'Windows' run: | mkdir -p release cp rust/target/release/{limabean,limabean-pod} release/ tar czvf limabean-${{ matrix.os }}.tar.gz -C release . + - name: Package binaries (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + mkdir -p release + $bins = @( + "rust\target\release\limabean.exe", + "rust\target\release\limabean-pod.exe" + ) + Copy-Item $bins release\ + Compress-Archive -Path release\* -DestinationPath limabean-${{ matrix.os }}.zip + - name: Upload Rust binaries uses: actions/upload-artifact@v6 with: diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 2ca7d7a..3663776 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -31,7 +31,10 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] + defaults: + run: + shell: bash steps: - name: Checkout uses: actions/checkout@v6 diff --git a/rust/src/bin/limabean/run.rs b/rust/src/bin/limabean/run.rs index 1b5eea9..e6096da 100644 --- a/rust/src/bin/limabean/run.rs +++ b/rust/src/bin/limabean/run.rs @@ -112,6 +112,37 @@ fn run_or_fail(mut cmd: Command) { std::process::exit(1); } +#[cfg(windows)] +fn run_or_fail(mut cmd: Command) { + let cmd = cmd + .stdin(std::process::Stdio::inherit()) + .stdout(std::process::Stdio::inherit()) + .stderr(std::process::Stdio::inherit()); + + match cmd.spawn() { + Ok(mut child) => { + let exit_status = child + .wait() + .unwrap_or_else(|e| panic!("limabean unexpected wait failure: {}", e)); + + // any error message is already written on stderr, so we're done + // TODO improve error path here, early exit is nasty + if !exit_status.success() { + std::process::exit(exit_status.code().unwrap_or(1)); + } + } + + Err(e) => { + eprintln!( + "limabean can't run {}: {}", + cmd.get_program().to_string_lossy(), + &e + ); + std::process::exit(1); + } + } +} + pub(crate) fn run(runtime: &Runtime, args: &[String]) { let verbose = args.iter().any(|arg| arg == "-v" || arg == "--verbose"); let version = args.iter().any(|arg| arg == "--version");