Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
release:
types: [ published ]
workflow_dispatch:

defaults:
run:
shell: bash

env:
CARGO_TERM_COLOR: always

jobs:
test:
name: Test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-15 ]
steps:
- uses: actions/checkout@v4
- if: github.event_name != 'release' && github.event_name != 'workflow_dispatch'
uses: Swatinem/rust-cache@v2
- uses: dtolnay/rust-toolchain@stable
- uses: taiki-e/install-action@v2
with: { tool: just }
- run: just ci-test

test-msrv:
name: Test MSRV
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-15 ]
steps:
- uses: actions/checkout@v4
- if: github.event_name != 'release' && github.event_name != 'workflow_dispatch'
uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with: { tool: just }
- name: Read MSRV
id: msrv
run: echo "value=$(just get-msrv)" >> $GITHUB_OUTPUT
- name: Install MSRV Rust ${{ steps.msrv.outputs.value }}
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ steps.msrv.outputs.value }}
- run: just ci_mode=0 ci-test-msrv # Ignore warnings in MSRV

# This job checks if any of the previous jobs failed or were canceled.
# This approach also allows some jobs to be skipped if they are not needed.
ci-passed:
needs: [ test, test-msrv ]
if: always()
runs-on: ubuntu-latest
steps:
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
run: exit 1
39 changes: 0 additions & 39 deletions .github/workflows/main.yml

This file was deleted.

21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,17 @@ The library is completely safe.

There are no `unsafe` in this library and in most of its dependencies (excluding `bytemuck`).

## Developer documents

For notes on the backporting process of HarfBuzz code, see [docs/backporting.md](docs/backporting.md).

For notes on generating state machine using `ragel`, see [docs/ragel.md](docs/ragel.md).

The following HarfBuzz _studies_ are relevant to HarfRust development:

- 2025 - [Introducing HarfRust][2]
- 2025 – [Caching][1]
## Development

* This project is easier to develop with [just](https://github.com/casey/just#readme), a modern alternative to `make`.
Install it with `cargo install just`.
* To get a list of available commands, run `just`.
* To run tests, use `just test`.
* For notes on the backporting process of HarfBuzz code, see [docs/backporting.md](docs/backporting.md).
* For notes on generating state machine using `ragel`, see [docs/ragel.md](docs/ragel.md).
* The following HarfBuzz _studies_ are relevant to HarfRust development:
- 2025 - [Introducing HarfRust][2]
- 2025 – [Caching][1]

## License

Expand Down
150 changes: 150 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/usr/bin/env just --justfile

main_crate := 'harfrust'
features_flag := '--all-features'

# if running in CI, treat warnings as errors by setting RUSTFLAGS and RUSTDOCFLAGS to '-D warnings' unless they are already set
# Use `CI=true just ci-test` to run the same tests as in GitHub CI.
# Use `just env-info` to see the current values of RUSTFLAGS and RUSTDOCFLAGS
ci_mode := if env('CI', '') != '' {'1'} else {''}
export RUSTFLAGS := env('RUSTFLAGS', if ci_mode == '1' {'-D warnings'} else {''})
export RUSTDOCFLAGS := env('RUSTDOCFLAGS', if ci_mode == '1' {'-D warnings'} else {''})
export RUST_BACKTRACE := env('RUST_BACKTRACE', if ci_mode == '1' {'1'} else {''})

@_default:
{{just_executable()}} --list

# Build the project
build: build-lib build-lib-no-std
cargo build --workspace --all-targets {{features_flag}}

# Build just the core lib
build-lib:
cargo build --lib --package {{main_crate}} {{features_flag}}

# Build just the core lib with no_std
build-lib-no-std:
cargo build --lib --package {{main_crate}} --no-default-features

# Quick compile without building a binary
check:
cargo check --workspace --all-targets {{features_flag}}
cargo check --lib --package {{main_crate}} {{features_flag}}
cargo check --lib --package {{main_crate}} --no-default-features

# Generate code coverage report to upload to codecov.io
ci-coverage: env-info && \
(coverage '--codecov --output-path target/llvm-cov/codecov.info')
# ATTENTION: the full file path above is used in the CI workflow
mkdir -p target/llvm-cov

# Run all tests as expected by CI
ci-test: env-info test-fmt build test test-doc clippy && assert-git-is-clean

# Run minimal subset of tests to ensure compatibility with MSRV
ci-test-msrv: env-info build-lib build-lib-no-std

# Clean all build artifacts
clean:
cargo clean
rm -f Cargo.lock

# Run cargo clippy to lint the code
clippy *args:
cargo clippy --workspace --all-targets {{features_flag}} {{args}}

# Generate code coverage report. Will install `cargo llvm-cov` if missing.
coverage *args='--no-clean --open': (cargo-install 'cargo-llvm-cov')
cargo llvm-cov --workspace --all-targets {{features_flag}} --include-build-script {{args}}

# Build and open code documentation
docs *args='--open':
DOCS_RS=1 cargo doc --no-deps {{args}} --workspace {{features_flag}}

# Print environment info
env-info:
@echo "Running {{if ci_mode == '1' {'in CI mode'} else {'in dev mode'} }} on {{os()}} / {{arch()}}"
{{just_executable()}} --version
rustc --version
cargo --version
rustup --version
@echo "RUSTFLAGS='$RUSTFLAGS'"
@echo "RUSTDOCFLAGS='$RUSTDOCFLAGS'"
@echo "RUST_BACKTRACE='$RUST_BACKTRACE'"

# Reformat all code `cargo fmt`.
fmt:
cargo fmt --all

# Get any package's field from the metadata
get-crate-field field package=main_crate: (assert-cmd 'jq')
cargo metadata --format-version 1 | jq -e -r '.packages | map(select(.name == "{{package}}")) | first | .{{field}} | select(. != null)'

# Get the minimum supported Rust version (MSRV) for the crate
get-msrv package=main_crate: (get-crate-field 'rust_version' package)

# Find the minimum supported Rust version (MSRV) using cargo-msrv extension, and update Cargo.toml
msrv: (cargo-install 'cargo-msrv')
cargo msrv find --write-msrv --ignore-lockfile {{features_flag}}

release *args='': (cargo-install 'release-plz')
release-plz {{args}}

# Check semver compatibility with prior published version. Install it with `cargo install cargo-semver-checks`
semver *args: (cargo-install 'cargo-semver-checks')
cargo semver-checks {{features_flag}} {{args}}

# Run all unit and integration tests
test:
cargo test --workspace --all-targets {{features_flag}}
cargo test --workspace --doc {{features_flag}}

# Test documentation generation
test-doc: (docs '')

# Test code formatting
test-fmt:
cargo fmt --all -- --check

# Find unused dependencies. Install it with `cargo install cargo-udeps`
udeps: (cargo-install 'cargo-udeps')
cargo +nightly udeps --workspace --all-targets {{features_flag}}

# Update all dependencies, including breaking changes. Requires nightly toolchain (install with `rustup install nightly`)
update:
cargo +nightly -Z unstable-options update --breaking
cargo update

# Ensure that a certain command is available
[private]
assert-cmd command:
@if ! type {{command}} > /dev/null; then \
echo "Command '{{command}}' could not be found. Please make sure it has been installed on your computer." ;\
exit 1 ;\
fi

# Make sure the git repo has no uncommitted changes
[private]
assert-git-is-clean:
@if [ -n "$(git status --untracked-files --porcelain)" ]; then \
>&2 echo "ERROR: git repo is no longer clean. Make sure compilation and tests artifacts are in the .gitignore, and no repo files are modified." ;\
>&2 echo "######### git status ##########" ;\
git status ;\
git --no-pager diff ;\
exit 1 ;\
fi

# Check if a certain Cargo command is installed, and install it if needed
[private]
cargo-install $COMMAND $INSTALL_CMD='' *args='':
#!/usr/bin/env bash
set -euo pipefail
if ! command -v $COMMAND > /dev/null; then
if ! command -v cargo-binstall > /dev/null; then
echo "$COMMAND could not be found. Installing it with cargo install ${INSTALL_CMD:-$COMMAND} --locked {{args}}"
cargo install ${INSTALL_CMD:-$COMMAND} --locked {{args}}
else
echo "$COMMAND could not be found. Installing it with cargo binstall ${INSTALL_CMD:-$COMMAND} --locked {{args}}"
cargo binstall ${INSTALL_CMD:-$COMMAND} --locked {{args}}
fi
fi
Loading