From 520489ab48577143c4b300e8890e4685661e8826 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Mon, 23 Mar 2026 03:30:12 +0300 Subject: [PATCH] docs: finalize hacking guidelines Signed-off-by: NotAShelf Change-Id: I2d3a5a9d745630f5da305664f0bdc66e6a6a6964 --- docs/HACKING.md | 278 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 261 insertions(+), 17 deletions(-) diff --git a/docs/HACKING.md b/docs/HACKING.md index 5f5bafb..28eb21c 100644 --- a/docs/HACKING.md +++ b/docs/HACKING.md @@ -1,11 +1,12 @@ # Hacking Pinakes -Pinakes is a lot of things. One of the things it aims to be is _complete_. To be -complete in features, to be complete in documentation and to be complete in -hackability. This document covers, very comprehensively, how you may: +Pinakes is a lot of things. It also _plans_ to be a lot of things. One of those +things, as you might have noticed, is _complete_. To be complete in features, to +be complete in documentation and to be complete in hackability. This document +covers, very comprehensively, how you may: -- Build Pinakes - Develop Pinakes +- Build Pinakes - Contribute to Pinakes for developers as well as: @@ -14,19 +15,262 @@ for developers as well as: for Pinakes maintainers and packagers. -## Building Pinakes - -Pinakes is built with Rust (nightly edition) and various crates. The most -_notable_ crate among those is Dioxus, which provides its own toolkit. The UI -for Pinakes is usually _not_ built with the Dioxus CLI but instead with -`cargo build`. This also applies to distributable build results. +## Development Environment +[Nix]: https://nixos.org [Direnv]: https://direnv.net -To build Pinakes, simply pick the components you want and build them with -`cargo build --release --package `. A Nix shell is provided for -reproducible developer environments and you may obtain all build dependencies by -simply running `nix develop` or `direnv allow` if you use [Direnv]. Nix is a -cross-platform build tool and works on most Linux distributions as well as -Darwin. While distro-specific package managers _might_ work, Nix is the only -supported one. +Pinakes uses [Nix] with flakes for pure, reproducible developer environments. +All of the build dependencies that you need, from Rust to GTK and webkit, are +provided in the devshell. In addition to _not_ requiring system libraries, we'd +like to _actively discourage you_ from relying on system libraries. + +[Direnv] may be preferred by some users as an alternative to `nix develop`. + +```bash +# Enter the dev shell +$ nix develop + +# Or with direnv (recommended) +$ direnv allow +``` + +Nix is the only supported way to get all dependencies. Distro package managers +_may_ work for the core crates but are not supported for the UI. + +## Building Pinakes + +Pinakes is a Cargo workspace with multiple crates targeting multiple aspects of +the projects. The user-facing crates are provided in `packages/*`. +`pinakes-server` and `pinakes-tui` can be built normally with `cargo` while the +UI crate, i.e., `pinakes-ui` **must** be built with the Dioxus CLI (`dx`) so +that the SCSS stylesheets are compiled correctly. Everything else should work +perfectly fine with the standard `cargo build`. + +[Just]: https://just.systems + +To make the things a _little_ bit more convenient, this project uses [Just] as +its command runner and provides a few recipes for common tasks. + +```bash +# Build all crates (server + TUI + UI) +$ just build-all + +# Build individual components +$ just build-server # pinakes-server (HTTP API) +$ just build-tui # pinakes-tui (terminal UI) +$ just build-ui # pinakes-ui (Dioxus desktop/web UI, requires dx) +``` + +The dependencies required for the recipes, including Just itself, is provided by +the Nix devshell. You may also run the cargo equivalents of those commands: + +```bash +# Core crates +$ cargo build -p pinakes-server +$ cargo build -p pinakes-tui + +# The UI crate must be built with dx, not cargo. +$ dx build -p pinakes-ui +``` + +Release builds follow the same pattern, but with `--release`. Nothing else +should be required for the most part. + +## Running Pinakes + +For the time being, UI clients require the server to be running before they can +function. Offline sync is planned, but likely come later alongside cross-device +sync. All UIs connect to the server over HTTP. + +```bash +# 1. Copy and edit the example config (first time only) +$ cp pinakes.example.toml pinakes.toml + +# 2. Start the server (defaults to 127.0.0.1:3000) +$ cargo run -p pinakes-server -- pinakes.toml + +# 3a. Run the TUI client +$ cargo run -p pinakes-tui + +# 3b. Run the desktop/web UI +$ cargo run -p pinakes-ui + +# Connect TUI to a non-default server address +$ cargo run -p pinakes-tui -- --server http://localhost:3000 +``` + +The GUI reads `PINAKES_SERVER_URL` if set; otherwise it assumes +`http://127.0.0.1:3000`. You may change the host and port if you require. + +## Testing + +[cargo-nextest]: https://nexte.st + +Pinakes boasts, or well, attempts to boast a very comprehensive testing suite to +ensure no regressions are introduced while in development. For fast parallel +test execution, we use [cargo-nextest] and while you are recommended to use it +over `cargo test` both should be supported. For CI and package tests, only +`cargo-nextest` is supported. + +```bash +# Run all workspace tests (preferred) +$ just test + +# Equivalent without Just +$ cargo nextest run --workspace + +# Tests for a single crate +$ cargo nextest run -p pinakes-core +$ cargo nextest run -p pinakes-server + +# Run a specific test by name and show output +$ cargo test -p pinakes-core -- test_name --nocapture +``` + +## Linting and Formatting + +### Formatting + +There is a treewide formatter provided within the `flake.nix` that invokes the +recommended formatter tooling across the various filetypes, including database +migrations and Markdown sources. While a `just fmt` recipe is provided, it will +not cover most of the files. Still, you may format the Rust sources as such: + +```bash +# Format all code +$ just fmt # or: cargo fmt + +# Check formatting without modifying files +$ cargo fmt --check +``` + +### Linting + +For now lints only cover Rust sources, and are provided by the Clippy tool. You +may, as usual, invoke it with `just lint`. + +```bash +# Run Clippy +$ just lint # or: cargo clippy --workspace + +# Treat Clippy warnings as errors (used in CI) +$ cargo clippy --workspace -- -D warnings # `-D warnings` is recommended +``` + +All Clippy warnings, besides some of the really annoying ones or false +positives, must be resolved at the source. **Do not** use `#[allow(...)]` or +`#[expect(...)]` to silence warnings unless there is a documented reason. + +It may be okay, at times, to suppress lints but you should focus on _resolving_ +them rather than suppressing them. _If_ suppressing, prefer `#[expect]` and +provide the `reason` parameter. + +## Generating API Documentation + +The REST API documentation is generated from OpenAPI annotations in +`pinakes-server` using `cargo xtask`: + +```bash +# Generate the API documentation at docs/api/ +$ just docs # or: cargo xtask docs +``` + +This writes: + +- `docs/api.md` - Index linking all generated files +- `docs/api/.md` - One Markdown file per API tag +- `docs/api/openapi.json` - Full OpenAPI 3.0 specification + +Please do not edit files under `docs/api/` by hand; they are regenerated on each +run. + +## Code Style + +There are many conventions that are in play within the Pinakes codebase. You'll +get used and adjust to most of them naturally, but here are some of the general +conventions written down for convenience. + +### General + +1. **Make illegal states unrepresentable**; ıse ADTs and newtype wrappers to + encode constraints in the type system. Parse and validate at system + boundaries (user input, external APIs); trust internal types everywhere else. +2. This one is kind of obvious, but please use the `tracing` crate with + structured fields. Do not use `println!` or `eprintln!` in library or server + code. +3. All storage operations must be implemented for both the SQLite and PostgreSQL + backends. Neither backend is optional. + +Naming is kind of obvious, but I'd like to remind you that we use `snake_case` +for functions and variables, `PascalCase` for types and traits, +`SCREAMING_SNAKE_CASE` for constants. There is not much else to it. + +### Error Handling + +- **`unwrap()` and `expect()` are banned** in non-test code. Use `?`, + `ok_or_else`, `match`, or `if let` instead. + - The only accepted exception is when a failure is truly impossible (e.g., a + hardcoded regex that is known-valid at compile time). In that case, add + `#[expect(clippy::expect_used, reason = "...")]` with a clear explanation. +- Wrap storage errors with the `db_ctx` helper so error messages include the + operation and relevant ID: + + ```rust + stmt.execute(params).map_err(db_ctx("insert_media", &media_id))?; + ``` + +### Disallowed Types and APIs + +Pinakes uses hashers from `rustc_hash`, i.e., `FxHashMap` and `FxHashSet` over +the `std` equivalents due to their faster nature without random state. This is +enforced by clippy. + +As Pinakes uses Rust 1.90+, the now-deprecated `once_cell` crate is also banned. +Use the stdlib equivalents: + +- `once_cell::unsync::OnceCell` -> `std::cell::OnceCell` +- `once_cell::sync::OnceCell` -> `std::sync::OnceLock` +- `once_cell::unsync::Lazy` -> `std::cell::LazyCell` +- `once_cell::sync::Lazy` -> `std::sync::LazyLock` + +## Contributing + +1. Fork the repository and create a feature branch. +2. Enter the dev shell: `nix develop` (or `direnv allow`). +3. Make your changes; keep commits focused and descriptive. We use **scoped + commits**. +4. Run `just fmt` and `just lint` before opening a pull request. +5. Run `just test` to verify nothing is broken. +6. Open a pull request against `main`. Describe what you changed and why. + +For significant changes, consider opening an issue first to discuss the +approach. + +## Packaging and Distribution + +Pinakes is released under EUPL v1.2. For distributable release builds, please +respect the license. You may create release builds for the user-facing crates +using `cargo build --release` for server and TUI components. Use `dx` instead +for the GUI: + +```bash +# Server +$ cargo build --release -p pinakes-server + +# TUI +$ cargo build --release -p pinakes-tui + +# GUI +$ dx build --release -p pinakes-ui +``` + +The resulting binaries are self-contained except for system libraries required +by the UI (GTK3, libsoup, webkit2gtk). Database migrations run automatically on +first server startup via the `refinery` crate; no manual migration step is +needed. + +SQLite (the default backend) requires no external database server. PostgreSQL +deployments need the `pg_trgm` extension enabled on the target database. It is +generally advisable to document those requirements for the users, even though +they do not require additional packaging steps.