ratio-matrix 0.6.0

Ratio's matrix data library.
Documentation
# This justfile contains jobs for a mixed Rust/Python project, but can be used for sole Rust
# projects as well, as forwarding commands check whether HAS_PYTHON is set to a value to determine
# whether the Python build, test, lint, etc. jobs must be run in conjunction with their Rust
# counterparts, which are always run.
# Version 2025-05-12

set dotenv-load
set export

# Whether this project has Python bindings.
HAS_PYTHON := env("HAS_PYTHON", "")

# Shorthand for the justfile directory.
HERE := env("HERE", justfile_directory())

# Container image to use when running commands in a dev container.
IMAGE := env("IMAGE", "registry.gitlab.com/ratio-case-os/docker/rust-ci")
# The tag. Switch to "cross" for cross compilation.
TAG := env("TAG", if HAS_PYTHON == "" { "latest" } else { "cross" })
# Compilation targets if required.
# TARGETS := env("TARGETS", "x86_64-unknown-linux-gnu x86_64-pc-windows-msvc aarch64-unknown-linux-gnu aarch64-pc-windows-msvc")
TARGETS := env("TARGETS", "x86_64-unknown-linux-gnu x86_64-apple-darwin x86_64-pc-windows-msvc aarch64-unknown-linux-gnu aarch64-apple-darwin aarch64-pc-windows-msvc")

# Optional Rust crate to target within a workspace.
CRATE := env("CRATE", "")

# String of flame scripts (space separated) to run and calculate flamegraphs for.
FLAMES := env("FLAMES", "")
# Flamegraph output directory.
FLAMES_DIR := env("FLAMES_DIR", HERE + "/target/flames")

# The Python crate name.
PYTHON_CRATE := env("PYTHON_CRATE", CRATE + "-py")
# The directory containing the Python bindings crate.
PYTHON_DIR := env("PYTHON_DIR", HERE / PYTHON_CRATE)
# The Python wheels output directory.
WHEELS_DIR := env("WHEELS_DIR", HERE + "/target/wheels")

# Show the recipe list.
default:
  @just --list --justfile {{justfile()}}

# Clean generated project files.
clean:
  cargo clean
  rm ./ratio-graph-py/python/**/*.so

# Pull the dev container image from the registry.
pull-container:
  podman pull {{IMAGE}}:{{TAG}}

# Run a dev container with the project directory mounted.
run-container args="" cmd="bash":
  podman run --userns=keep-id --rm -it -v {{HERE}}:/home/ratio/work:z {{args}} {{IMAGE}}:{{TAG}} {{cmd}}

# Run a recipe in a dev container.
in-container recipe="":
  podman run --userns=keep-id --rm -it -v {{HERE}}:/home/ratio/work:z {{IMAGE}}:{{TAG}} just {{recipe}}

@install:
  if [[ -n "{{HAS_PYTHON}}" ]]; then just install-py; fi

# Install the Python bindings environment.
install-py *args:
  cd {{PYTHON_DIR}} && \
  uv lock && \
  uv sync --all-extras --all-groups && \
  uvx maturin develop --uv && \
  uv run python -m maturin_import_hook site install

# Build package in release mode.
@build: build-rs
  if [[ -n "{{HAS_PYTHON}}" ]]; then just build-py; fi

# Build Rust crate(s) for all available targets.
build-rs:
  cargo build --release --all-targets --color always {{ if CRATE != "" { "-p " + CRATE } else { "" } }}

# Build Python bindings for all set targets.
build-py *args:
  rm -rf {{WHEELS_DIR}}
  cd {{PYTHON_DIR}} && for i in {{TARGETS}}; do uvx maturin[zig] build --zig --release --target "$i" {{args}}; done

# Create flamegraph of certain scripts for performance measurement.
flamegraph *args:
  #!/bin/bash
  mkdir -p {{FLAMES_DIR}}
  for i in {{FLAMES}}; \
  do CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -o "{{FLAMES_DIR}}/$i.svg" --no-inline --unit-test -- "$i" --color always {{args}} || true; \
  done
  rm -f perf.data
  rm -f perf.data.old
alias flame := flamegraph

# Lint both the Rust code, license usage, and Python bindings.
@lint: lint-rs lint-deny
  if [[ -n "{{HAS_PYTHON}}" ]]; then just lint-py; fi

# Lint the Rust code.
lint-rs *args:
  cargo clippy --all-targets --color always {{ if CRATE != "" { "-p " + CRATE } else { "" } }} {{args}}
  cargo +nightly fmt --check

# Lint the Python bindings if any.
lint-py *args:
  uvx ruff check {{PYTHON_DIR}} {{args}}

# Lint project dependencies and licenses
lint-deny:
  cargo deny check

# Fix the Rust code and Python bindings if any.
@fix: fix-rs
  if [[ -n "{{HAS_PYTHON}}" ]]; then just fix-py; fi

# Fix the Rust code.
fix-rs *args:
  cargo clippy --all-targets --fix --allow-dirty --allow-staged --color always {{args}}
  cargo +nightly fmt --all

# Fix the Python bindings if any.
fix-py *args:
  uvx ruff format {{PYTHON_DIR}} {{args}}

# Run a single test cycle for the project.
@test: test-rs-coverage
  if [[ -n "{{HAS_PYTHON}}" ]]; then just test-py; fi

# Run Rust code tests.
test-rs *args:
  cargo test {{ if CRATE != "" { "-p " + CRATE } else { "" } }} {{args}}

# Run the Python bindings tests.
test-py *args:
  cd {{PYTHON_DIR}} && uv run pytest {{args}}

# Run Rust tests with coverage.
test-rs-coverage *args:
  cargo tarpaulin --tests --doc --color always --locked --out Xml --output-dir target/tarpaulin {{ if CRATE != "" { "-p " + CRATE } else { "" } }} {{args}}

# Run Rust tests in watch mode, or the Python suite if the bindings are enabled.
@watch *args:
  if [[ -n "{{HAS_PYTHON}}" ]]; then just watch-py; else just watch-rs; fi

# Run Rust tests continuously.
watch-rs *args:
  bacon -j test {{ if CRATE != "" { "-p " + CRATE } else { "" } }} {{args}}

# Run Python bindings test continuously.
watch-py *args:
  bacon -j pytest {{args}}

# Build and publish both the Rust crate(s) as well as the Python bindings.
@publish: publish-rs
 if [[ -n "{{HAS_PYTHON}}" ]]; then just publish-py; fi

# Build and publish the Rust crate.
publish-rs *args: build-rs
  cargo publish --color always {{ if CRATE != "" { "-p " + CRATE } else { "" } }} {{args}}

# Build and publish the Python bindings.
publish-py *args:
  uv publish {{args}} {{WHEELS_DIR}}/*

# Check for outdated packages.
outdated: outdated-rs

# Check for outdated packages for the Rust code.
outdated-rs *args:
  cargo outdated --color always {{ if CRATE != "" { "-p " + CRATE } else { "" } }} {{args}}

# Upgrade all dependencies.
@upgrade: upgrade-rs
  if [[ -n "{{HAS_PYTHON}}" ]]; then just update-py; fi

# Upgrade Rust crate dependencies.
upgrade-rs *args:
  cargo upgrade {{ if CRATE != "" { "-p " + CRATE } else { "" } }} {{args}}

# Update Python lockfile.
update-py *args:
  cd {{PYTHON_DIR}} && uv lock

# Update this justfile to the latest version.
update-justfile:
  wget https://gitlab.com/ratio-case-os/justfiles/-/raw/main/justfiles/rust-ci.justfile -O "{{justfile()}}"