To get started it's recommended to install the Rust toolchain using rustup. If you've already installed rustup before, you can update with
rustup updateTo aid in the editing and navigating of Rust code, install rust-analyzer in your development environment of choice. I highly recommend turning on your editor's format-on-save feature to keep the code properly formatted.
Next, you'll want to install the build and runtime dependencies. On Debian-based systems, this looks something like
sudo apt update && sudo apt install -y build-essential perlNote: Although development could technically be done without this setup by using docker compose build, I don't recommend this as the main development loop as the Docker build is much slower than building locally.
To compile the server, enter the server/ directory and run
cargo buildIf you would just like to check if the server compiles, you can run
cargo checkThis is much faster than building, as it skips the expensive code generation step of compilation. Finally, to run, run
cargo runNote that by default, these commands operate on the debug profile, which adds extra checks and symbols useful for debugging. However, debug is usually 10-100x slower than release builds. If you would like to compile the release profile, you can add the --release flag can be added to any of these commands.
The server-side code has a number of unit tests, most of which require a connection to the database. Make sure the PostgreSQL server is up and ready to make connections before running tests.
To run all server unit tests, run
cargo testSome tests take a few minutes to run in debug, so you may wish to add --release to speed things up. By default, the test runner hides any console output during tests. You can opt out of this behavior with the following flag:
cargo test -- --nocaptureYou can also run a subset of tests using
cargo test test_filterwhere only tests with test_filter in their name or namespace will be run. You can learn about additional test options here.
If there are any test failures, make sure to start your investigation at the first test failure. Some test failures can cause other failures due to database consistency issues.
After a series of changes to the code, it's good practice to run Rust's static analysis tool, clippy, to help catch subtle bugs and style issues. You can do this by running
cargo clippy --all-targetsIf a warning is particularly oppressive or unhelpful, it can be disabled locally with #[allow(clippy::warning_name)] above the offending line or globally with #![allow(clippy::warning_name)].
Sometimes it is necessary to make modifications to the database schema. To accomplish this, you must add a migration to the oxibooru/server/migrations/ directory. These migrations consist of a up.sql that makes the modification and a down.sql that reverts the modification.
Diesel uses the schema.rs file to keep track of the current state of the database in order to make compile-time checks on constructed queries. However, this is not automatically updated when a migration is added. DO NOT update schema.rs manually. Instead, use the Diesel CLI to run the new migration and generate a new schema.rs.
If you haven't already, install the Diesel CLI. Once you've down this, navigate to the server directory and run
diesel migration run --database-url='postgres://POSTGRES_USER:POSTGRES_PASSWORD@localhost:POSTGRES_PORT/POSTGRES_DB'where POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_PORT, and POSTGRES_DB are the values of the environment variables defined in .env.
Each migration is run inside a transaction and will be reverted automatically if an error is encountered. After a migration is applied successfully, it's good practice to make sure that it is reversible. To do this, run
diesel migration redo --database-url='postgres://POSTGRES_USER:POSTGRES_PASSWORD@localhost:POSTGRES_PORT/POSTGRES_DB'which applies the down.sql and then up.sql again.