From a1e6633fff2319026f433fd2b05166ddc7263e88 Mon Sep 17 00:00:00 2001 From: Ivan Glazunov Date: Wed, 29 Apr 2026 16:55:57 +0300 Subject: [PATCH] ci: add realease workflow --- .github/workflows/ci.yml | 39 +++++++++++ .github/workflows/release.yml | 56 ++++++++++++++++ README.md | 121 +++++++++++++++++++++++++++++++++- src/cli/output.rs | 6 +- 4 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f81c99..974638a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,45 @@ env: CARGO_TERM_COLOR: always jobs: + lint: + name: Lint (fmt + clippy) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + lfs: true + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake libclang-dev clang + + - name: Build and install SuiteSparse:GraphBLAS + run: | + git clone --depth 1 https://github.com/DrTimothyAldenDavis/GraphBLAS.git + cd GraphBLAS + make compact + sudo make install + + - name: Build and install LAGraph + run: | + cd deps/LAGraph + make + sudo make install + + - name: Install Rust toolchain (stable) + run: | + rustup update stable + rustup default stable + rustup component add rustfmt clippy + + - name: cargo fmt + run: cargo fmt --all -- --check + + - name: cargo clippy + run: cargo clippy --all-targets --all-features -- -D warnings + build_and_test: name: Rust project - latest runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c333112 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,56 @@ +name: Release + +on: + push: + tags: + - 'v*.*.*' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + docker: + name: Build & push Docker image + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + lfs: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/README.md b/README.md index 1018d52..bb95c20 100644 --- a/README.md +++ b/README.md @@ -1 +1,120 @@ -# pathrex \ No newline at end of file +# pathrex + +[![CI](https://github.com/SparseLinearAlgebra/pathrex/actions/workflows/ci.yml/badge.svg)](https://github.com/SparseLinearAlgebra/pathrex/actions/workflows/ci.yml) +[![Container](https://img.shields.io/badge/ghcr.io-pathrex-blue?logo=docker)](https://github.com/SparseLinearAlgebra/pathrex/pkgs/container/pathrex) + +**Pathrex** is a Rust library and CLI for evaluating and benchmarking +**Path Queries** over edge-labeled graphs. +## Features + +- **Two RPQ evaluators** out of the box: + - `nfarpq` — runs `LAGraph_RegularPathQuery`. + - `rpqmatrix` — runs `LAGraph_RPQMatrix`. +- **Multiple input formats**: MatrixMarket directories, CSV edge lists, and + RDF (Turtle / N-Triples). +- **SPARQL frontend**: parses `SELECT` queries with a single triple/property-path + pattern. +- **Benchmarking** with [`criterion`](https://crates.io/crates/criterion): + per-query timing, JSON output, checkpoint/resume, optional HTML plots. +- **Reusable Rust library** with backend-agnostic `Graph`, `GraphSource`, + `GraphBuilder`, and generic `Evaluator` traits. + +## Quickstart with Docker + +A pre-built image is published to GitHub Container Registry on every release tag. + +```bash +docker pull ghcr.io/sparselinearalgebra/pathrex:latest +``` + +The image's entrypoint forwards arguments to the `pathrex` binary. + +### Run a query + +Mount a directory containing your graph and queries, then call `query`: + +```bash +DATA= +docker run --rm \ + -v "${DATA}:/data:ro" \ + ghcr.io/sparselinearalgebra/pathrex:latest \ + query \ + --graph /data/my-graph \ + --format mm \ + --queries /data/queries.txt \ + --algo nfarpq \ + --algo rpqmatrix +``` + +### Run a benchmark + +```bash +DATA= +RESULTS= +docker run --rm \ + -v "${DATA}:/data:ro" \ + -v "${RESULTS}:/results" \ + ghcr.io/sparselinearalgebra/pathrex:latest \ + bench \ + --graph /data/my-graph \ + --queries /data/queries.txt \ + --algo nfarpq +``` + +The entrypoint defaults to: + +- `--output /results/bench_results.json` +- `--checkpoint /results/bench_checkpoint.json` +- `--criterion-dir /results/criterion` + +Pass any of those flags explicitly to override. + +## CLI usage + +```text +pathrex [OPTIONS] + +Subcommands: + query Run queries once and report result counts + bench Benchmark RPQ evaluators with criterion +``` + +### Common options + +| Flag | Description | +|---|---| +| `-g`, `--graph ` | Path to the graph (directory for `mm`, file for `csv`/`rdf`). | +| `-f`, `--format ` | Input format. Defaults to `mm`. | +| `-q`, `--queries ` | Queries file (see format below). | +| `-a`, `--algo ` | Algorithm(s). Repeat to run several. | +| `-b`, `--base-iri []` | Optional `BASE ` to prepend to each query. Bare `--base-iri` uses `http://example.org/`. | + +`query` adds `-o, --output ` to write JSON. + +`bench` adds `--output`, `--checkpoint`, `--resume`, `--criterion-dir`, +`--plots`, `--sample-size`, `--warm-up`, `--measurement`. See +`pathrex bench --help` for details. + +### Queries file format + +One query per line: + +```text +, +``` + +The pattern is wrapped into a full SPARQL query at load time: + +- with `--base-iri `: `BASE SELECT * WHERE { . }` +- without: `SELECT * WHERE { . }` + +Example `queries.txt`: + +```text +q1,?x /* ?y +q2,?x (|)+ ?y +``` + +## License + +See [`LICENSE`](LICENSE). diff --git a/src/cli/output.rs b/src/cli/output.rs index 9b568ea..4dbe0a2 100644 --- a/src/cli/output.rs +++ b/src/cli/output.rs @@ -99,8 +99,7 @@ pub struct QueryMetadata { impl QueryOutput { pub fn write_to_file(&self, path: &Path) -> Result<(), std::io::Error> { - let json = serde_json::to_string_pretty(self) - .map_err(std::io::Error::other)?; + let json = serde_json::to_string_pretty(self).map_err(std::io::Error::other)?; fs::write(path, json) } } @@ -128,8 +127,7 @@ pub struct BenchMetadata { impl BenchOutput { pub fn write_to_file(&self, path: &Path) -> Result<(), std::io::Error> { - let json = serde_json::to_string_pretty(self) - .map_err(std::io::Error::other)?; + let json = serde_json::to_string_pretty(self).map_err(std::io::Error::other)?; fs::write(path, json) } }