Skip to content

Commit f0126f9

Browse files
committed
feat(nix) :: add a development shell
Adds an optional dev shell with all of the tools needed to build SQLPage at the same versions the CI uses. If you have nix installed or use NixOS you can now run :: (1) `nix develop` :: assumes the dev shell (2) `nix fmt` :: runs rustfmt, biome, and nixfmt (3) `nix run .#test-rust` (4) `nix run .#test-browser` (5) `nix run .#test-examples` (6) `nix flake check`
1 parent 3a5609e commit f0126f9

4 files changed

Lines changed: 302 additions & 0 deletions

File tree

‎.envrc‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ sqlpage/sqlpage.db
1515
tests_uploads/
1616
/test-results/
1717
/playwright-report/
18+
/result
19+
.direnv/

‎flake.lock‎

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎flake.nix‎

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
{
2+
description = "Optional development environment for SQLPage";
3+
4+
inputs = {
5+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6+
# Ships the official rustup binaries, so the toolchain in this shell is
7+
# the same build CI and the release use, down to the bundled LLVM.
8+
rust-overlay.url = "github:oxalica/rust-overlay";
9+
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
10+
};
11+
12+
outputs =
13+
{
14+
self,
15+
nixpkgs,
16+
rust-overlay,
17+
}:
18+
let
19+
inherit (nixpkgs) lib;
20+
21+
systems = [
22+
"aarch64-darwin"
23+
"aarch64-linux"
24+
"x86_64-linux"
25+
];
26+
27+
# Oracle governs its own client library by licence, so nixpkgs marks it
28+
# unfree. Naming it here keeps every other package in this flake free.
29+
unfreePackages = [ "oracle-instantclient" ];
30+
31+
forEachSystem =
32+
build:
33+
lib.genAttrs systems (
34+
system:
35+
build (
36+
import nixpkgs {
37+
inherit system;
38+
config.allowUnfreePredicate = package: builtins.elem (lib.getName package) unfreePackages;
39+
overlays = [ rust-overlay.overlays.default ];
40+
}
41+
)
42+
);
43+
44+
cargoEdition = (lib.importTOML ./Cargo.toml).package.edition;
45+
46+
lockedPlaywrightVersion =
47+
(lib.importJSON ./package-lock.json).packages."node_modules/playwright-core".version;
48+
49+
formatterFor =
50+
pkgs:
51+
pkgs.treefmt.withConfig {
52+
runtimeInputs = [
53+
pkgs.biome
54+
pkgs.nixfmt
55+
pkgs.rustfmt
56+
];
57+
settings = {
58+
on-unmatched = "info";
59+
formatter = {
60+
nixfmt = {
61+
command = "nixfmt";
62+
includes = [ "*.nix" ];
63+
};
64+
rustfmt = {
65+
command = "rustfmt";
66+
options = [
67+
"--edition"
68+
cargoEdition
69+
];
70+
includes = [ "*.rs" ];
71+
};
72+
biome = {
73+
command = "biome";
74+
options = [
75+
"format"
76+
"--write"
77+
"--no-errors-on-unmatched"
78+
];
79+
includes = [
80+
"*.css"
81+
"*.js"
82+
"*.json"
83+
"*.jsonc"
84+
"*.mjs"
85+
"*.ts"
86+
];
87+
};
88+
};
89+
};
90+
};
91+
92+
rustToolchainFor = pkgs: pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
93+
94+
# odbc-sys links against a driver manager, and the C sources vendored by
95+
# aws-lc-sys, libsqlite3-sys and zstd-sys need a compiler. Nothing here
96+
# reaches for OpenSSL: SQLPage speaks TLS through rustls.
97+
cargoRuntime = pkgs: [
98+
(rustToolchainFor pkgs)
99+
pkgs.stdenv.cc
100+
pkgs.unixodbc
101+
];
102+
# The database matrix runs prebuilt test binaries that link the unixODBC
103+
# driver manager statically. It still reads ODBCSYSINI at run time and
104+
# dlopens whatever absolute path this file names, so pointing that one
105+
# variable at the store replaces every driver install step.
106+
odbcDriversFor =
107+
pkgs:
108+
pkgs.runCommand "sqlpage-odbc-drivers" { } ''
109+
mkdir -p "$out"
110+
oracleDriver=(${lib.getLib pkgs.oracle-instantclient}/lib/libsqora.so.*)
111+
cat > "$out/odbcinst.ini" <<INI
112+
[PostgreSQL Unicode]
113+
Driver = ${pkgs.unixodbcDrivers.psql}/${pkgs.unixodbcDrivers.psql.driver}
114+
115+
[Oracle 21 ODBC driver]
116+
Driver = ''${oracleDriver[0]}
117+
INI
118+
'';
119+
120+
cargoEnv = pkgs: {
121+
LIBRARY_PATH = "${pkgs.unixodbc}/lib";
122+
};
123+
124+
# Playwright is installed via npm, we we need to set the browser paths.
125+
playwrightEnv = pkgs: {
126+
PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
127+
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "1";
128+
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = "true";
129+
};
130+
131+
gatesFor =
132+
pkgs:
133+
lib.mapAttrs
134+
(
135+
name:
136+
{
137+
description,
138+
packages ? [ ],
139+
env ? { },
140+
script,
141+
}:
142+
pkgs.writeShellApplication {
143+
inherit name;
144+
runtimeInputs = [ pkgs.git ] ++ packages;
145+
runtimeEnv = env;
146+
meta = { inherit description; };
147+
text = ''
148+
cd "$(git rev-parse --show-toplevel)"
149+
''
150+
+ script;
151+
}
152+
)
153+
{
154+
lint-rust = {
155+
description = "Check Rust formatting and deny every clippy warning";
156+
packages = cargoRuntime pkgs;
157+
env = cargoEnv pkgs;
158+
script = ''
159+
cargo fmt --all -- --check
160+
cargo clippy --all-targets --all-features -- -D warnings
161+
'';
162+
};
163+
164+
test-rust = {
165+
description = "Run the Rust test suites against DATABASE_URL, or SQLite when it is unset";
166+
packages = cargoRuntime pkgs;
167+
env = cargoEnv pkgs;
168+
script = ''
169+
cargo test "$@"
170+
'';
171+
};
172+
173+
test-browser = {
174+
description = "Drive the components in a browser with Playwright";
175+
packages = [ pkgs.nodejs_26 ] ++ cargoRuntime pkgs;
176+
env = cargoEnv pkgs // playwrightEnv pkgs;
177+
script = ''
178+
npm ci --ignore-scripts
179+
npm run build
180+
cd tests/end-to-end
181+
npx playwright test "$@"
182+
'';
183+
};
184+
185+
test-examples = {
186+
description = "Run the Hurl suite of an example against its own containers";
187+
packages = [ pkgs.hurl ];
188+
script = ''
189+
scripts/test-examples-hurl.sh "$@"
190+
'';
191+
};
192+
};
193+
in
194+
{
195+
packages = forEachSystem (pkgs: {
196+
odbc-drivers = odbcDriversFor pkgs;
197+
});
198+
199+
formatter = forEachSystem formatterFor;
200+
201+
checks = forEachSystem (pkgs: {
202+
formatting = (formatterFor pkgs).check self;
203+
});
204+
205+
apps = forEachSystem (
206+
pkgs:
207+
lib.mapAttrs (_: gate: {
208+
type = "app";
209+
program = lib.getExe gate;
210+
inherit (gate) meta;
211+
}) (gatesFor pkgs)
212+
);
213+
214+
devShells = forEachSystem (
215+
pkgs:
216+
assert lib.assertMsg (lockedPlaywrightVersion == pkgs.playwright-driver.version)
217+
"package-lock.json pins Playwright ${lockedPlaywrightVersion}, but nixpkgs ships ${pkgs.playwright-driver.version}. Playwright only drives the browsers its own release shipped with, so run `nix flake update` or realign package-lock.json.";
218+
{
219+
default = pkgs.mkShell {
220+
name = "sqlpage";
221+
222+
packages =
223+
(with pkgs; [
224+
biome
225+
hurl
226+
nodejs_26
227+
pkg-config
228+
sqlite
229+
])
230+
++ cargoRuntime pkgs
231+
++ [ (formatterFor pkgs) ]
232+
++ lib.attrValues (gatesFor pkgs);
233+
234+
buildInputs = with pkgs; [
235+
unixodbc
236+
zstd
237+
];
238+
239+
# DATABASE_URL and LISTEN_ON stay unset on purpose. SQLPage reads
240+
# both from the environment, so exporting them here would override
241+
# every example and test fixture that ships its own configuration.
242+
env = {
243+
RUST_SRC_PATH = "${rustToolchainFor pkgs}/lib/rustlib/src/rust/library";
244+
ZSTD_SYS_USE_PKG_CONFIG = "1";
245+
}
246+
// playwrightEnv pkgs;
247+
};
248+
}
249+
);
250+
};
251+
}

0 commit comments

Comments
 (0)