diff --git a/.envrc b/.envrc new file mode 100755 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index e53db2d3..6d8dd1f1 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,7 @@ developerID_application.cer sqlpage.key sqlpage.p12 sqlpage_cert.pem + +# Nix build result and direnv cache +/result +.direnv/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9ffaf4eb..2b91b510 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,6 +19,20 @@ Default builds require a system ODBC driver manager. On Linux and macOS, be installed separately. Windows uses its system ODBC driver manager. Published crates include browser assets and do not require Node.js. +### Optional: Nix dev shell + +If you have [Nix](https://nixos.org/download/) with flakes enabled, `nix develop` provides the tools above at the versions CI uses. With [direnv](https://direnv.net/), `direnv allow` enters the shell automatically when you enter the directory. + +| Command | What it runs | +| --- | --- | +| `nix fmt` | rustfmt, Biome, and nixfmt | +| `nix flake check` | formatting, plus the flake's own version assertions | +| `nix run .#lint-rust` | `cargo fmt --check` and `cargo clippy` | +| `nix run .#test-rust` | the Rust test suites | +| `nix run .#test-browser` | the Playwright suites | +| `nix run .#test-examples` | one example's Hurl suite | +| `nix build .#odbc-drivers` | an `odbcinst.ini`; point `ODBCSYSINI` at it for the ODBC tests | + ## Validation For Rust changes: diff --git a/flake.lock b/flake.lock new file mode 100755 index 00000000..1cdfb70f --- /dev/null +++ b/flake.lock @@ -0,0 +1,48 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1790046670, + "narHash": "sha256-MYiI+CzL0tuWgRPjGsKCDHqYs2T3OzMlMQWOYWG0qso=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6774f7bc253789b113a4f39285dc0fa100abeacc", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1790149037, + "narHash": "sha256-01WcSplVEmQt13QUZLfWez27JO+2lyYWX+yTitvkF3g=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "fb058ecf6d14837ea152a3d5225ce7f88ee5cde1", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..def67e21 --- /dev/null +++ b/flake.nix @@ -0,0 +1,251 @@ +{ + description = "Optional development environment for SQLPage"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # Ships the official rustup binaries, so the toolchain in this shell is + # the same build CI and the release use, down to the bundled LLVM. + rust-overlay.url = "github:oxalica/rust-overlay"; + rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = + { + self, + nixpkgs, + rust-overlay, + }: + let + inherit (nixpkgs) lib; + + systems = [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-linux" + ]; + + # Oracle governs its own client library by licence, so nixpkgs marks it + # unfree. Naming it here keeps every other package in this flake free. + unfreePackages = [ "oracle-instantclient" ]; + + forEachSystem = + build: + lib.genAttrs systems ( + system: + build ( + import nixpkgs { + inherit system; + config.allowUnfreePredicate = package: builtins.elem (lib.getName package) unfreePackages; + overlays = [ rust-overlay.overlays.default ]; + } + ) + ); + + cargoEdition = (lib.importTOML ./Cargo.toml).package.edition; + + lockedPlaywrightVersion = + (lib.importJSON ./package-lock.json).packages."node_modules/playwright-core".version; + + formatterFor = + pkgs: + pkgs.treefmt.withConfig { + runtimeInputs = [ + pkgs.biome + pkgs.nixfmt + pkgs.rustfmt + ]; + settings = { + on-unmatched = "info"; + formatter = { + nixfmt = { + command = "nixfmt"; + includes = [ "*.nix" ]; + }; + rustfmt = { + command = "rustfmt"; + options = [ + "--edition" + cargoEdition + ]; + includes = [ "*.rs" ]; + }; + biome = { + command = "biome"; + options = [ + "format" + "--write" + "--no-errors-on-unmatched" + ]; + includes = [ + "*.css" + "*.js" + "*.json" + "*.jsonc" + "*.mjs" + "*.ts" + ]; + }; + }; + }; + }; + + rustToolchainFor = pkgs: pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + + # odbc-sys links against a driver manager, and the C sources vendored by + # aws-lc-sys, libsqlite3-sys and zstd-sys need a compiler. Nothing here + # reaches for OpenSSL: SQLPage speaks TLS through rustls. + cargoRuntime = pkgs: [ + (rustToolchainFor pkgs) + pkgs.stdenv.cc + pkgs.unixodbc + ]; + # The database matrix runs prebuilt test binaries that link the unixODBC + # driver manager statically. It still reads ODBCSYSINI at run time and + # dlopens whatever absolute path this file names, so pointing that one + # variable at the store replaces every driver install step. + odbcDriversFor = + pkgs: + pkgs.runCommand "sqlpage-odbc-drivers" { } '' + mkdir -p "$out" + oracleDriver=(${lib.getLib pkgs.oracle-instantclient}/lib/libsqora.so.*) + cat > "$out/odbcinst.ini" <