diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 94acb21..2672ebe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,20 +5,22 @@ on: branches: [ "main" ] paths: - 'Cargo.toml' - workflow_dispatch: # Allows manual triggering + workflow_dispatch: permissions: contents: write jobs: - release: - name: Release + prepare-release: + name: Prepare release runs-on: ubuntu-latest + outputs: + version: ${{ steps.get-package-info.outputs.version }} + should_release: ${{ steps.check-version.outputs.exists == 'false' }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - name: Get package info from Cargo.toml id: get-package-info @@ -53,18 +55,129 @@ jobs: gh release create "v${version}" \ --title "v${version}" \ - --generate-notes + --generate-notes \ + --draft # Make it draft until binaries are uploaded + + build-and-upload: + needs: prepare-release + if: needs.prepare-release.outputs.should_release == 'true' + name: ${{ matrix.target }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-musl + use-cross: true + - os: ubuntu-latest + target: aarch64-unknown-linux-musl + use-cross: true + - os: macos-13 + target: x86_64-apple-darwin + use-cross: false + - os: macos-latest + target: aarch64-apple-darwin + use-cross: false + - os: windows-latest + target: x86_64-pc-windows-msvc + use-cross: false + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Handle Rust dependencies caching + uses: Swatinem/rust-cache@v2 + with: + key: v1-${{ matrix.target }} + + - name: Build binary + uses: clechasseur/rs-cargo@v2 + with: + command: build + args: --release --target ${{ matrix.target }} + use-cross: ${{ matrix.use-cross }} + + - name: Get binary name from Cargo.toml + shell: bash + run: | + BINARY_NAME=$(grep -m1 '^name' Cargo.toml | cut -d'"' -f2 | cut -d"'" -f2) + echo "BINARY_NAME=$BINARY_NAME" >> $GITHUB_ENV + + - name: Create release archive + shell: bash + run: | + cd target/${{ matrix.target }}/release + VERSION="${{ needs.prepare-release.outputs.version }}" + if [ "${{ runner.os }}" = "Windows" ]; then + ARCHIVE="${{ env.BINARY_NAME }}-v${VERSION}-${{ matrix.target }}.zip" + mv "${{ env.BINARY_NAME }}.exe" "${{ env.BINARY_NAME }}-${{ matrix.target }}.exe" + 7z a "$ARCHIVE" "${{ env.BINARY_NAME }}-${{ matrix.target }}.exe" + else + ARCHIVE="${{ env.BINARY_NAME }}-v${VERSION}-${{ matrix.target }}.tar.gz" + mv "${{ env.BINARY_NAME }}" "${{ env.BINARY_NAME }}-${{ matrix.target }}" + tar -czvf "$ARCHIVE" "${{ env.BINARY_NAME }}-${{ matrix.target }}" + fi + + # Generate checksums + openssl dgst -r -sha256 -out "$ARCHIVE.sha256" "$ARCHIVE" + openssl dgst -r -sha512 -out "$ARCHIVE.sha512" "$ARCHIVE" + + echo "ASSET=$ARCHIVE" >> $GITHUB_ENV + + - name: Verify binary + shell: bash + run: | + cd target/${{ matrix.target }}/release + case "${{ matrix.target }}" in + *windows*) + 7z x -y "$ASSET" + ./${{ env.BINARY_NAME }}-${{ matrix.target }}.exe --version ;; + aarch64*) + echo "Can't test an ARM binary on a AMD64 runner" ;; + *) + tar -xvzf "$ASSET" + ./${{ env.BINARY_NAME }}-${{ matrix.target }} --version ;; + esac + + - name: Upload to release + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ needs.prepare-release.outputs.version }} + files: | + target/${{ matrix.target }}/release/${{ env.ASSET }} + target/${{ matrix.target }}/release/${{ env.ASSET }}.sha256 + target/${{ matrix.target }}/release/${{ env.ASSET }}.sha512 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + publish: + needs: [prepare-release, build-and-upload] + if: needs.prepare-release.outputs.should_release == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 - name: Install Rust toolchain - if: steps.check-version.outputs.exists == 'false' uses: dtolnay/rust-toolchain@stable - name: Rust cache - if: steps.check-version.outputs.exists == 'false' uses: Swatinem/rust-cache@v2 - name: Publish to crates.io - if: steps.check-version.outputs.exists == 'false' env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} run: cargo publish + + - name: Publish release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release edit "v${{ needs.prepare-release.outputs.version }}" --draft=false diff --git a/README.md b/README.md index 2544f28..a23f7d9 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,22 @@ Scooter respects both `.gitignore` and `.ignore` files. You can add capture groups to the search regex and use them in the replacement string: for instance, if you use `(\d) - (\w+)` for the search text and `($2) "$1"` as the replacement, then `9 - foo` would be replaced with `(foo) "9"`. +## Usage + +Run + +```sh +scooter +``` + +in a terminal to launch Scooter. By default the current directory is used to search and replace in, but you can pass in a directory as the first argument to override this behaviour: + +```sh +scooter ../foo/bar` +``` + +You can then enter some text to search with and text to replace matches with, toggle on or off fixed strings, and enter a regex pattern that filenames must match. A more extensive set of keymappings will be shown at the bottom of the window: these vary slightly depending on the screen you're on. + ## Installation ### Cargo @@ -24,6 +40,19 @@ Ensure you have cargo installed (see [here](https://doc.rust-lang.org/cargo/gett cargo install scooter ``` +### Prebuilt binaries + +You can download binaries from the [releases page](https://github.com/thomasschafer/scooter/releases/latest). After downloading, unzip the binary and move it to a directory in your `PATH`. + +- **Linux** + - Intel/AMD: `*-x86_64-unknown-linux-musl.tar.gz` + - ARM64: `*-aarch64-unknown-linux-musl.tar.gz` +- **macOS** + - Apple silicon: `*-aarch64-apple-darwin.tar.gz` + - Intel: `*-x86_64-apple-darwin.tar.gz` +- **Windows** + - `*-x86_64-pc-windows-msvc.zip` + ### Building from source Ensure you have cargo installed (see [here](https://doc.rust-lang.org/cargo/getting-started/installation.html)), then run the following commands: @@ -34,10 +63,6 @@ cd scooter cargo install --path . ``` -## Usage - -Run `scooter` in a terminal to launch Scooter. You can then enter some text to search with and text to replace matches with, toggle on or off fixed strings, and enter a regex pattern that filenames must match. A more extensive set of keymappings will be shown at the bottom of the window: these vary slightly depending on the screen you're on. - ## Contributing Contributions are very welcome! I'd be especially grateful for any contributions to add scooter to popular package managers. If you'd like to add a new feature, please create an issue first so we can discuss the idea, then create a PR with your changes. diff --git a/src/main.rs b/src/main.rs index 1321ee0..7143f66 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,11 @@ use ratatui::{backend::CrosstermBackend, Terminal}; use std::{io, path::PathBuf, str::FromStr}; use tui::Tui; +use crate::{ + app::App, + event::{Event, EventHandler}, +}; + mod app; mod event; mod fields; @@ -11,13 +16,10 @@ mod logging; mod tui; mod ui; mod utils; -use crate::{ - app::App, - event::{Event, EventHandler}, -}; #[derive(Parser, Debug)] #[command(about = "Interactive find and replace TUI.")] +#[command(version)] struct Args { /// Directory in which to search #[arg(index = 1)]