docs: finalize hacking guidelines
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I2d3a5a9d745630f5da305664f0bdc66e6a6a6964
This commit is contained in:
parent
273d0244aa
commit
520489ab48
1 changed files with 260 additions and 16 deletions
278
docs/HACKING.md
278
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 <component>`. 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/<tag>.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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue