├── .envrc ├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── evaluator ├── Cargo.toml ├── find-drvs-from-previous-commit.sh └── src │ ├── lib.rs │ ├── main.rs │ └── pull_request.rs ├── flake.lock ├── flake.nix ├── server ├── .gitignore ├── Cargo.toml ├── diesel.toml ├── migrations │ ├── .gitkeep │ └── 2021-01-28-042303_create_projects │ │ ├── down.sql │ │ └── up.sql └── src │ ├── build_manager.rs │ ├── cli.rs │ ├── github_producer.rs │ ├── main.rs │ └── models.rs ├── shared ├── Cargo.toml └── src │ ├── db.rs │ ├── db │ ├── models.rs │ └── sql │ │ ├── down.sql │ │ └── up.sql │ ├── error.rs │ ├── eval_events.rs │ ├── github.rs │ ├── github │ ├── pull_request.rs │ └── repo_events.rs │ ├── lib.rs │ ├── outpaths.nix │ └── types.rs ├── shell.nix ├── web └── elm │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── elm.json │ ├── package.json │ ├── src │ ├── Main.elm │ ├── index.html │ ├── index.js │ └── styles.scss │ ├── tests │ └── Example.elm │ └── webpack.config.js └── worker ├── Cargo.toml └── src └── main.rs /.envrc: -------------------------------------------------------------------------------- 1 | watch_file flake.nix 2 | watch_file flake.lock 3 | mkdir -p "$(direnv_layout_dir)" 4 | eval "$(nix print-dev-env --profile "$(direnv_layout_dir)/flake-profile")" 5 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | run: DATABASE_URL="sqlite::memory:" cargo build --verbose 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .direnv/ 2 | .idea 3 | .vscode 4 | *.db* 5 | 6 | # Added by cargo 7 | 8 | debug/ 9 | /target 10 | result* 11 | 12 | **/*.rs.bk 13 | 14 | # Compiled source # 15 | ################### 16 | *.com 17 | *.class 18 | *.dll 19 | *.exe 20 | *.o 21 | *.so 22 | 23 | # Packages # 24 | ############ 25 | *.7z 26 | *.dmg 27 | *.gz 28 | *.iso 29 | *.jar 30 | *.rar 31 | *.tar 32 | *.zip 33 | 34 | # Logs and databases # 35 | ###################### 36 | *.log 37 | *.sql 38 | *.sqlite 39 | 40 | # OS generated files # 41 | ###################### 42 | .DS_Store 43 | .DS_Store? 44 | ._* 45 | .Spotlight-V100 46 | .Trashes 47 | ehthumbs.db 48 | Thumbs.db 49 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "once_cell", 28 | "version_check", 29 | "zerocopy", 30 | ] 31 | 32 | [[package]] 33 | name = "aho-corasick" 34 | version = "1.1.3" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 37 | dependencies = [ 38 | "memchr", 39 | ] 40 | 41 | [[package]] 42 | name = "allocator-api2" 43 | version = "0.2.18" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 46 | 47 | [[package]] 48 | name = "android-tzdata" 49 | version = "0.1.1" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 52 | 53 | [[package]] 54 | name = "android_system_properties" 55 | version = "0.1.5" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 58 | dependencies = [ 59 | "libc", 60 | ] 61 | 62 | [[package]] 63 | name = "ansi_term" 64 | version = "0.12.1" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 67 | dependencies = [ 68 | "winapi", 69 | ] 70 | 71 | [[package]] 72 | name = "atoi" 73 | version = "2.0.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" 76 | dependencies = [ 77 | "num-traits", 78 | ] 79 | 80 | [[package]] 81 | name = "atty" 82 | version = "0.2.14" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 85 | dependencies = [ 86 | "hermit-abi 0.1.19", 87 | "libc", 88 | "winapi", 89 | ] 90 | 91 | [[package]] 92 | name = "autocfg" 93 | version = "1.4.0" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 96 | 97 | [[package]] 98 | name = "backtrace" 99 | version = "0.3.74" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 102 | dependencies = [ 103 | "addr2line", 104 | "cfg-if", 105 | "libc", 106 | "miniz_oxide", 107 | "object", 108 | "rustc-demangle", 109 | "windows-targets 0.52.6", 110 | ] 111 | 112 | [[package]] 113 | name = "base64" 114 | version = "0.21.7" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 117 | 118 | [[package]] 119 | name = "base64" 120 | version = "0.22.1" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 123 | 124 | [[package]] 125 | name = "base64ct" 126 | version = "1.6.0" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 129 | 130 | [[package]] 131 | name = "basinix-server" 132 | version = "0.1.0" 133 | dependencies = [ 134 | "basinix_evaluator", 135 | "basinix_shared", 136 | "chrono", 137 | "clap", 138 | "env_logger", 139 | "log", 140 | "reqwest", 141 | "serde", 142 | "serde_json", 143 | "tokio", 144 | "toml", 145 | "warp", 146 | ] 147 | 148 | [[package]] 149 | name = "basinix_evaluator" 150 | version = "0.1.0" 151 | dependencies = [ 152 | "basinix_shared", 153 | "bincode", 154 | "chrono", 155 | "env_logger", 156 | "log", 157 | "reqwest", 158 | "serde", 159 | "serde_json", 160 | "tokio", 161 | ] 162 | 163 | [[package]] 164 | name = "basinix_shared" 165 | version = "0.1.0" 166 | dependencies = [ 167 | "bincode", 168 | "derive_more", 169 | "dirs", 170 | "lazy_static", 171 | "log", 172 | "reqwest", 173 | "serde", 174 | "serde_json", 175 | "sqlx", 176 | ] 177 | 178 | [[package]] 179 | name = "basinix_worker" 180 | version = "0.1.0" 181 | 182 | [[package]] 183 | name = "bincode" 184 | version = "1.3.3" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 187 | dependencies = [ 188 | "serde", 189 | ] 190 | 191 | [[package]] 192 | name = "bitflags" 193 | version = "1.3.2" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 196 | 197 | [[package]] 198 | name = "bitflags" 199 | version = "2.6.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 202 | dependencies = [ 203 | "serde", 204 | ] 205 | 206 | [[package]] 207 | name = "block-buffer" 208 | version = "0.10.4" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 211 | dependencies = [ 212 | "generic-array", 213 | ] 214 | 215 | [[package]] 216 | name = "bumpalo" 217 | version = "3.16.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 220 | 221 | [[package]] 222 | name = "byteorder" 223 | version = "1.5.0" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 226 | 227 | [[package]] 228 | name = "bytes" 229 | version = "1.7.2" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" 232 | 233 | [[package]] 234 | name = "cc" 235 | version = "1.1.28" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" 238 | dependencies = [ 239 | "shlex", 240 | ] 241 | 242 | [[package]] 243 | name = "cfg-if" 244 | version = "1.0.0" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 247 | 248 | [[package]] 249 | name = "chrono" 250 | version = "0.4.38" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 253 | dependencies = [ 254 | "android-tzdata", 255 | "iana-time-zone", 256 | "js-sys", 257 | "num-traits", 258 | "wasm-bindgen", 259 | "windows-targets 0.52.6", 260 | ] 261 | 262 | [[package]] 263 | name = "clap" 264 | version = "2.34.0" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 267 | dependencies = [ 268 | "ansi_term", 269 | "atty", 270 | "bitflags 1.3.2", 271 | "strsim", 272 | "textwrap", 273 | "unicode-width", 274 | "vec_map", 275 | ] 276 | 277 | [[package]] 278 | name = "concurrent-queue" 279 | version = "2.5.0" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 282 | dependencies = [ 283 | "crossbeam-utils", 284 | ] 285 | 286 | [[package]] 287 | name = "const-oid" 288 | version = "0.9.6" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 291 | 292 | [[package]] 293 | name = "convert_case" 294 | version = "0.4.0" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 297 | 298 | [[package]] 299 | name = "core-foundation" 300 | version = "0.9.4" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 303 | dependencies = [ 304 | "core-foundation-sys", 305 | "libc", 306 | ] 307 | 308 | [[package]] 309 | name = "core-foundation-sys" 310 | version = "0.8.7" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 313 | 314 | [[package]] 315 | name = "cpufeatures" 316 | version = "0.2.14" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" 319 | dependencies = [ 320 | "libc", 321 | ] 322 | 323 | [[package]] 324 | name = "crc" 325 | version = "3.2.1" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" 328 | dependencies = [ 329 | "crc-catalog", 330 | ] 331 | 332 | [[package]] 333 | name = "crc-catalog" 334 | version = "2.4.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 337 | 338 | [[package]] 339 | name = "crossbeam-queue" 340 | version = "0.3.11" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" 343 | dependencies = [ 344 | "crossbeam-utils", 345 | ] 346 | 347 | [[package]] 348 | name = "crossbeam-utils" 349 | version = "0.8.20" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 352 | 353 | [[package]] 354 | name = "crypto-common" 355 | version = "0.1.6" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 358 | dependencies = [ 359 | "generic-array", 360 | "typenum", 361 | ] 362 | 363 | [[package]] 364 | name = "data-encoding" 365 | version = "2.6.0" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" 368 | 369 | [[package]] 370 | name = "der" 371 | version = "0.7.9" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" 374 | dependencies = [ 375 | "const-oid", 376 | "pem-rfc7468", 377 | "zeroize", 378 | ] 379 | 380 | [[package]] 381 | name = "derive_more" 382 | version = "0.99.18" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" 385 | dependencies = [ 386 | "convert_case", 387 | "proc-macro2", 388 | "quote", 389 | "rustc_version", 390 | "syn", 391 | ] 392 | 393 | [[package]] 394 | name = "digest" 395 | version = "0.10.7" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 398 | dependencies = [ 399 | "block-buffer", 400 | "const-oid", 401 | "crypto-common", 402 | "subtle", 403 | ] 404 | 405 | [[package]] 406 | name = "dirs" 407 | version = "3.0.2" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" 410 | dependencies = [ 411 | "dirs-sys", 412 | ] 413 | 414 | [[package]] 415 | name = "dirs-sys" 416 | version = "0.3.7" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 419 | dependencies = [ 420 | "libc", 421 | "redox_users", 422 | "winapi", 423 | ] 424 | 425 | [[package]] 426 | name = "dotenvy" 427 | version = "0.15.7" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 430 | 431 | [[package]] 432 | name = "either" 433 | version = "1.13.0" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 436 | dependencies = [ 437 | "serde", 438 | ] 439 | 440 | [[package]] 441 | name = "encoding_rs" 442 | version = "0.8.34" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 445 | dependencies = [ 446 | "cfg-if", 447 | ] 448 | 449 | [[package]] 450 | name = "env_logger" 451 | version = "0.8.4" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" 454 | dependencies = [ 455 | "atty", 456 | "humantime", 457 | "log", 458 | "regex", 459 | "termcolor", 460 | ] 461 | 462 | [[package]] 463 | name = "equivalent" 464 | version = "1.0.1" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 467 | 468 | [[package]] 469 | name = "errno" 470 | version = "0.3.9" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 473 | dependencies = [ 474 | "libc", 475 | "windows-sys 0.52.0", 476 | ] 477 | 478 | [[package]] 479 | name = "etcetera" 480 | version = "0.8.0" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" 483 | dependencies = [ 484 | "cfg-if", 485 | "home", 486 | "windows-sys 0.48.0", 487 | ] 488 | 489 | [[package]] 490 | name = "event-listener" 491 | version = "5.3.1" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" 494 | dependencies = [ 495 | "concurrent-queue", 496 | "parking", 497 | "pin-project-lite", 498 | ] 499 | 500 | [[package]] 501 | name = "fastrand" 502 | version = "2.1.1" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" 505 | 506 | [[package]] 507 | name = "flume" 508 | version = "0.11.0" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" 511 | dependencies = [ 512 | "futures-core", 513 | "futures-sink", 514 | "spin", 515 | ] 516 | 517 | [[package]] 518 | name = "fnv" 519 | version = "1.0.7" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 522 | 523 | [[package]] 524 | name = "foreign-types" 525 | version = "0.3.2" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 528 | dependencies = [ 529 | "foreign-types-shared", 530 | ] 531 | 532 | [[package]] 533 | name = "foreign-types-shared" 534 | version = "0.1.1" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 537 | 538 | [[package]] 539 | name = "form_urlencoded" 540 | version = "1.2.1" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 543 | dependencies = [ 544 | "percent-encoding", 545 | ] 546 | 547 | [[package]] 548 | name = "futures-channel" 549 | version = "0.3.31" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 552 | dependencies = [ 553 | "futures-core", 554 | "futures-sink", 555 | ] 556 | 557 | [[package]] 558 | name = "futures-core" 559 | version = "0.3.31" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 562 | 563 | [[package]] 564 | name = "futures-executor" 565 | version = "0.3.31" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 568 | dependencies = [ 569 | "futures-core", 570 | "futures-task", 571 | "futures-util", 572 | ] 573 | 574 | [[package]] 575 | name = "futures-intrusive" 576 | version = "0.5.0" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" 579 | dependencies = [ 580 | "futures-core", 581 | "lock_api", 582 | "parking_lot", 583 | ] 584 | 585 | [[package]] 586 | name = "futures-io" 587 | version = "0.3.31" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 590 | 591 | [[package]] 592 | name = "futures-sink" 593 | version = "0.3.31" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 596 | 597 | [[package]] 598 | name = "futures-task" 599 | version = "0.3.31" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 602 | 603 | [[package]] 604 | name = "futures-util" 605 | version = "0.3.31" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 608 | dependencies = [ 609 | "futures-core", 610 | "futures-io", 611 | "futures-sink", 612 | "futures-task", 613 | "memchr", 614 | "pin-project-lite", 615 | "pin-utils", 616 | "slab", 617 | ] 618 | 619 | [[package]] 620 | name = "generic-array" 621 | version = "0.14.7" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 624 | dependencies = [ 625 | "typenum", 626 | "version_check", 627 | ] 628 | 629 | [[package]] 630 | name = "getrandom" 631 | version = "0.2.15" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 634 | dependencies = [ 635 | "cfg-if", 636 | "libc", 637 | "wasi", 638 | ] 639 | 640 | [[package]] 641 | name = "gimli" 642 | version = "0.31.1" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 645 | 646 | [[package]] 647 | name = "h2" 648 | version = "0.3.26" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 651 | dependencies = [ 652 | "bytes", 653 | "fnv", 654 | "futures-core", 655 | "futures-sink", 656 | "futures-util", 657 | "http 0.2.12", 658 | "indexmap", 659 | "slab", 660 | "tokio", 661 | "tokio-util", 662 | "tracing", 663 | ] 664 | 665 | [[package]] 666 | name = "hashbrown" 667 | version = "0.14.5" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 670 | dependencies = [ 671 | "ahash", 672 | "allocator-api2", 673 | ] 674 | 675 | [[package]] 676 | name = "hashbrown" 677 | version = "0.15.0" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" 680 | 681 | [[package]] 682 | name = "hashlink" 683 | version = "0.9.1" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" 686 | dependencies = [ 687 | "hashbrown 0.14.5", 688 | ] 689 | 690 | [[package]] 691 | name = "headers" 692 | version = "0.3.9" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" 695 | dependencies = [ 696 | "base64 0.21.7", 697 | "bytes", 698 | "headers-core", 699 | "http 0.2.12", 700 | "httpdate", 701 | "mime", 702 | "sha1", 703 | ] 704 | 705 | [[package]] 706 | name = "headers-core" 707 | version = "0.2.0" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" 710 | dependencies = [ 711 | "http 0.2.12", 712 | ] 713 | 714 | [[package]] 715 | name = "heck" 716 | version = "0.5.0" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 719 | 720 | [[package]] 721 | name = "hermit-abi" 722 | version = "0.1.19" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 725 | dependencies = [ 726 | "libc", 727 | ] 728 | 729 | [[package]] 730 | name = "hermit-abi" 731 | version = "0.3.9" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 734 | 735 | [[package]] 736 | name = "hex" 737 | version = "0.4.3" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 740 | 741 | [[package]] 742 | name = "hkdf" 743 | version = "0.12.4" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" 746 | dependencies = [ 747 | "hmac", 748 | ] 749 | 750 | [[package]] 751 | name = "hmac" 752 | version = "0.12.1" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 755 | dependencies = [ 756 | "digest", 757 | ] 758 | 759 | [[package]] 760 | name = "home" 761 | version = "0.5.9" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 764 | dependencies = [ 765 | "windows-sys 0.52.0", 766 | ] 767 | 768 | [[package]] 769 | name = "http" 770 | version = "0.2.12" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 773 | dependencies = [ 774 | "bytes", 775 | "fnv", 776 | "itoa", 777 | ] 778 | 779 | [[package]] 780 | name = "http" 781 | version = "1.1.0" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 784 | dependencies = [ 785 | "bytes", 786 | "fnv", 787 | "itoa", 788 | ] 789 | 790 | [[package]] 791 | name = "http-body" 792 | version = "0.4.6" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 795 | dependencies = [ 796 | "bytes", 797 | "http 0.2.12", 798 | "pin-project-lite", 799 | ] 800 | 801 | [[package]] 802 | name = "httparse" 803 | version = "1.9.5" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 806 | 807 | [[package]] 808 | name = "httpdate" 809 | version = "1.0.3" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 812 | 813 | [[package]] 814 | name = "humantime" 815 | version = "2.1.0" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 818 | 819 | [[package]] 820 | name = "hyper" 821 | version = "0.14.30" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" 824 | dependencies = [ 825 | "bytes", 826 | "futures-channel", 827 | "futures-core", 828 | "futures-util", 829 | "h2", 830 | "http 0.2.12", 831 | "http-body", 832 | "httparse", 833 | "httpdate", 834 | "itoa", 835 | "pin-project-lite", 836 | "socket2", 837 | "tokio", 838 | "tower-service", 839 | "tracing", 840 | "want", 841 | ] 842 | 843 | [[package]] 844 | name = "hyper-tls" 845 | version = "0.5.0" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 848 | dependencies = [ 849 | "bytes", 850 | "hyper", 851 | "native-tls", 852 | "tokio", 853 | "tokio-native-tls", 854 | ] 855 | 856 | [[package]] 857 | name = "iana-time-zone" 858 | version = "0.1.61" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 861 | dependencies = [ 862 | "android_system_properties", 863 | "core-foundation-sys", 864 | "iana-time-zone-haiku", 865 | "js-sys", 866 | "wasm-bindgen", 867 | "windows-core", 868 | ] 869 | 870 | [[package]] 871 | name = "iana-time-zone-haiku" 872 | version = "0.1.2" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 875 | dependencies = [ 876 | "cc", 877 | ] 878 | 879 | [[package]] 880 | name = "idna" 881 | version = "0.5.0" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 884 | dependencies = [ 885 | "unicode-bidi", 886 | "unicode-normalization", 887 | ] 888 | 889 | [[package]] 890 | name = "indexmap" 891 | version = "2.6.0" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 894 | dependencies = [ 895 | "equivalent", 896 | "hashbrown 0.15.0", 897 | ] 898 | 899 | [[package]] 900 | name = "ipnet" 901 | version = "2.10.1" 902 | source = "registry+https://github.com/rust-lang/crates.io-index" 903 | checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" 904 | 905 | [[package]] 906 | name = "itoa" 907 | version = "1.0.11" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 910 | 911 | [[package]] 912 | name = "js-sys" 913 | version = "0.3.70" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" 916 | dependencies = [ 917 | "wasm-bindgen", 918 | ] 919 | 920 | [[package]] 921 | name = "lazy_static" 922 | version = "1.5.0" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 925 | dependencies = [ 926 | "spin", 927 | ] 928 | 929 | [[package]] 930 | name = "libc" 931 | version = "0.2.159" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" 934 | 935 | [[package]] 936 | name = "libm" 937 | version = "0.2.8" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" 940 | 941 | [[package]] 942 | name = "libredox" 943 | version = "0.1.3" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 946 | dependencies = [ 947 | "bitflags 2.6.0", 948 | "libc", 949 | ] 950 | 951 | [[package]] 952 | name = "libsqlite3-sys" 953 | version = "0.30.1" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" 956 | dependencies = [ 957 | "cc", 958 | "pkg-config", 959 | "vcpkg", 960 | ] 961 | 962 | [[package]] 963 | name = "linux-raw-sys" 964 | version = "0.4.14" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 967 | 968 | [[package]] 969 | name = "lock_api" 970 | version = "0.4.12" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 973 | dependencies = [ 974 | "autocfg", 975 | "scopeguard", 976 | ] 977 | 978 | [[package]] 979 | name = "log" 980 | version = "0.4.22" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 983 | 984 | [[package]] 985 | name = "md-5" 986 | version = "0.10.6" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" 989 | dependencies = [ 990 | "cfg-if", 991 | "digest", 992 | ] 993 | 994 | [[package]] 995 | name = "memchr" 996 | version = "2.7.4" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 999 | 1000 | [[package]] 1001 | name = "mime" 1002 | version = "0.3.17" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1005 | 1006 | [[package]] 1007 | name = "mime_guess" 1008 | version = "2.0.5" 1009 | source = "registry+https://github.com/rust-lang/crates.io-index" 1010 | checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" 1011 | dependencies = [ 1012 | "mime", 1013 | "unicase", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "minimal-lexical" 1018 | version = "0.2.1" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 1021 | 1022 | [[package]] 1023 | name = "miniz_oxide" 1024 | version = "0.8.0" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 1027 | dependencies = [ 1028 | "adler2", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "mio" 1033 | version = "1.0.2" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" 1036 | dependencies = [ 1037 | "hermit-abi 0.3.9", 1038 | "libc", 1039 | "wasi", 1040 | "windows-sys 0.52.0", 1041 | ] 1042 | 1043 | [[package]] 1044 | name = "multer" 1045 | version = "2.1.0" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" 1048 | dependencies = [ 1049 | "bytes", 1050 | "encoding_rs", 1051 | "futures-util", 1052 | "http 0.2.12", 1053 | "httparse", 1054 | "log", 1055 | "memchr", 1056 | "mime", 1057 | "spin", 1058 | "version_check", 1059 | ] 1060 | 1061 | [[package]] 1062 | name = "native-tls" 1063 | version = "0.2.12" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 1066 | dependencies = [ 1067 | "libc", 1068 | "log", 1069 | "openssl", 1070 | "openssl-probe", 1071 | "openssl-sys", 1072 | "schannel", 1073 | "security-framework", 1074 | "security-framework-sys", 1075 | "tempfile", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "nom" 1080 | version = "7.1.3" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 1083 | dependencies = [ 1084 | "memchr", 1085 | "minimal-lexical", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "num-bigint-dig" 1090 | version = "0.8.4" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" 1093 | dependencies = [ 1094 | "byteorder", 1095 | "lazy_static", 1096 | "libm", 1097 | "num-integer", 1098 | "num-iter", 1099 | "num-traits", 1100 | "rand", 1101 | "smallvec", 1102 | "zeroize", 1103 | ] 1104 | 1105 | [[package]] 1106 | name = "num-integer" 1107 | version = "0.1.46" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1110 | dependencies = [ 1111 | "num-traits", 1112 | ] 1113 | 1114 | [[package]] 1115 | name = "num-iter" 1116 | version = "0.1.45" 1117 | source = "registry+https://github.com/rust-lang/crates.io-index" 1118 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 1119 | dependencies = [ 1120 | "autocfg", 1121 | "num-integer", 1122 | "num-traits", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "num-traits" 1127 | version = "0.2.19" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1130 | dependencies = [ 1131 | "autocfg", 1132 | "libm", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "object" 1137 | version = "0.36.5" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 1140 | dependencies = [ 1141 | "memchr", 1142 | ] 1143 | 1144 | [[package]] 1145 | name = "once_cell" 1146 | version = "1.20.2" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 1149 | 1150 | [[package]] 1151 | name = "openssl" 1152 | version = "0.10.66" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" 1155 | dependencies = [ 1156 | "bitflags 2.6.0", 1157 | "cfg-if", 1158 | "foreign-types", 1159 | "libc", 1160 | "once_cell", 1161 | "openssl-macros", 1162 | "openssl-sys", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "openssl-macros" 1167 | version = "0.1.1" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1170 | dependencies = [ 1171 | "proc-macro2", 1172 | "quote", 1173 | "syn", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "openssl-probe" 1178 | version = "0.1.5" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1181 | 1182 | [[package]] 1183 | name = "openssl-sys" 1184 | version = "0.9.103" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" 1187 | dependencies = [ 1188 | "cc", 1189 | "libc", 1190 | "pkg-config", 1191 | "vcpkg", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "parking" 1196 | version = "2.2.1" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 1199 | 1200 | [[package]] 1201 | name = "parking_lot" 1202 | version = "0.12.3" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1205 | dependencies = [ 1206 | "lock_api", 1207 | "parking_lot_core", 1208 | ] 1209 | 1210 | [[package]] 1211 | name = "parking_lot_core" 1212 | version = "0.9.10" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1215 | dependencies = [ 1216 | "cfg-if", 1217 | "libc", 1218 | "redox_syscall", 1219 | "smallvec", 1220 | "windows-targets 0.52.6", 1221 | ] 1222 | 1223 | [[package]] 1224 | name = "paste" 1225 | version = "1.0.15" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1228 | 1229 | [[package]] 1230 | name = "pem-rfc7468" 1231 | version = "0.7.0" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" 1234 | dependencies = [ 1235 | "base64ct", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "percent-encoding" 1240 | version = "2.3.1" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1243 | 1244 | [[package]] 1245 | name = "pin-project" 1246 | version = "1.1.6" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" 1249 | dependencies = [ 1250 | "pin-project-internal", 1251 | ] 1252 | 1253 | [[package]] 1254 | name = "pin-project-internal" 1255 | version = "1.1.6" 1256 | source = "registry+https://github.com/rust-lang/crates.io-index" 1257 | checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" 1258 | dependencies = [ 1259 | "proc-macro2", 1260 | "quote", 1261 | "syn", 1262 | ] 1263 | 1264 | [[package]] 1265 | name = "pin-project-lite" 1266 | version = "0.2.14" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 1269 | 1270 | [[package]] 1271 | name = "pin-utils" 1272 | version = "0.1.0" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1275 | 1276 | [[package]] 1277 | name = "pkcs1" 1278 | version = "0.7.5" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" 1281 | dependencies = [ 1282 | "der", 1283 | "pkcs8", 1284 | "spki", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "pkcs8" 1289 | version = "0.10.2" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 1292 | dependencies = [ 1293 | "der", 1294 | "spki", 1295 | ] 1296 | 1297 | [[package]] 1298 | name = "pkg-config" 1299 | version = "0.3.31" 1300 | source = "registry+https://github.com/rust-lang/crates.io-index" 1301 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1302 | 1303 | [[package]] 1304 | name = "ppv-lite86" 1305 | version = "0.2.20" 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" 1307 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1308 | dependencies = [ 1309 | "zerocopy", 1310 | ] 1311 | 1312 | [[package]] 1313 | name = "proc-macro2" 1314 | version = "1.0.87" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" 1317 | dependencies = [ 1318 | "unicode-ident", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "quote" 1323 | version = "1.0.37" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 1326 | dependencies = [ 1327 | "proc-macro2", 1328 | ] 1329 | 1330 | [[package]] 1331 | name = "rand" 1332 | version = "0.8.5" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1335 | dependencies = [ 1336 | "libc", 1337 | "rand_chacha", 1338 | "rand_core", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "rand_chacha" 1343 | version = "0.3.1" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1346 | dependencies = [ 1347 | "ppv-lite86", 1348 | "rand_core", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "rand_core" 1353 | version = "0.6.4" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1356 | dependencies = [ 1357 | "getrandom", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "redox_syscall" 1362 | version = "0.5.7" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" 1365 | dependencies = [ 1366 | "bitflags 2.6.0", 1367 | ] 1368 | 1369 | [[package]] 1370 | name = "redox_users" 1371 | version = "0.4.6" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 1374 | dependencies = [ 1375 | "getrandom", 1376 | "libredox", 1377 | "thiserror", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "regex" 1382 | version = "1.11.0" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" 1385 | dependencies = [ 1386 | "aho-corasick", 1387 | "memchr", 1388 | "regex-automata", 1389 | "regex-syntax", 1390 | ] 1391 | 1392 | [[package]] 1393 | name = "regex-automata" 1394 | version = "0.4.8" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" 1397 | dependencies = [ 1398 | "aho-corasick", 1399 | "memchr", 1400 | "regex-syntax", 1401 | ] 1402 | 1403 | [[package]] 1404 | name = "regex-syntax" 1405 | version = "0.8.5" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1408 | 1409 | [[package]] 1410 | name = "reqwest" 1411 | version = "0.11.27" 1412 | source = "registry+https://github.com/rust-lang/crates.io-index" 1413 | checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" 1414 | dependencies = [ 1415 | "base64 0.21.7", 1416 | "bytes", 1417 | "encoding_rs", 1418 | "futures-core", 1419 | "futures-util", 1420 | "h2", 1421 | "http 0.2.12", 1422 | "http-body", 1423 | "hyper", 1424 | "hyper-tls", 1425 | "ipnet", 1426 | "js-sys", 1427 | "log", 1428 | "mime", 1429 | "native-tls", 1430 | "once_cell", 1431 | "percent-encoding", 1432 | "pin-project-lite", 1433 | "rustls-pemfile 1.0.4", 1434 | "serde", 1435 | "serde_json", 1436 | "serde_urlencoded", 1437 | "sync_wrapper", 1438 | "system-configuration", 1439 | "tokio", 1440 | "tokio-native-tls", 1441 | "tower-service", 1442 | "url", 1443 | "wasm-bindgen", 1444 | "wasm-bindgen-futures", 1445 | "web-sys", 1446 | "winreg", 1447 | ] 1448 | 1449 | [[package]] 1450 | name = "ring" 1451 | version = "0.17.8" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1454 | dependencies = [ 1455 | "cc", 1456 | "cfg-if", 1457 | "getrandom", 1458 | "libc", 1459 | "spin", 1460 | "untrusted", 1461 | "windows-sys 0.52.0", 1462 | ] 1463 | 1464 | [[package]] 1465 | name = "rsa" 1466 | version = "0.9.6" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" 1469 | dependencies = [ 1470 | "const-oid", 1471 | "digest", 1472 | "num-bigint-dig", 1473 | "num-integer", 1474 | "num-traits", 1475 | "pkcs1", 1476 | "pkcs8", 1477 | "rand_core", 1478 | "signature", 1479 | "spki", 1480 | "subtle", 1481 | "zeroize", 1482 | ] 1483 | 1484 | [[package]] 1485 | name = "rustc-demangle" 1486 | version = "0.1.24" 1487 | source = "registry+https://github.com/rust-lang/crates.io-index" 1488 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1489 | 1490 | [[package]] 1491 | name = "rustc_version" 1492 | version = "0.4.1" 1493 | source = "registry+https://github.com/rust-lang/crates.io-index" 1494 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 1495 | dependencies = [ 1496 | "semver", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "rustix" 1501 | version = "0.38.37" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" 1504 | dependencies = [ 1505 | "bitflags 2.6.0", 1506 | "errno", 1507 | "libc", 1508 | "linux-raw-sys", 1509 | "windows-sys 0.52.0", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "rustls" 1514 | version = "0.23.14" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" 1517 | dependencies = [ 1518 | "once_cell", 1519 | "ring", 1520 | "rustls-pki-types", 1521 | "rustls-webpki", 1522 | "subtle", 1523 | "zeroize", 1524 | ] 1525 | 1526 | [[package]] 1527 | name = "rustls-pemfile" 1528 | version = "1.0.4" 1529 | source = "registry+https://github.com/rust-lang/crates.io-index" 1530 | checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" 1531 | dependencies = [ 1532 | "base64 0.21.7", 1533 | ] 1534 | 1535 | [[package]] 1536 | name = "rustls-pemfile" 1537 | version = "2.2.0" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 1540 | dependencies = [ 1541 | "rustls-pki-types", 1542 | ] 1543 | 1544 | [[package]] 1545 | name = "rustls-pki-types" 1546 | version = "1.9.0" 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" 1548 | checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" 1549 | 1550 | [[package]] 1551 | name = "rustls-webpki" 1552 | version = "0.102.8" 1553 | source = "registry+https://github.com/rust-lang/crates.io-index" 1554 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 1555 | dependencies = [ 1556 | "ring", 1557 | "rustls-pki-types", 1558 | "untrusted", 1559 | ] 1560 | 1561 | [[package]] 1562 | name = "ryu" 1563 | version = "1.0.18" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1566 | 1567 | [[package]] 1568 | name = "schannel" 1569 | version = "0.1.26" 1570 | source = "registry+https://github.com/rust-lang/crates.io-index" 1571 | checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" 1572 | dependencies = [ 1573 | "windows-sys 0.59.0", 1574 | ] 1575 | 1576 | [[package]] 1577 | name = "scoped-tls" 1578 | version = "1.0.1" 1579 | source = "registry+https://github.com/rust-lang/crates.io-index" 1580 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1581 | 1582 | [[package]] 1583 | name = "scopeguard" 1584 | version = "1.2.0" 1585 | source = "registry+https://github.com/rust-lang/crates.io-index" 1586 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1587 | 1588 | [[package]] 1589 | name = "security-framework" 1590 | version = "2.11.1" 1591 | source = "registry+https://github.com/rust-lang/crates.io-index" 1592 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1593 | dependencies = [ 1594 | "bitflags 2.6.0", 1595 | "core-foundation", 1596 | "core-foundation-sys", 1597 | "libc", 1598 | "security-framework-sys", 1599 | ] 1600 | 1601 | [[package]] 1602 | name = "security-framework-sys" 1603 | version = "2.12.0" 1604 | source = "registry+https://github.com/rust-lang/crates.io-index" 1605 | checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" 1606 | dependencies = [ 1607 | "core-foundation-sys", 1608 | "libc", 1609 | ] 1610 | 1611 | [[package]] 1612 | name = "semver" 1613 | version = "1.0.23" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 1616 | 1617 | [[package]] 1618 | name = "serde" 1619 | version = "1.0.210" 1620 | source = "registry+https://github.com/rust-lang/crates.io-index" 1621 | checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" 1622 | dependencies = [ 1623 | "serde_derive", 1624 | ] 1625 | 1626 | [[package]] 1627 | name = "serde_derive" 1628 | version = "1.0.210" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" 1631 | dependencies = [ 1632 | "proc-macro2", 1633 | "quote", 1634 | "syn", 1635 | ] 1636 | 1637 | [[package]] 1638 | name = "serde_json" 1639 | version = "1.0.128" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" 1642 | dependencies = [ 1643 | "itoa", 1644 | "memchr", 1645 | "ryu", 1646 | "serde", 1647 | ] 1648 | 1649 | [[package]] 1650 | name = "serde_urlencoded" 1651 | version = "0.7.1" 1652 | source = "registry+https://github.com/rust-lang/crates.io-index" 1653 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1654 | dependencies = [ 1655 | "form_urlencoded", 1656 | "itoa", 1657 | "ryu", 1658 | "serde", 1659 | ] 1660 | 1661 | [[package]] 1662 | name = "sha1" 1663 | version = "0.10.6" 1664 | source = "registry+https://github.com/rust-lang/crates.io-index" 1665 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1666 | dependencies = [ 1667 | "cfg-if", 1668 | "cpufeatures", 1669 | "digest", 1670 | ] 1671 | 1672 | [[package]] 1673 | name = "sha2" 1674 | version = "0.10.8" 1675 | source = "registry+https://github.com/rust-lang/crates.io-index" 1676 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1677 | dependencies = [ 1678 | "cfg-if", 1679 | "cpufeatures", 1680 | "digest", 1681 | ] 1682 | 1683 | [[package]] 1684 | name = "shlex" 1685 | version = "1.3.0" 1686 | source = "registry+https://github.com/rust-lang/crates.io-index" 1687 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1688 | 1689 | [[package]] 1690 | name = "signal-hook-registry" 1691 | version = "1.4.2" 1692 | source = "registry+https://github.com/rust-lang/crates.io-index" 1693 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1694 | dependencies = [ 1695 | "libc", 1696 | ] 1697 | 1698 | [[package]] 1699 | name = "signature" 1700 | version = "2.2.0" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 1703 | dependencies = [ 1704 | "digest", 1705 | "rand_core", 1706 | ] 1707 | 1708 | [[package]] 1709 | name = "slab" 1710 | version = "0.4.9" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1713 | dependencies = [ 1714 | "autocfg", 1715 | ] 1716 | 1717 | [[package]] 1718 | name = "smallvec" 1719 | version = "1.13.2" 1720 | source = "registry+https://github.com/rust-lang/crates.io-index" 1721 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1722 | dependencies = [ 1723 | "serde", 1724 | ] 1725 | 1726 | [[package]] 1727 | name = "socket2" 1728 | version = "0.5.7" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1731 | dependencies = [ 1732 | "libc", 1733 | "windows-sys 0.52.0", 1734 | ] 1735 | 1736 | [[package]] 1737 | name = "spin" 1738 | version = "0.9.8" 1739 | source = "registry+https://github.com/rust-lang/crates.io-index" 1740 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1741 | dependencies = [ 1742 | "lock_api", 1743 | ] 1744 | 1745 | [[package]] 1746 | name = "spki" 1747 | version = "0.7.3" 1748 | source = "registry+https://github.com/rust-lang/crates.io-index" 1749 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 1750 | dependencies = [ 1751 | "base64ct", 1752 | "der", 1753 | ] 1754 | 1755 | [[package]] 1756 | name = "sqlformat" 1757 | version = "0.2.6" 1758 | source = "registry+https://github.com/rust-lang/crates.io-index" 1759 | checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" 1760 | dependencies = [ 1761 | "nom", 1762 | "unicode_categories", 1763 | ] 1764 | 1765 | [[package]] 1766 | name = "sqlx" 1767 | version = "0.8.2" 1768 | source = "registry+https://github.com/rust-lang/crates.io-index" 1769 | checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" 1770 | dependencies = [ 1771 | "sqlx-core", 1772 | "sqlx-macros", 1773 | "sqlx-mysql", 1774 | "sqlx-postgres", 1775 | "sqlx-sqlite", 1776 | ] 1777 | 1778 | [[package]] 1779 | name = "sqlx-core" 1780 | version = "0.8.2" 1781 | source = "registry+https://github.com/rust-lang/crates.io-index" 1782 | checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" 1783 | dependencies = [ 1784 | "atoi", 1785 | "byteorder", 1786 | "bytes", 1787 | "crc", 1788 | "crossbeam-queue", 1789 | "either", 1790 | "event-listener", 1791 | "futures-channel", 1792 | "futures-core", 1793 | "futures-intrusive", 1794 | "futures-io", 1795 | "futures-util", 1796 | "hashbrown 0.14.5", 1797 | "hashlink", 1798 | "hex", 1799 | "indexmap", 1800 | "log", 1801 | "memchr", 1802 | "once_cell", 1803 | "paste", 1804 | "percent-encoding", 1805 | "rustls", 1806 | "rustls-pemfile 2.2.0", 1807 | "serde", 1808 | "serde_json", 1809 | "sha2", 1810 | "smallvec", 1811 | "sqlformat", 1812 | "thiserror", 1813 | "tokio", 1814 | "tokio-stream", 1815 | "tracing", 1816 | "url", 1817 | "webpki-roots", 1818 | ] 1819 | 1820 | [[package]] 1821 | name = "sqlx-macros" 1822 | version = "0.8.2" 1823 | source = "registry+https://github.com/rust-lang/crates.io-index" 1824 | checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" 1825 | dependencies = [ 1826 | "proc-macro2", 1827 | "quote", 1828 | "sqlx-core", 1829 | "sqlx-macros-core", 1830 | "syn", 1831 | ] 1832 | 1833 | [[package]] 1834 | name = "sqlx-macros-core" 1835 | version = "0.8.2" 1836 | source = "registry+https://github.com/rust-lang/crates.io-index" 1837 | checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" 1838 | dependencies = [ 1839 | "dotenvy", 1840 | "either", 1841 | "heck", 1842 | "hex", 1843 | "once_cell", 1844 | "proc-macro2", 1845 | "quote", 1846 | "serde", 1847 | "serde_json", 1848 | "sha2", 1849 | "sqlx-core", 1850 | "sqlx-mysql", 1851 | "sqlx-postgres", 1852 | "sqlx-sqlite", 1853 | "syn", 1854 | "tempfile", 1855 | "tokio", 1856 | "url", 1857 | ] 1858 | 1859 | [[package]] 1860 | name = "sqlx-mysql" 1861 | version = "0.8.2" 1862 | source = "registry+https://github.com/rust-lang/crates.io-index" 1863 | checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" 1864 | dependencies = [ 1865 | "atoi", 1866 | "base64 0.22.1", 1867 | "bitflags 2.6.0", 1868 | "byteorder", 1869 | "bytes", 1870 | "crc", 1871 | "digest", 1872 | "dotenvy", 1873 | "either", 1874 | "futures-channel", 1875 | "futures-core", 1876 | "futures-io", 1877 | "futures-util", 1878 | "generic-array", 1879 | "hex", 1880 | "hkdf", 1881 | "hmac", 1882 | "itoa", 1883 | "log", 1884 | "md-5", 1885 | "memchr", 1886 | "once_cell", 1887 | "percent-encoding", 1888 | "rand", 1889 | "rsa", 1890 | "serde", 1891 | "sha1", 1892 | "sha2", 1893 | "smallvec", 1894 | "sqlx-core", 1895 | "stringprep", 1896 | "thiserror", 1897 | "tracing", 1898 | "whoami", 1899 | ] 1900 | 1901 | [[package]] 1902 | name = "sqlx-postgres" 1903 | version = "0.8.2" 1904 | source = "registry+https://github.com/rust-lang/crates.io-index" 1905 | checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" 1906 | dependencies = [ 1907 | "atoi", 1908 | "base64 0.22.1", 1909 | "bitflags 2.6.0", 1910 | "byteorder", 1911 | "crc", 1912 | "dotenvy", 1913 | "etcetera", 1914 | "futures-channel", 1915 | "futures-core", 1916 | "futures-io", 1917 | "futures-util", 1918 | "hex", 1919 | "hkdf", 1920 | "hmac", 1921 | "home", 1922 | "itoa", 1923 | "log", 1924 | "md-5", 1925 | "memchr", 1926 | "once_cell", 1927 | "rand", 1928 | "serde", 1929 | "serde_json", 1930 | "sha2", 1931 | "smallvec", 1932 | "sqlx-core", 1933 | "stringprep", 1934 | "thiserror", 1935 | "tracing", 1936 | "whoami", 1937 | ] 1938 | 1939 | [[package]] 1940 | name = "sqlx-sqlite" 1941 | version = "0.8.2" 1942 | source = "registry+https://github.com/rust-lang/crates.io-index" 1943 | checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" 1944 | dependencies = [ 1945 | "atoi", 1946 | "flume", 1947 | "futures-channel", 1948 | "futures-core", 1949 | "futures-executor", 1950 | "futures-intrusive", 1951 | "futures-util", 1952 | "libsqlite3-sys", 1953 | "log", 1954 | "percent-encoding", 1955 | "serde", 1956 | "serde_urlencoded", 1957 | "sqlx-core", 1958 | "tracing", 1959 | "url", 1960 | ] 1961 | 1962 | [[package]] 1963 | name = "stringprep" 1964 | version = "0.1.5" 1965 | source = "registry+https://github.com/rust-lang/crates.io-index" 1966 | checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" 1967 | dependencies = [ 1968 | "unicode-bidi", 1969 | "unicode-normalization", 1970 | "unicode-properties", 1971 | ] 1972 | 1973 | [[package]] 1974 | name = "strsim" 1975 | version = "0.8.0" 1976 | source = "registry+https://github.com/rust-lang/crates.io-index" 1977 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1978 | 1979 | [[package]] 1980 | name = "subtle" 1981 | version = "2.6.1" 1982 | source = "registry+https://github.com/rust-lang/crates.io-index" 1983 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1984 | 1985 | [[package]] 1986 | name = "syn" 1987 | version = "2.0.79" 1988 | source = "registry+https://github.com/rust-lang/crates.io-index" 1989 | checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" 1990 | dependencies = [ 1991 | "proc-macro2", 1992 | "quote", 1993 | "unicode-ident", 1994 | ] 1995 | 1996 | [[package]] 1997 | name = "sync_wrapper" 1998 | version = "0.1.2" 1999 | source = "registry+https://github.com/rust-lang/crates.io-index" 2000 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 2001 | 2002 | [[package]] 2003 | name = "system-configuration" 2004 | version = "0.5.1" 2005 | source = "registry+https://github.com/rust-lang/crates.io-index" 2006 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 2007 | dependencies = [ 2008 | "bitflags 1.3.2", 2009 | "core-foundation", 2010 | "system-configuration-sys", 2011 | ] 2012 | 2013 | [[package]] 2014 | name = "system-configuration-sys" 2015 | version = "0.5.0" 2016 | source = "registry+https://github.com/rust-lang/crates.io-index" 2017 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 2018 | dependencies = [ 2019 | "core-foundation-sys", 2020 | "libc", 2021 | ] 2022 | 2023 | [[package]] 2024 | name = "tempfile" 2025 | version = "3.13.0" 2026 | source = "registry+https://github.com/rust-lang/crates.io-index" 2027 | checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" 2028 | dependencies = [ 2029 | "cfg-if", 2030 | "fastrand", 2031 | "once_cell", 2032 | "rustix", 2033 | "windows-sys 0.59.0", 2034 | ] 2035 | 2036 | [[package]] 2037 | name = "termcolor" 2038 | version = "1.4.1" 2039 | source = "registry+https://github.com/rust-lang/crates.io-index" 2040 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 2041 | dependencies = [ 2042 | "winapi-util", 2043 | ] 2044 | 2045 | [[package]] 2046 | name = "textwrap" 2047 | version = "0.11.0" 2048 | source = "registry+https://github.com/rust-lang/crates.io-index" 2049 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 2050 | dependencies = [ 2051 | "unicode-width", 2052 | ] 2053 | 2054 | [[package]] 2055 | name = "thiserror" 2056 | version = "1.0.64" 2057 | source = "registry+https://github.com/rust-lang/crates.io-index" 2058 | checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" 2059 | dependencies = [ 2060 | "thiserror-impl", 2061 | ] 2062 | 2063 | [[package]] 2064 | name = "thiserror-impl" 2065 | version = "1.0.64" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" 2068 | dependencies = [ 2069 | "proc-macro2", 2070 | "quote", 2071 | "syn", 2072 | ] 2073 | 2074 | [[package]] 2075 | name = "tinyvec" 2076 | version = "1.8.0" 2077 | source = "registry+https://github.com/rust-lang/crates.io-index" 2078 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 2079 | dependencies = [ 2080 | "tinyvec_macros", 2081 | ] 2082 | 2083 | [[package]] 2084 | name = "tinyvec_macros" 2085 | version = "0.1.1" 2086 | source = "registry+https://github.com/rust-lang/crates.io-index" 2087 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2088 | 2089 | [[package]] 2090 | name = "tokio" 2091 | version = "1.40.0" 2092 | source = "registry+https://github.com/rust-lang/crates.io-index" 2093 | checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" 2094 | dependencies = [ 2095 | "backtrace", 2096 | "bytes", 2097 | "libc", 2098 | "mio", 2099 | "parking_lot", 2100 | "pin-project-lite", 2101 | "signal-hook-registry", 2102 | "socket2", 2103 | "tokio-macros", 2104 | "windows-sys 0.52.0", 2105 | ] 2106 | 2107 | [[package]] 2108 | name = "tokio-macros" 2109 | version = "2.4.0" 2110 | source = "registry+https://github.com/rust-lang/crates.io-index" 2111 | checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" 2112 | dependencies = [ 2113 | "proc-macro2", 2114 | "quote", 2115 | "syn", 2116 | ] 2117 | 2118 | [[package]] 2119 | name = "tokio-native-tls" 2120 | version = "0.3.1" 2121 | source = "registry+https://github.com/rust-lang/crates.io-index" 2122 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2123 | dependencies = [ 2124 | "native-tls", 2125 | "tokio", 2126 | ] 2127 | 2128 | [[package]] 2129 | name = "tokio-stream" 2130 | version = "0.1.16" 2131 | source = "registry+https://github.com/rust-lang/crates.io-index" 2132 | checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" 2133 | dependencies = [ 2134 | "futures-core", 2135 | "pin-project-lite", 2136 | "tokio", 2137 | ] 2138 | 2139 | [[package]] 2140 | name = "tokio-tungstenite" 2141 | version = "0.21.0" 2142 | source = "registry+https://github.com/rust-lang/crates.io-index" 2143 | checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" 2144 | dependencies = [ 2145 | "futures-util", 2146 | "log", 2147 | "tokio", 2148 | "tungstenite", 2149 | ] 2150 | 2151 | [[package]] 2152 | name = "tokio-util" 2153 | version = "0.7.12" 2154 | source = "registry+https://github.com/rust-lang/crates.io-index" 2155 | checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" 2156 | dependencies = [ 2157 | "bytes", 2158 | "futures-core", 2159 | "futures-sink", 2160 | "pin-project-lite", 2161 | "tokio", 2162 | ] 2163 | 2164 | [[package]] 2165 | name = "toml" 2166 | version = "0.5.11" 2167 | source = "registry+https://github.com/rust-lang/crates.io-index" 2168 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 2169 | dependencies = [ 2170 | "serde", 2171 | ] 2172 | 2173 | [[package]] 2174 | name = "tower-service" 2175 | version = "0.3.3" 2176 | source = "registry+https://github.com/rust-lang/crates.io-index" 2177 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 2178 | 2179 | [[package]] 2180 | name = "tracing" 2181 | version = "0.1.40" 2182 | source = "registry+https://github.com/rust-lang/crates.io-index" 2183 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 2184 | dependencies = [ 2185 | "log", 2186 | "pin-project-lite", 2187 | "tracing-attributes", 2188 | "tracing-core", 2189 | ] 2190 | 2191 | [[package]] 2192 | name = "tracing-attributes" 2193 | version = "0.1.27" 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" 2195 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 2196 | dependencies = [ 2197 | "proc-macro2", 2198 | "quote", 2199 | "syn", 2200 | ] 2201 | 2202 | [[package]] 2203 | name = "tracing-core" 2204 | version = "0.1.32" 2205 | source = "registry+https://github.com/rust-lang/crates.io-index" 2206 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 2207 | dependencies = [ 2208 | "once_cell", 2209 | ] 2210 | 2211 | [[package]] 2212 | name = "try-lock" 2213 | version = "0.2.5" 2214 | source = "registry+https://github.com/rust-lang/crates.io-index" 2215 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2216 | 2217 | [[package]] 2218 | name = "tungstenite" 2219 | version = "0.21.0" 2220 | source = "registry+https://github.com/rust-lang/crates.io-index" 2221 | checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" 2222 | dependencies = [ 2223 | "byteorder", 2224 | "bytes", 2225 | "data-encoding", 2226 | "http 1.1.0", 2227 | "httparse", 2228 | "log", 2229 | "rand", 2230 | "sha1", 2231 | "thiserror", 2232 | "url", 2233 | "utf-8", 2234 | ] 2235 | 2236 | [[package]] 2237 | name = "typenum" 2238 | version = "1.17.0" 2239 | source = "registry+https://github.com/rust-lang/crates.io-index" 2240 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2241 | 2242 | [[package]] 2243 | name = "unicase" 2244 | version = "2.7.0" 2245 | source = "registry+https://github.com/rust-lang/crates.io-index" 2246 | checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" 2247 | dependencies = [ 2248 | "version_check", 2249 | ] 2250 | 2251 | [[package]] 2252 | name = "unicode-bidi" 2253 | version = "0.3.17" 2254 | source = "registry+https://github.com/rust-lang/crates.io-index" 2255 | checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" 2256 | 2257 | [[package]] 2258 | name = "unicode-ident" 2259 | version = "1.0.13" 2260 | source = "registry+https://github.com/rust-lang/crates.io-index" 2261 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 2262 | 2263 | [[package]] 2264 | name = "unicode-normalization" 2265 | version = "0.1.24" 2266 | source = "registry+https://github.com/rust-lang/crates.io-index" 2267 | checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" 2268 | dependencies = [ 2269 | "tinyvec", 2270 | ] 2271 | 2272 | [[package]] 2273 | name = "unicode-properties" 2274 | version = "0.1.3" 2275 | source = "registry+https://github.com/rust-lang/crates.io-index" 2276 | checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" 2277 | 2278 | [[package]] 2279 | name = "unicode-width" 2280 | version = "0.1.14" 2281 | source = "registry+https://github.com/rust-lang/crates.io-index" 2282 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 2283 | 2284 | [[package]] 2285 | name = "unicode_categories" 2286 | version = "0.1.1" 2287 | source = "registry+https://github.com/rust-lang/crates.io-index" 2288 | checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" 2289 | 2290 | [[package]] 2291 | name = "untrusted" 2292 | version = "0.9.0" 2293 | source = "registry+https://github.com/rust-lang/crates.io-index" 2294 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2295 | 2296 | [[package]] 2297 | name = "url" 2298 | version = "2.5.2" 2299 | source = "registry+https://github.com/rust-lang/crates.io-index" 2300 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 2301 | dependencies = [ 2302 | "form_urlencoded", 2303 | "idna", 2304 | "percent-encoding", 2305 | ] 2306 | 2307 | [[package]] 2308 | name = "utf-8" 2309 | version = "0.7.6" 2310 | source = "registry+https://github.com/rust-lang/crates.io-index" 2311 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 2312 | 2313 | [[package]] 2314 | name = "vcpkg" 2315 | version = "0.2.15" 2316 | source = "registry+https://github.com/rust-lang/crates.io-index" 2317 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2318 | 2319 | [[package]] 2320 | name = "vec_map" 2321 | version = "0.8.2" 2322 | source = "registry+https://github.com/rust-lang/crates.io-index" 2323 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 2324 | 2325 | [[package]] 2326 | name = "version_check" 2327 | version = "0.9.5" 2328 | source = "registry+https://github.com/rust-lang/crates.io-index" 2329 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2330 | 2331 | [[package]] 2332 | name = "want" 2333 | version = "0.3.1" 2334 | source = "registry+https://github.com/rust-lang/crates.io-index" 2335 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2336 | dependencies = [ 2337 | "try-lock", 2338 | ] 2339 | 2340 | [[package]] 2341 | name = "warp" 2342 | version = "0.3.7" 2343 | source = "registry+https://github.com/rust-lang/crates.io-index" 2344 | checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" 2345 | dependencies = [ 2346 | "bytes", 2347 | "futures-channel", 2348 | "futures-util", 2349 | "headers", 2350 | "http 0.2.12", 2351 | "hyper", 2352 | "log", 2353 | "mime", 2354 | "mime_guess", 2355 | "multer", 2356 | "percent-encoding", 2357 | "pin-project", 2358 | "scoped-tls", 2359 | "serde", 2360 | "serde_json", 2361 | "serde_urlencoded", 2362 | "tokio", 2363 | "tokio-tungstenite", 2364 | "tokio-util", 2365 | "tower-service", 2366 | "tracing", 2367 | ] 2368 | 2369 | [[package]] 2370 | name = "wasi" 2371 | version = "0.11.0+wasi-snapshot-preview1" 2372 | source = "registry+https://github.com/rust-lang/crates.io-index" 2373 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2374 | 2375 | [[package]] 2376 | name = "wasite" 2377 | version = "0.1.0" 2378 | source = "registry+https://github.com/rust-lang/crates.io-index" 2379 | checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" 2380 | 2381 | [[package]] 2382 | name = "wasm-bindgen" 2383 | version = "0.2.93" 2384 | source = "registry+https://github.com/rust-lang/crates.io-index" 2385 | checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" 2386 | dependencies = [ 2387 | "cfg-if", 2388 | "once_cell", 2389 | "wasm-bindgen-macro", 2390 | ] 2391 | 2392 | [[package]] 2393 | name = "wasm-bindgen-backend" 2394 | version = "0.2.93" 2395 | source = "registry+https://github.com/rust-lang/crates.io-index" 2396 | checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" 2397 | dependencies = [ 2398 | "bumpalo", 2399 | "log", 2400 | "once_cell", 2401 | "proc-macro2", 2402 | "quote", 2403 | "syn", 2404 | "wasm-bindgen-shared", 2405 | ] 2406 | 2407 | [[package]] 2408 | name = "wasm-bindgen-futures" 2409 | version = "0.4.43" 2410 | source = "registry+https://github.com/rust-lang/crates.io-index" 2411 | checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" 2412 | dependencies = [ 2413 | "cfg-if", 2414 | "js-sys", 2415 | "wasm-bindgen", 2416 | "web-sys", 2417 | ] 2418 | 2419 | [[package]] 2420 | name = "wasm-bindgen-macro" 2421 | version = "0.2.93" 2422 | source = "registry+https://github.com/rust-lang/crates.io-index" 2423 | checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" 2424 | dependencies = [ 2425 | "quote", 2426 | "wasm-bindgen-macro-support", 2427 | ] 2428 | 2429 | [[package]] 2430 | name = "wasm-bindgen-macro-support" 2431 | version = "0.2.93" 2432 | source = "registry+https://github.com/rust-lang/crates.io-index" 2433 | checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" 2434 | dependencies = [ 2435 | "proc-macro2", 2436 | "quote", 2437 | "syn", 2438 | "wasm-bindgen-backend", 2439 | "wasm-bindgen-shared", 2440 | ] 2441 | 2442 | [[package]] 2443 | name = "wasm-bindgen-shared" 2444 | version = "0.2.93" 2445 | source = "registry+https://github.com/rust-lang/crates.io-index" 2446 | checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" 2447 | 2448 | [[package]] 2449 | name = "web-sys" 2450 | version = "0.3.70" 2451 | source = "registry+https://github.com/rust-lang/crates.io-index" 2452 | checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" 2453 | dependencies = [ 2454 | "js-sys", 2455 | "wasm-bindgen", 2456 | ] 2457 | 2458 | [[package]] 2459 | name = "webpki-roots" 2460 | version = "0.26.6" 2461 | source = "registry+https://github.com/rust-lang/crates.io-index" 2462 | checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" 2463 | dependencies = [ 2464 | "rustls-pki-types", 2465 | ] 2466 | 2467 | [[package]] 2468 | name = "whoami" 2469 | version = "1.5.2" 2470 | source = "registry+https://github.com/rust-lang/crates.io-index" 2471 | checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" 2472 | dependencies = [ 2473 | "redox_syscall", 2474 | "wasite", 2475 | ] 2476 | 2477 | [[package]] 2478 | name = "winapi" 2479 | version = "0.3.9" 2480 | source = "registry+https://github.com/rust-lang/crates.io-index" 2481 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2482 | dependencies = [ 2483 | "winapi-i686-pc-windows-gnu", 2484 | "winapi-x86_64-pc-windows-gnu", 2485 | ] 2486 | 2487 | [[package]] 2488 | name = "winapi-i686-pc-windows-gnu" 2489 | version = "0.4.0" 2490 | source = "registry+https://github.com/rust-lang/crates.io-index" 2491 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2492 | 2493 | [[package]] 2494 | name = "winapi-util" 2495 | version = "0.1.9" 2496 | source = "registry+https://github.com/rust-lang/crates.io-index" 2497 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 2498 | dependencies = [ 2499 | "windows-sys 0.59.0", 2500 | ] 2501 | 2502 | [[package]] 2503 | name = "winapi-x86_64-pc-windows-gnu" 2504 | version = "0.4.0" 2505 | source = "registry+https://github.com/rust-lang/crates.io-index" 2506 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2507 | 2508 | [[package]] 2509 | name = "windows-core" 2510 | version = "0.52.0" 2511 | source = "registry+https://github.com/rust-lang/crates.io-index" 2512 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 2513 | dependencies = [ 2514 | "windows-targets 0.52.6", 2515 | ] 2516 | 2517 | [[package]] 2518 | name = "windows-sys" 2519 | version = "0.48.0" 2520 | source = "registry+https://github.com/rust-lang/crates.io-index" 2521 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2522 | dependencies = [ 2523 | "windows-targets 0.48.5", 2524 | ] 2525 | 2526 | [[package]] 2527 | name = "windows-sys" 2528 | version = "0.52.0" 2529 | source = "registry+https://github.com/rust-lang/crates.io-index" 2530 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2531 | dependencies = [ 2532 | "windows-targets 0.52.6", 2533 | ] 2534 | 2535 | [[package]] 2536 | name = "windows-sys" 2537 | version = "0.59.0" 2538 | source = "registry+https://github.com/rust-lang/crates.io-index" 2539 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2540 | dependencies = [ 2541 | "windows-targets 0.52.6", 2542 | ] 2543 | 2544 | [[package]] 2545 | name = "windows-targets" 2546 | version = "0.48.5" 2547 | source = "registry+https://github.com/rust-lang/crates.io-index" 2548 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2549 | dependencies = [ 2550 | "windows_aarch64_gnullvm 0.48.5", 2551 | "windows_aarch64_msvc 0.48.5", 2552 | "windows_i686_gnu 0.48.5", 2553 | "windows_i686_msvc 0.48.5", 2554 | "windows_x86_64_gnu 0.48.5", 2555 | "windows_x86_64_gnullvm 0.48.5", 2556 | "windows_x86_64_msvc 0.48.5", 2557 | ] 2558 | 2559 | [[package]] 2560 | name = "windows-targets" 2561 | version = "0.52.6" 2562 | source = "registry+https://github.com/rust-lang/crates.io-index" 2563 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2564 | dependencies = [ 2565 | "windows_aarch64_gnullvm 0.52.6", 2566 | "windows_aarch64_msvc 0.52.6", 2567 | "windows_i686_gnu 0.52.6", 2568 | "windows_i686_gnullvm", 2569 | "windows_i686_msvc 0.52.6", 2570 | "windows_x86_64_gnu 0.52.6", 2571 | "windows_x86_64_gnullvm 0.52.6", 2572 | "windows_x86_64_msvc 0.52.6", 2573 | ] 2574 | 2575 | [[package]] 2576 | name = "windows_aarch64_gnullvm" 2577 | version = "0.48.5" 2578 | source = "registry+https://github.com/rust-lang/crates.io-index" 2579 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2580 | 2581 | [[package]] 2582 | name = "windows_aarch64_gnullvm" 2583 | version = "0.52.6" 2584 | source = "registry+https://github.com/rust-lang/crates.io-index" 2585 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2586 | 2587 | [[package]] 2588 | name = "windows_aarch64_msvc" 2589 | version = "0.48.5" 2590 | source = "registry+https://github.com/rust-lang/crates.io-index" 2591 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2592 | 2593 | [[package]] 2594 | name = "windows_aarch64_msvc" 2595 | version = "0.52.6" 2596 | source = "registry+https://github.com/rust-lang/crates.io-index" 2597 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2598 | 2599 | [[package]] 2600 | name = "windows_i686_gnu" 2601 | version = "0.48.5" 2602 | source = "registry+https://github.com/rust-lang/crates.io-index" 2603 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2604 | 2605 | [[package]] 2606 | name = "windows_i686_gnu" 2607 | version = "0.52.6" 2608 | source = "registry+https://github.com/rust-lang/crates.io-index" 2609 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2610 | 2611 | [[package]] 2612 | name = "windows_i686_gnullvm" 2613 | version = "0.52.6" 2614 | source = "registry+https://github.com/rust-lang/crates.io-index" 2615 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2616 | 2617 | [[package]] 2618 | name = "windows_i686_msvc" 2619 | version = "0.48.5" 2620 | source = "registry+https://github.com/rust-lang/crates.io-index" 2621 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2622 | 2623 | [[package]] 2624 | name = "windows_i686_msvc" 2625 | version = "0.52.6" 2626 | source = "registry+https://github.com/rust-lang/crates.io-index" 2627 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2628 | 2629 | [[package]] 2630 | name = "windows_x86_64_gnu" 2631 | version = "0.48.5" 2632 | source = "registry+https://github.com/rust-lang/crates.io-index" 2633 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2634 | 2635 | [[package]] 2636 | name = "windows_x86_64_gnu" 2637 | version = "0.52.6" 2638 | source = "registry+https://github.com/rust-lang/crates.io-index" 2639 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2640 | 2641 | [[package]] 2642 | name = "windows_x86_64_gnullvm" 2643 | version = "0.48.5" 2644 | source = "registry+https://github.com/rust-lang/crates.io-index" 2645 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2646 | 2647 | [[package]] 2648 | name = "windows_x86_64_gnullvm" 2649 | version = "0.52.6" 2650 | source = "registry+https://github.com/rust-lang/crates.io-index" 2651 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2652 | 2653 | [[package]] 2654 | name = "windows_x86_64_msvc" 2655 | version = "0.48.5" 2656 | source = "registry+https://github.com/rust-lang/crates.io-index" 2657 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2658 | 2659 | [[package]] 2660 | name = "windows_x86_64_msvc" 2661 | version = "0.52.6" 2662 | source = "registry+https://github.com/rust-lang/crates.io-index" 2663 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2664 | 2665 | [[package]] 2666 | name = "winreg" 2667 | version = "0.50.0" 2668 | source = "registry+https://github.com/rust-lang/crates.io-index" 2669 | checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" 2670 | dependencies = [ 2671 | "cfg-if", 2672 | "windows-sys 0.48.0", 2673 | ] 2674 | 2675 | [[package]] 2676 | name = "zerocopy" 2677 | version = "0.7.35" 2678 | source = "registry+https://github.com/rust-lang/crates.io-index" 2679 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2680 | dependencies = [ 2681 | "byteorder", 2682 | "zerocopy-derive", 2683 | ] 2684 | 2685 | [[package]] 2686 | name = "zerocopy-derive" 2687 | version = "0.7.35" 2688 | source = "registry+https://github.com/rust-lang/crates.io-index" 2689 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2690 | dependencies = [ 2691 | "proc-macro2", 2692 | "quote", 2693 | "syn", 2694 | ] 2695 | 2696 | [[package]] 2697 | name = "zeroize" 2698 | version = "1.8.1" 2699 | source = "registry+https://github.com/rust-lang/crates.io-index" 2700 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2701 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "server", 4 | "shared", 5 | "worker", 6 | "evaluator", 7 | ] 8 | 9 | [workspace.dependencies] 10 | reqwest = { version = "0.11", features = [ "json", "blocking" ]} 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Deprecated: This is now intended to be [an integrated CI tool](https://github.com/ekala-project/eka-ci) 2 | 3 | # Basinix 4 | 5 | This is meant to be a pull request reviewing tool for large nix package sets. 6 | 7 | This is intended to be an intersection of [nixpkgs-review](https://github.com/Mic92/nixpkgs-review), [ofborg](https://github.com/NixOS/ofborg) and [hydra](https://github.com/NixOS/hydra). 8 | In which each PR will be a "jobset", all changed packages will be built and cached. Then when failures or regressions occur, there's enough data to pinpoint when the failures occured and with what commit. Also, failures will only be attempted to be built once. 9 | 10 | This is also meant to be exposed as a website similar to Hydra. However, there will be more emphasis as on this being used as a tool, and will allow for users to view information. Users will also be able to login with their github credentials, and perform PR actions. 11 | 12 | # Roadmap (Initial CI support) 13 | 14 | - [ ] Server 15 | - [x] Ability to pull Github events 16 | - [x] Initial polling of api events 17 | - [x] Filter events relevant to needing a rebuild 18 | - [x] Deconflict with previous events 19 | - [ ] Ability to configure basinix 20 | - [ ] Cache directory: base branch checkout and pr worktrees 21 | - [ ] Workers: 22 | - [ ] Number of threads, number of workers 23 | - [ ] (Optional) Attempt to do cgroups 24 | - [ ] Set cpu and memory limits 25 | - [ ] Building derivations 26 | - [ ] Nixpkgs control 27 | - [x] Create worktrees for each PR 28 | - [ ] Update refs (e.g. master branch) on push events 29 | - [ ] Build and evaluate difference between commits 30 | - [x] Initial Evaluation support 31 | - [x] Verify PR didn't break evaluation 32 | - [ ] support `allowAliases = false;` scenario 33 | - [x] Determine new or changed attrs 34 | - [ ] Deconflict with previous builds (successful or unsuccessful) 35 | - [ ] Create priority queue of nix builds needed to be complete 36 | - Probably optimize for lowest rebuild number (increase # of PRs able to be reviewed) 37 | - [ ] Accurately adjust (remove no-longer relevant, add new builds) to PRs getting push events 38 | - [ ] Detect "tests", and build those as well 39 | - [ ] Check if `passthru.tests` is populated and add derivations as additional tests 40 | - [ ] Nix garbage collection policies 41 | - [ ] Retain "fixed-output-derivations" on a branch 42 | - [ ] Retain all derivations on a branch 43 | - [ ] "Archive", or keep everything 44 | - [ ] Flake support 45 | - [ ] translate `basinixJobs` into PR gates 46 | - [ ] Web UI 47 | - [ ] Initial layout 48 | - [ ] Be able to view PR status 49 | - [ ] New / changed / removed packages 50 | - [ ] Build status of affected packages 51 | - [ ] (Optional) Linting gates? 52 | - [ ] Github Integration 53 | - [ ] Oauth support 54 | - [ ] PR actions 55 | - [ ] View PR diff (for easy checking) 56 | - [ ] Merge 57 | - [ ] without comment 58 | - [ ] with comment 59 | - [ ] Enumerate newly failing, newly succeeding, still failing, still suceeding, removed packages 60 | - [ ] Addtional checks (tests, etc) 61 | - [ ] Review Comment (see above) 62 | - [ ] Packaging 63 | - [ ] Expose nix modules 64 | 65 | # Future Features 66 | 67 | - [ ] Added, removed, changed files from outputs between base branch and head 68 | - [ ] Allow for "post-build-hook" like behavior of uploading artifacts with explicit lifetimes 69 | - [ ] Diffoscope like changes from base branch to PR 70 | - [ ] Mult-platform support (unlikely to happen unless someone donates hardware) 71 | - [ ] Support remote host workers 72 | - [ ] aarch64-linux 73 | - [ ] aarch64-darwin 74 | - [ ] x86_64-darwin 75 | - [ ] Support for systemFeatures and related configuration 76 | - [ ] Heterogenous cpu and memory configurations 77 | - [ ] nixos-test 78 | - [ ] big-parallel 79 | -------------------------------------------------------------------------------- /evaluator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "basinix_evaluator" 3 | version = "0.1.0" 4 | authors = ["Jonathan Ringer "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bincode = "^1.3" 11 | log = "0.4" 12 | chrono = "0.4" 13 | env_logger = "0.8" 14 | basinix_shared = { path = "../shared" } 15 | serde = { version = "1.0", features = ["derive"] } 16 | serde_json = "1.0" 17 | reqwest = { workspace = true } 18 | tokio = { version = "1.0", features = ["process"] } 19 | 20 | [lib] 21 | name = "basinix_evaluator" 22 | path = "src/lib.rs" 23 | 24 | [[bin]] 25 | name = "basinix_evaluator_runner" 26 | path = "src/main.rs" -------------------------------------------------------------------------------- /evaluator/find-drvs-from-previous-commit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env nix-shell 2 | #!nix-shell -i bash -p git nix jq 3 | 4 | set -euo pipefail 5 | 6 | echoerr() { 7 | echo -e $@ >&2 8 | } 9 | 10 | usage() { 11 | local name=$(basename $0) 12 | echoerr "$name Create derivations from a given commit" 13 | echoerr "" 14 | echoerr "USAGE:" 15 | echoerr "\t$name " 16 | echoerr "" 17 | echoerr "ARGS:" 18 | echoerr "\tcommit-ish>\t\t git commit-ish from nixpkgs repo" 19 | echoerr "" 20 | echoerr "EXAMPLE:" 21 | echoerr "\t$ $name abcdefg" 22 | exit 1 23 | } 24 | 25 | [ "$1" == "--help" -o "$1" = "-h" ] && usage 26 | 27 | # validate environment 28 | if [ -z "${NIXPKGS_PATH:-}" ]; then 29 | echoerr "error: Please set NIXPKGS_PATH before running script" 30 | echoerr "" 31 | usage 32 | fi 33 | 34 | if [ -z "${1:-}" ]; then 35 | echoerr "No rev was given, please give a valid rev" 36 | echoerr "" 37 | usage 38 | fi 39 | PR_NUMBER="$1" 40 | 41 | #if test $(git cat-file --path="$NIXPKGS_PATH" -t commit) != commit; then 42 | # echoerr "The rev \'$rev\' was not a valid commit" 43 | # echoerr "" 44 | # usage 45 | #fi 46 | 47 | set -x 48 | 49 | # create workdir 50 | worktreedir=$(mktemp -d) 51 | 52 | # remove tempdir, incase something fails 53 | #trap "rm -rf $worktreedir" EXIT 54 | pushd "$NIXPKGS_PATH" 55 | 56 | git -c fetch.prune=false fetch --force https://github.com/NixOS/nixpkgs pull/$PR_NUMBER/head:refs/evaluator 57 | 58 | git worktree add $worktreedir refs/evaluator 59 | 60 | cd $worktreedir 61 | 62 | list_drvs() { 63 | nix-env -I nixpkgs="$NIXPKGS_PATH" -f $worktreedir -qaP --no-name --drv-path --show-trace | sort 64 | } 65 | 66 | list_drvs > new_drvs.txt 67 | 68 | git checkout HEAD^ 69 | 70 | list_drvs > old_drvs.txt 71 | 72 | comm -23 old_drvs.txt new_drvs.txt > old_diff_drvs.txt 73 | comm -13 old_drvs.txt new_drvs.txt > new_diff_drvs.txt 74 | 75 | -------------------------------------------------------------------------------- /evaluator/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | use basinix_shared::types::{BuildRequest, GlobalConfig}; 3 | use basinix_shared::types::Message::{self, EvalPullRequest, EvalPush, PullRequestClosed}; 4 | use log::{debug, error, info}; 5 | use std::fs; 6 | use std::process::Command; 7 | use std::sync::mpsc::{Receiver, Sender}; 8 | 9 | pub mod pull_request; 10 | 11 | const LOG_TARGET: &str = "basinix::evaluator"; 12 | 13 | fn ensure_nixpkgs_exists(config: GlobalConfig) { 14 | let nixpkgs_path = &config.nixpkgs_dir.as_path(); 15 | let nixpkgs_path_str = nixpkgs_path.to_str().unwrap(); 16 | 17 | if !nixpkgs_path.exists() { 18 | info!("Creating nixpkgs checkout at {}", nixpkgs_path_str); 19 | fs::create_dir_all(nixpkgs_path).unwrap_or_else(|_| panic!("Unable to create nixpkgs directory at: {}", 20 | nixpkgs_path_str)); 21 | 22 | if !Command::new("git") 23 | .args(&[ 24 | "clone", 25 | "git@github.com:NixOS/nixpkgs.git", 26 | nixpkgs_path_str, 27 | ]) 28 | .status() 29 | .unwrap() 30 | .success() 31 | { 32 | error!("Failed to clone nixpkgs repo to {}", nixpkgs_path_str); 33 | error!("Please ensure that XDG_CACHE_DIR is write-able"); 34 | std::process::exit(1); 35 | } 36 | } 37 | 38 | Command::new("git") 39 | .current_dir(nixpkgs_path_str) 40 | .args(&[ 41 | "-c", 42 | "fetch.prune=false", 43 | "fetch", 44 | "origin", 45 | ]) 46 | .status() 47 | .expect("Unable to fetch remote for nixpkgs"); 48 | 49 | // We want to get into detached HEAD, as worktrees may already have a branch or commit checkedout 50 | Command::new("git") 51 | .current_dir(nixpkgs_path_str) 52 | .args(&[ 53 | "checkout", 54 | "origin/master^", 55 | ]) 56 | .status() 57 | .expect("Unable to checkout nixpkgs origin/master"); 58 | } 59 | 60 | pub fn eval_events(recv: Receiver, build_sender: Sender, config: GlobalConfig) { 61 | debug!(target: LOG_TARGET, "Ensuring nixpkgs checkout"); 62 | ensure_nixpkgs_exists(config.clone()); 63 | 64 | // This is used to check whether or not we need to update the base branch 65 | // and determine all of the drv paths 66 | let mut base_revs: std::collections::HashMap = std::collections::HashMap::new(); 67 | 68 | debug!(target: LOG_TARGET, "Starting evaluator loop"); 69 | loop { 70 | match recv.recv() { 71 | Ok(EvalPush(push_info)) => { 72 | info!( 73 | "Evaluating push from {} to {}", 74 | &push_info.before, &push_info.head 75 | ); 76 | } 77 | 78 | Ok(EvalPullRequest(pr)) => { 79 | info!("Evaluating pull request: {}", pr.number); 80 | let pr_result = pull_request::eval_pr(&config, build_sender.clone(), pr.number, &mut base_revs); 81 | match pr_result { 82 | Err(_) => log::error!("Failed to eval pr: {}", pr.number), 83 | Ok(_) => log::info!("Completed eval for pr: {}", pr.number) 84 | } 85 | } 86 | 87 | Ok(PullRequestClosed(pr)) => { 88 | info!("Pull request was closed: {}", pr); 89 | } 90 | 91 | Err(e) => { 92 | error!("Failed to receive evaluation event: {:?}", e) 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /evaluator/src/main.rs: -------------------------------------------------------------------------------- 1 | use basinix_shared::read_config; 2 | use log::{error}; 3 | use std::os::unix::net::UnixListener; 4 | 5 | fn main() -> std::io::Result<()> { 6 | let _global_config = read_config(); 7 | 8 | println!("Listening on socket"); 9 | std::fs::create_dir_all("/run/user/1000/basinix/")?; 10 | 11 | // TODO: enable some communication between rmote evaluators and main build manager 12 | // let (sender, receiver) = channel(); 13 | // thread::Builder::new() 14 | // .name("Evaluator".to_string()) 15 | // .spawn(move || { 16 | // eval_events(receiver, &global_config); 17 | // }) 18 | // .unwrap(); 19 | 20 | let listener = UnixListener::bind("/run/user/1000/basinix/evaluator.sock")?; 21 | match listener.accept() { 22 | Ok((_socket, addr)) => { 23 | println!("Got a client: {:?}", addr); 24 | } 25 | Err(e) => { 26 | error!("accept function failed: {:?}", e) 27 | } 28 | } 29 | Ok(()) 30 | } 31 | -------------------------------------------------------------------------------- /evaluator/src/pull_request.rs: -------------------------------------------------------------------------------- 1 | 2 | use basinix_shared::error::Result; 3 | use basinix_shared::github::pull_request::PullRequest; 4 | use basinix_shared::types::{BuildRequest, GlobalConfig}; 5 | 6 | use log::{debug, info}; 7 | use reqwest::blocking::Client; 8 | 9 | use std::process::Command; 10 | use std::io::{Read, BufRead, BufReader, BufWriter, Write}; 11 | 12 | use std::path::{Path, PathBuf}; 13 | use std::sync::mpsc::Sender; 14 | use std::fs::File; 15 | 16 | const LOG_TARGET: &str = "basinix::evaluator::pull_request"; 17 | 18 | // Fetches upstream, then creates a worktree for the revision. 19 | // Returns the sha of HEAD 20 | pub fn create_base_worktree_if_missing(nixpkgs_dir: &Path, base_ref: &str) -> String { 21 | // need to fetch the branch which has the commits on it 22 | Command::new("git") 23 | .current_dir(nixpkgs_dir) 24 | .args(&[ 25 | "-c", 26 | "fetch.prune=false", 27 | "fetch", 28 | "--force", 29 | "origin", 30 | &format!("{}:refs/basinix/{}", base_ref, base_ref) 31 | ]) 32 | .status() 33 | .expect("Unable to fetch base ref for nixpkgs"); 34 | 35 | let base_rev: String = std::string::String::from_utf8(Command::new("git") 36 | .current_dir(nixpkgs_dir) 37 | .args(&[ 38 | "rev-parse", 39 | &format!("origin/{}", base_ref) 40 | ]) 41 | .output() 42 | .unwrap() 43 | .stdout) 44 | .expect("Unable read from rev-parse") 45 | .trim() 46 | .to_string(); 47 | 48 | let mut worktree_dest_dir = nixpkgs_dir.parent().unwrap().to_path_buf(); 49 | worktree_dest_dir.push(&base_rev); 50 | 51 | create_worktree_if_missing(nixpkgs_dir, worktree_dest_dir.as_path(), &base_rev); 52 | 53 | base_rev 54 | } 55 | 56 | pub fn fetch_pr(nixpkgs_dir: &Path, pr_number: u64) { 57 | // need to fetch the branch which has the commits on it 58 | Command::new("git") 59 | .current_dir(nixpkgs_dir) 60 | .args(&[ 61 | "-c", 62 | "fetch.prune=false", 63 | "fetch", 64 | "--force", 65 | "https://github.com/NixOS/nixpkgs", 66 | &format!("pull/{}/head:refs/basinix/pull/{}", pr_number, pr_number) 67 | ]) 68 | .status() 69 | .unwrap_or_else(|_| panic!("Unable to fetch PR #{} for nixpkgs", pr_number)); 70 | } 71 | 72 | pub fn create_worktree_if_missing(nixpkgs_dir: &Path, worktree_dest_dir: &Path, rev: &str) { 73 | // checkout branch on a worktree, will be reused to build the derivations 74 | info!(target: LOG_TARGET, "Creating worktree at {}", worktree_dest_dir.to_str().unwrap()); 75 | if !worktree_dest_dir.exists() { 76 | Command::new("git") 77 | .current_dir(nixpkgs_dir) 78 | .args(&[ 79 | "worktree", 80 | "add", 81 | worktree_dest_dir.to_str().unwrap(), 82 | rev 83 | ]) 84 | .status() 85 | .expect("Unable to create worktree"); 86 | } else { 87 | info!(target: LOG_TARGET, "Skipping creating a worktree for {}, already exists", worktree_dest_dir.to_str().unwrap()); 88 | } 89 | } 90 | 91 | fn three_words(s: String) -> Option<(String, String, String)> { 92 | let mut words = s.split_whitespace(); 93 | let first = words.next()?; 94 | let second = words.next()?; 95 | let third = words.next()?; 96 | Some((first.to_owned(), second.to_owned(), third.to_owned())) 97 | } 98 | 99 | /// The original outputs.txt will contain ` `, split those into their own separate files 100 | fn split_output_to_separate_files(src_file: impl Read, prefix: &str, worktree_dir: &Path) { 101 | let first_words = BufReader::new(src_file) 102 | .lines() 103 | .filter_map(|line| line.map(three_words).ok().unwrap_or(None)); 104 | 105 | let attrs_file_str = format!("{}/{}_{}", worktree_dir.display(), prefix, "attrs.txt"); 106 | let drvs_file_str = format!("{}/{}_{}", worktree_dir.display(), prefix, "drvs.txt"); 107 | let output_paths_file_str = format!("{}/{}_{}", worktree_dir.display(), prefix, "output_paths.txt"); 108 | 109 | let mut attrs_file = BufWriter::new(File::create(attrs_file_str).expect("Unable to open attrs_file")); 110 | let _drvs_file = File::create(drvs_file_str); 111 | let _output_paths_file = File::create(output_paths_file_str); 112 | 113 | for (attr, _drv, _outpath) in first_words { 114 | let _sanitized_attr = attr.strip_suffix(".x86_64-linux").unwrap_or(&attr); 115 | attrs_file.write_all(attr.as_bytes()).unwrap(); 116 | attrs_file.write_all("\n".as_bytes()).unwrap(); 117 | } 118 | } 119 | 120 | pub fn eval_pr(config: &GlobalConfig, _build_sender: std::sync::mpsc::Sender, pr_number: u64, base_revs: &mut std::collections::HashMap) -> Result { 121 | 122 | let pr_info: PullRequest = get_pr_response(pr_number)?; 123 | 124 | // This is less awkward than using the PathBuf `push` paradigm 125 | let base_path = format!("{}/{}", config.worktree_dir.to_str().unwrap(), &pr_info.base.base_ref); 126 | let base_worktree_dir = std::path::Path::new(&base_path); 127 | 128 | let head_path = format!("{}/{}", config.worktree_dir.to_str().unwrap(), &pr_info.head.sha); 129 | let head_worktree_dir = Path::new(&head_path); 130 | let head_drv_outputs_str = format!("{}/{}", &head_path, "outputs.txt"); 131 | let head_drv_outputs = Path::new(&head_drv_outputs_str); 132 | let head_changed_drv_outputs_str = format!("{}/{}", &head_path, "changed_drvs.txt"); 133 | let head_changed_drv_outputs = Path::new(&head_changed_drv_outputs_str); 134 | let head_changed_attr_outputs_str = format!("{}/{}", &head_path, "changed_attrs.txt"); 135 | let _head_changed_attr_outputs = Path::new(&head_changed_attr_outputs_str); 136 | let head_old_drv_outputs_str = format!("{}/{}", &head_path, "old_drvs.txt"); 137 | let head_old_drv_outputs = Path::new(&head_old_drv_outputs_str); 138 | let head_old_attr_outputs_str = format!("{}/{}", &head_path, "old_drvs.txt"); 139 | let _head_old_attr_outputs = Path::new(&head_old_drv_outputs_str); 140 | let head_added_attr_outputs_str = format!("{}/{}", &head_path, "added_attrs.txt"); 141 | let head_added_attr_outputs = Path::new(&head_added_attr_outputs_str); 142 | let head_removed_attr_outputs_str = format!("{}/{}", &head_path, "removed_attrs.txt"); 143 | let head_removed_attr_outputs = Path::new(&head_removed_attr_outputs_str); 144 | let head_base_rev_str = format!("{}/{}", &head_path, "head_revision.txt"); 145 | let head_base_rev = Path::new(&head_base_rev_str); 146 | 147 | // create worktree for base branch if missing 148 | // Check if we need to do any work 149 | // TODO: make sha check less ugly 150 | if &pr_info.base.sha.as_str() == &base_revs.get(&pr_info.base.base_ref).unwrap_or(&"0".to_string()) { 151 | info!(target: LOG_TARGET, "Skipping checkout of {} branch, sha is the same", &pr_info.base.base_ref); 152 | } else { 153 | let base_rev = create_base_worktree_if_missing(config.nixpkgs_dir.as_path(), &pr_info.base.base_ref); 154 | base_revs.insert(pr_info.base.base_ref.to_string(), base_rev); 155 | } 156 | 157 | // create worktree for head branch if missing 158 | fetch_pr(config.nixpkgs_dir.as_path(), pr_number); 159 | create_worktree_if_missing( 160 | config.nixpkgs_dir.as_path(), 161 | head_worktree_dir, 162 | &pr_info.head.sha); 163 | create_worktree_if_missing( 164 | config.nixpkgs_dir.as_path(), 165 | base_worktree_dir, 166 | &pr_info.base.base_ref); 167 | 168 | let (base_rev, base_drv_outputs): (String, PathBuf) = query_base_outpaths(config, base_worktree_dir, &pr_info.base.base_ref)?; 169 | 170 | // query outpaths 171 | if !head_drv_outputs.exists() { 172 | query_pr_outpaths(config, head_worktree_dir, head_drv_outputs, &pr_info.base.base_ref, &base_rev)?; 173 | } 174 | 175 | // create changed derivations file 176 | if !head_changed_drv_outputs.exists() { 177 | let output_file = File::create(&head_changed_drv_outputs).unwrap_or_else(|_| panic!("Unable to write to {}", &head_changed_drv_outputs_str)); 178 | Command::new("comm") 179 | .args(&[ 180 | "-13", 181 | base_drv_outputs.to_str().unwrap(), 182 | head_drv_outputs.to_str().unwrap() 183 | ]) 184 | .stdout(output_file) 185 | .status() 186 | .unwrap(); 187 | 188 | // also write the changed attrs to a separate file 189 | let changed_drvs_file = std::fs::File::open(&head_changed_drv_outputs).unwrap_or_else(|_| panic!("Unable to read to {}", &head_changed_drv_outputs_str)); 190 | split_output_to_separate_files(&changed_drvs_file, "changed", head_worktree_dir); 191 | } else { 192 | info!(target: LOG_TARGET, "Skipping creation of {}, already exists", &head_changed_drv_outputs_str); 193 | } 194 | 195 | // create old derivations file, these will be used to determine changed builds and regressions 196 | if !head_old_drv_outputs.exists() { 197 | let output_file = File::create(&head_old_drv_outputs).unwrap_or_else(|_| panic!("Unable to write to {}", &head_old_drv_outputs_str)); 198 | Command::new("comm") 199 | .args(&[ 200 | "-23", 201 | base_drv_outputs.to_str().unwrap(), 202 | head_drv_outputs.to_str().unwrap() 203 | ]) 204 | .stdout(output_file) 205 | .status() 206 | .unwrap(); 207 | } else { 208 | info!(target: LOG_TARGET, "Skipping creation of {}, already exists", &head_changed_drv_outputs_str); 209 | } 210 | 211 | if !head_added_attr_outputs.exists() { 212 | let output_file = File::create(&head_added_attr_outputs).unwrap_or_else(|_| panic!("Unable to write to {}", &head_added_attr_outputs_str)); 213 | Command::new("comm") 214 | .args(&[ 215 | "-13", 216 | &head_old_attr_outputs_str, 217 | &head_changed_attr_outputs_str 218 | ]) 219 | .stdout(output_file) 220 | .status() 221 | .unwrap(); 222 | } else { 223 | info!(target: LOG_TARGET, "Skipping creation of {}, already exists", &head_added_attr_outputs_str); 224 | } 225 | let head_added_attr_outputs_file = BufReader::new(File::open(&head_added_attr_outputs_str).expect("Could not open file")); 226 | let head_added_attr_outputs_lines = head_added_attr_outputs_file.lines().count() as u32; 227 | 228 | if !head_removed_attr_outputs.exists() { 229 | let output_file = File::create(&head_removed_attr_outputs).unwrap_or_else(|_| panic!("Unable to write to {}", &head_removed_attr_outputs_str)); 230 | Command::new("comm") 231 | .args(&[ 232 | "-23", 233 | &head_old_attr_outputs_str, 234 | &head_changed_attr_outputs_str 235 | ]) 236 | .stdout(output_file) 237 | .status() 238 | .unwrap(); 239 | } else { 240 | info!(target: LOG_TARGET, "Skipping creation of {}, already exists", &head_removed_attr_outputs_str); 241 | } 242 | 243 | // can be used later to determine if results aren't stale 244 | if !head_base_rev.exists() { 245 | let mut output_file = File::create(&head_base_rev).unwrap_or_else(|_| panic!("Unable to write to {}", &head_base_rev_str)); 246 | output_file.write(pr_info.base.base_ref.as_bytes()) 247 | .expect("failed to write base_rev."); 248 | } else { 249 | info!(target: LOG_TARGET, "Skipping creation of {}, already exists", &head_base_rev_str); 250 | } 251 | 252 | let head_added_attr_outputs_file = BufReader::new(File::open(&head_added_attr_outputs_str).expect("Could not open file")); 253 | for maybe_line in head_added_attr_outputs_file.lines() { 254 | if let Ok(line) = maybe_line { 255 | let mut parts = line.split_whitespace(); 256 | let attr_path_with_platform = parts.next().unwrap(); 257 | let (attr, platform) = get_attr_parts(attr_path_with_platform); 258 | let drv = parts.next().unwrap(); 259 | let br = BuildRequest { 260 | platform: platform.to_string(), 261 | rev: pr_info.head.sha.to_string(), 262 | attr: attr.to_string(), 263 | drv: drv.to_string(), 264 | build_count: head_added_attr_outputs_lines 265 | }; 266 | 267 | _build_sender.send(br).expect(&format!("Unable to submit build request for {} on sha:{}", &attr, &pr_info.head.sha)); 268 | }; 269 | } 270 | 271 | // TODO: determine number of changed builds from new_drvs file 272 | Ok(head_added_attr_outputs_lines) 273 | } 274 | 275 | /// Splits an attr path into it's respective parts 276 | /// E.g. `python3Packages.requests.x86_64-linux` -> (python3Packages.requests, x86_64-linux) 277 | pub fn get_attr_parts (full_path: &str) -> (String, String) { 278 | let mut parts = full_path.split("."); 279 | 280 | let mut attr_path = parts.next().unwrap().to_owned(); 281 | let mut temp = parts.next().unwrap(); 282 | 283 | // peek at the next value, then consume the previous value accordingly 284 | if let Some(part) = parts.next() { 285 | attr_path.push_str("."); 286 | attr_path.push_str(temp); 287 | temp = part; 288 | } 289 | 290 | (attr_path.clone(), temp.to_string()) 291 | } 292 | 293 | pub fn generate_build_requests (drv_file_path: &Path, _build_sender: Sender) { 294 | let drv_file = File::open(drv_file_path).unwrap_or_else(|_| panic!("Unable to open {}", &drv_file_path.to_str().unwrap())); 295 | 296 | for line in BufReader::new(drv_file).lines() { 297 | if let Ok(str_part) = line { 298 | println!("{}", str_part); 299 | } 300 | } 301 | } 302 | 303 | fn query_base_outpaths(config: &GlobalConfig, worktree_dir: &Path, base_ref: &str) -> Result<(String, PathBuf)> { 304 | // reset directory, to avoid a previous run 305 | Command::new("git") 306 | .current_dir(worktree_dir) 307 | .args(&[ 308 | "checkout" 309 | ,"--" 310 | ,"." 311 | ]) 312 | .status()?; 313 | 314 | // bring changes from base branch into worktree dir 315 | Command::new("git") 316 | .current_dir(worktree_dir) 317 | .args(&[ 318 | "pull" 319 | ,"origin" 320 | ,base_ref 321 | ]) 322 | .status()?; 323 | 324 | let base_rev: String = std::str::from_utf8(&Command::new("git") 325 | .current_dir(worktree_dir) 326 | .args(&[ 327 | "rev-parse" 328 | ,"HEAD" 329 | ]) 330 | .output()? 331 | .stdout)? 332 | .trim() 333 | .to_owned(); 334 | 335 | let output_paths_file_str = format!("{}/{}.outputs.txt", worktree_dir.display(), &base_rev); 336 | let output_paths_file = Path::new(&output_paths_file_str); 337 | 338 | query_outpaths(config, worktree_dir, output_paths_file)?; 339 | 340 | Ok((base_rev, output_paths_file.to_path_buf())) 341 | } 342 | 343 | pub fn query_pr_outpaths(config: &GlobalConfig, worktree_dir: &Path, output_paths_file: &Path, base_ref: &str, base_rev: &str) -> Result<()> { 344 | // reset directory, to avoid a previous run 345 | debug!("Running command: PWD={} git checkout -- .", worktree_dir.display()); 346 | Command::new("git") 347 | .current_dir(worktree_dir) 348 | .args(&[ 349 | "checkout" 350 | ,"--" 351 | ,"." 352 | ]) 353 | .status()?; 354 | 355 | // ensure that the commit will be available 356 | debug!("Running command: PWD={} git fetch origin {}", worktree_dir.display(), base_ref); 357 | Command::new("git") 358 | .current_dir(worktree_dir) 359 | .args(&[ 360 | "fetch" 361 | ,"origin" 362 | ,base_ref 363 | ]) 364 | .status() 365 | .expect("failed to complete git fetch."); 366 | // bring changes from base branch into worktree dir 367 | debug!("Running command: PWD={} git merge --no-commit --no-ff {}", worktree_dir.display(), base_rev); 368 | Command::new("git") 369 | .current_dir(worktree_dir) 370 | .args(&[ 371 | "merge" 372 | ,"--no-commit" 373 | ,"--no-ff" 374 | ,base_rev 375 | ]) 376 | .status() 377 | .expect("git pull merge failed."); 378 | 379 | query_outpaths(config, worktree_dir, output_paths_file)?; 380 | Ok(()) 381 | } 382 | 383 | pub fn query_outpaths(config: &GlobalConfig, worktree_dir: &Path, output_paths_file: &Path) -> Result<()> { 384 | let output_file = File::create(&output_paths_file).unwrap_or_else(|_| panic!("Unable to write to {}", &output_paths_file.to_str().unwrap())); 385 | // This should create a file with the following contents: 386 | // . 387 | let nix_env_args = &[ 388 | "-f", 389 | config.outpaths_expression_path.to_str().unwrap(), 390 | "-qaP", 391 | "--no-name", 392 | "--out-path", 393 | "--drv-path", 394 | "--arg", 395 | "checkMeta", 396 | "true", 397 | "--arg", 398 | "path", 399 | worktree_dir.to_str().unwrap() 400 | ]; 401 | 402 | info!(target: LOG_TARGET, "Evaluating derivations for: {}", &worktree_dir.display()); 403 | debug!(target: LOG_TARGET, "Running command: nix-env {}", nix_env_args.join(" ")); 404 | let cmd1 = Command::new("nix-env") 405 | .current_dir(worktree_dir) 406 | .stdout(std::process::Stdio::piped()) 407 | .args(nix_env_args) 408 | .spawn()?; 409 | 410 | // tests.nixos-functions and tests.trivial just create noise 411 | let filter_noisy_drvs_cmd = Command::new("grep") 412 | .current_dir(worktree_dir) 413 | .stdin(cmd1.stdout.unwrap()) 414 | .stdout(std::process::Stdio::piped()) 415 | .args(&[ "-Fv", "-e", "tests.nixos-function", "-e", "tests.trivial"]) 416 | .spawn()?; 417 | 418 | Command::new("sort") 419 | .current_dir(worktree_dir) 420 | .stdin(filter_noisy_drvs_cmd.stdout.unwrap()) 421 | .stdout(output_file) 422 | .status()?; 423 | 424 | debug!(target: LOG_TARGET, "Finished running nix-env for {}.", worktree_dir.display()); 425 | Ok(()) 426 | } 427 | 428 | pub fn get_pr_response(pr_number: u64) -> Result { 429 | let request_client = Client::new(); 430 | 431 | let mut request = request_client 432 | .get(format!("https://api.github.com/repos/nixos/nixpkgs/pulls/{}", pr_number)) 433 | .header("User-Agent", "reqwest") 434 | .header("Accept", "application/vnd.github.v3+json"); 435 | 436 | if let Ok(github_token) = std::env::var("GITHUB_TOKEN") { 437 | debug!( 438 | target: LOG_TARGET, 439 | "Using github token for querying pull request #{}", pr_number 440 | ); 441 | request = request.header("Authorization", format!("token {}", github_token)); 442 | } 443 | 444 | info!(target: LOG_TARGET, "Querying PR #{}", pr_number); 445 | let body = request.send()?.text()?; 446 | Ok(serde_json::from_str::(&body)?) 447 | } 448 | 449 | // fn handle_serialization_error(body: reqwest::Body, err: serde_json::Err) { 450 | // error!( 451 | // target: LOG_TARGET, 452 | // "Unable to parse response from github to json: {:?}", err 453 | // ); 454 | // 455 | // let mut tmpfile = std::env::temp_dir(); 456 | // tmpfile.push("basinix"); 457 | // tmpfile.push("failed_json_parse"); 458 | // std::fs::create_dir_all(&tmpfile.as_path()); 459 | // tmpfile.push(format!("{}.txt", Local::now().to_rfc3339())); 460 | // let tmp_path = tmpfile.as_path(); 461 | // 462 | // error!( 463 | // target: LOG_TARGET, 464 | // "Writing contents to {}", 465 | // &tmpfile.display() 466 | // ); 467 | // std::fs::write(&tmp_path, body.as_bytes()).unwrap(); 468 | // } 469 | // 470 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1694529238, 9 | "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1728018373, 24 | "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", 25 | "owner": "nixos", 26 | "repo": "nixpkgs", 27 | "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "nixos", 32 | "ref": "nixos-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Basinix flake"; 3 | 4 | inputs = { 5 | flake-utils.url = "github:numtide/flake-utils"; 6 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 7 | }; 8 | 9 | outputs = { self, nixpkgs, flake-utils }: 10 | flake-utils.lib.eachDefaultSystem (system: 11 | let 12 | inherit (pkgs.darwin.apple_sdk.frameworks) Security; 13 | pkgs = nixpkgs.legacyPackages.${system}; 14 | devEnv = pkgs.mkShell { 15 | nativeBuildInputs = with pkgs; [ 16 | cargo 17 | rustfmt 18 | clippy 19 | elmPackages.elm 20 | pkg-config 21 | ]; 22 | buildInputs = with pkgs; [ 23 | openssl 24 | sqlite 25 | ] ++ lib.optionals stdenv.isDarwin [ Security ]; 26 | shellHook = '' 27 | test -f ~/.bashrc && source ~/.bashrc 28 | # needed for sqlx to do query! 29 | export DATABASE_URL=sqlite::memory: 30 | ''; 31 | DATABASE_URL="/var/run/user/1000/basinix/test.db"; 32 | }; 33 | in rec { 34 | defaultPackage = devEnv; 35 | devShell = devEnv; 36 | } 37 | ); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "basinix-server" 3 | version = "0.1.0" 4 | authors = ["Jonathan Ringer "] 5 | edition = "2021" 6 | description = "Continuous Integration Server for nixpkgs" 7 | repository = "https://github.com/jonringer/basinix" 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [dependencies] 12 | clap = "^2.0" 13 | chrono = "0.4" 14 | log = "0.4" 15 | env_logger = "0.8" 16 | toml = "^0.5.0" 17 | tokio = { version = "1.0", features = ["full"] } 18 | reqwest = { version = "0.11", features = ["json", "blocking"] } 19 | warp = "0.3" 20 | serde = { version = "1.0", features = ["derive"] } 21 | serde_json = "1.0" 22 | 23 | basinix_shared = { path = "../shared" } 24 | basinix_evaluator = { path = "../evaluator" } 25 | -------------------------------------------------------------------------------- /server/diesel.toml: -------------------------------------------------------------------------------- 1 | # For documentation on how to configure this file, 2 | # see diesel.rs/guides/configuring-diesel-cli 3 | 4 | [print_schema] 5 | file = "src/schema.rs" 6 | -------------------------------------------------------------------------------- /server/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonringer/basinix/add64ddb044a1bd984b993d0d3e8c34b25499574/server/migrations/.gitkeep -------------------------------------------------------------------------------- /server/migrations/2021-01-28-042303_create_projects/down.sql: -------------------------------------------------------------------------------- 1 | -- This file should undo anything in `up.sql` 2 | DROP TABLE projects 3 | -------------------------------------------------------------------------------- /server/migrations/2021-01-28-042303_create_projects/up.sql: -------------------------------------------------------------------------------- 1 | -- Your SQL goes here 2 | CREATE TABLE projects ( 3 | id INT NOT NULL PRIMARY KEY, 4 | name VARCHAR NOT NULL, 5 | url VARCHAR NOT NULL 6 | ) 7 | 8 | 9 | -------------------------------------------------------------------------------- /server/src/build_manager.rs: -------------------------------------------------------------------------------- 1 | //! Manages priority and backlog of in-queued drv builds 2 | //! 3 | //! Maintains a priority heap of builds-to-be-built, as well 4 | //! as maintains state synchronization with database. 5 | 6 | use basinix_shared::types::{BuildRequest, GlobalConfig}; 7 | use std::sync::atomic::{AtomicU64, Ordering}; 8 | use log::{info}; 9 | 10 | static BUILD_COUNT: AtomicU64 = AtomicU64::new(0); 11 | 12 | const LOG_TARGET: &str = "basinix::server::build_manager"; 13 | 14 | pub fn spawn_build_manager (config: GlobalConfig, recv: std::sync::mpsc::Receiver) { 15 | //TODO: use rayon threadpool 16 | let sleep_duration = std::time::Duration::from_secs(1); 17 | 18 | loop { 19 | let request = recv.recv() 20 | .expect("Build request channel was closed, unable to build any more derivations"); 21 | 22 | // wait until enough builds finish 23 | while BUILD_COUNT.load(Ordering::SeqCst) >= config.parallel_builds { 24 | std::thread::sleep(sleep_duration); 25 | } 26 | 27 | info!(target: LOG_TARGET, "building {}", &request.drv); 28 | 29 | let new_config = config.clone(); 30 | std::thread::Builder::new() 31 | .name(format!("Builder for {}", &request.drv)) 32 | .spawn(move || { 33 | build_drv(request, new_config); 34 | }) 35 | .unwrap(); 36 | } 37 | } 38 | 39 | fn build_drv(request: BuildRequest, config: GlobalConfig) { 40 | let worktree_dir_str = format!("{}/{}", config.worktree_dir.to_str().unwrap(), request.rev); 41 | let worktree_dir = std::path::Path::new(&worktree_dir_str); 42 | 43 | // A given drv might be part of the build closure, but might not be able 44 | // exposed through an attr. E.g. a drv declared in a let block 45 | // Use the attr to "hydrate" the store drv 46 | std::process::Command::new("nix-instantiate") 47 | .current_dir(&worktree_dir) 48 | .args(&[ "-A", &request.attr]); 49 | 50 | // Perform the "build" 51 | // TODO: Use cgroups to properly sandbox by threads 52 | info!(target: LOG_TARGET, "starting build for attr: {}, drv: {}", &request.attr, &request.drv); 53 | std::process::Command::new("nix-store") 54 | .current_dir(&worktree_dir) 55 | .args(&[ "-r", &request.drv, "--cores", &config.cores_per_build.to_string() ]); 56 | info!(target: LOG_TARGET, "finished build for attr: {}, drv: {}", &request.attr, &request.drv); 57 | 58 | BUILD_COUNT.fetch_sub(1, Ordering::SeqCst); 59 | 60 | // TODO: emit that build succeeced 61 | } -------------------------------------------------------------------------------- /server/src/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; 2 | use toml; 3 | use log::{error, info}; 4 | 5 | use basinix_shared::types::{FileConfig, GlobalConfig}; 6 | 7 | pub fn build_cli() -> App<'static, 'static> { 8 | App::new("basinix-server") 9 | .version("0.1.0") 10 | .author("Jon Ringer ") 11 | .about("Nixpkgs pr review tool") 12 | .setting(AppSettings::ColoredHelp) 13 | // make it so that completions subcommand doesn't 14 | // inherit global options 15 | .setting(AppSettings::ArgsNegateSubcommands) 16 | .after_help( 17 | "ENV VARS: 18 | 19 | GITHUB_TOKEN\tToken used during github api calls. 20 | XDG_CACHE_DIR\tDefault directory for nixpkgs and PR checkouts. 21 | 22 | EXAMPLES: 23 | 24 | # basinix server with configuration file 25 | $ basinix-server --config /etc/basinix/config.toml 26 | 27 | # explicit argument passing to basinix-server 28 | $ basinix-server --workers 5 --cores 2 --cache-dir=/var/lib/basinix/ 29 | ", 30 | ) 31 | .arg(Arg::from_usage( 32 | "-c,--config [file_path] 'File path to configuration file, use --generate-config for default example`'", 33 | )) 34 | .arg(Arg::from_usage( 35 | "--generate-config [file_path] 'Generate a configuration file with default values'", 36 | ).default_value("CHANGE")) 37 | .arg(Arg::from_usage( 38 | "-w,--workers [num] 'Number of workers to spawn as child threads, each worker will build a single derivation at-a-time'", 39 | )) 40 | .arg(Arg::from_usage( 41 | "-j,--cores [cores] 'Number of cores for each worker. Similar to --cores nix option'", 42 | )) 43 | .arg(Arg::from_usage( 44 | "--cache-dir [directory] 'Directory used for nixpkgs and pr worktrees'", 45 | )) 46 | .subcommand( 47 | SubCommand::with_name("completions") 48 | .about("Generate shell completion scripts, writes to stdout") 49 | .arg( 50 | Arg::from_usage("") 51 | .case_insensitive(true) 52 | .possible_values(&clap::Shell::variants()), 53 | ), 54 | ) 55 | } 56 | 57 | pub fn read_args( 58 | matches: &ArgMatches 59 | ) -> GlobalConfig { 60 | let file_config: FileConfig = match matches.value_of("config_file") { 61 | Some(file_path) => { 62 | match toml::from_str(&std::fs::read_to_string(file_path).unwrap()) { 63 | Ok(config) => { 64 | // good config 65 | config 66 | }, 67 | Err(e) => { 68 | error!("Unable to read config, at {}", e); 69 | std::process::exit(1); 70 | } 71 | } 72 | }, 73 | None => { 74 | info!("No configuration file passed, checking other arguments"); 75 | 76 | if let Some(cache_dir) = matches.value_of("cache-dir") { 77 | FileConfig { cache_dir: Some(cache_dir.to_string()) } 78 | } else { 79 | info!("No configuration file or cache dir was passed, defaulting to XDG_CACHE_DIR"); 80 | FileConfig { cache_dir: None } 81 | } 82 | } 83 | }; 84 | 85 | GlobalConfig::new(&file_config) 86 | // TODO: override with explicitly passed options 87 | } 88 | -------------------------------------------------------------------------------- /server/src/github_producer.rs: -------------------------------------------------------------------------------- 1 | use basinix_shared::github::repo_events::{Action, Event, EventType}; 2 | use basinix_shared::types::Message::{self, EvalPullRequest, EvalPush, PullRequestClosed}; 3 | use basinix_shared::types::{PullRequestInfo, PushInfo}; 4 | use chrono::Local; 5 | use log::{debug, error, info}; 6 | use reqwest::blocking::{Client, Response}; 7 | use std::collections::HashSet; 8 | use std::sync::mpsc::Sender; 9 | use std::thread::sleep; 10 | use std::time::Duration; 11 | 12 | const LOG_TARGET: &str = "basinix::server::github_polling"; 13 | 14 | fn gh_event_to_eval_event(gh_event: Event) -> Option { 15 | match gh_event.event_type { 16 | EventType::PullRequestEvent => match gh_event.payload.action.unwrap() { 17 | Action::Closed => Some(PullRequestClosed(gh_event.payload.number.unwrap())), 18 | _ => Some(EvalPullRequest(PullRequestInfo { 19 | number: gh_event.payload.number.unwrap(), 20 | base_branch: gh_event.payload.pull_request.unwrap().base.base_ref, 21 | })), 22 | }, 23 | EventType::PushEvent => Some(EvalPush(PushInfo { 24 | push_ref: gh_event.payload.payload_ref.unwrap(), 25 | before: gh_event.payload.before.unwrap(), 26 | head: gh_event.payload.head.unwrap(), 27 | })), 28 | _ => None, 29 | } 30 | } 31 | 32 | pub fn produce_github_pr_events(sender: Sender) { 33 | let mut sleep_seconds = 5; 34 | let request_client = Client::new(); 35 | 36 | let mut past_events: HashSet = HashSet::with_capacity(1000); 37 | 38 | loop { 39 | let mut request = request_client 40 | .get("https://api.github.com/repos/nixos/nixpkgs/events?per_page=100") 41 | .header("User-Agent", "reqwest") 42 | .header("Accept", "application/vnd.github.v3+json"); 43 | 44 | if let Ok(github_token) = std::env::var("GITHUB_TOKEN") { 45 | debug!(target: LOG_TARGET, "Using github token for polling events"); 46 | request = request.header("Authorization", format!("token {}", github_token)); 47 | } 48 | 49 | info!(target: LOG_TARGET, "Polling github activity"); 50 | match request.send() { 51 | Ok(response) => { 52 | let events = serialize_and_filter_events(response, &mut past_events); 53 | 54 | // Adjust polling rate based on successful retrievals 55 | // These rates will also only reflect push events, so the number of new 56 | // events may be much less than the total pay load 57 | if events.len() < 5 { 58 | debug!( 59 | target: LOG_TARGET, 60 | "Only {} new events returned. Doubling current sleep time of {}s", 61 | events.len(), 62 | sleep_seconds 63 | ); 64 | // TODO: Configure max wait time between polls 65 | sleep_seconds = std::cmp::min(sleep_seconds * 2, 300); 66 | } else if events.len() > 15 { 67 | debug!( 68 | target: LOG_TARGET, 69 | "More than 15 new events returned. Halving sleep time {}", sleep_seconds 70 | ); 71 | // TODO: Configure minimum time between polls 72 | sleep_seconds = std::cmp::max(sleep_seconds / 2, 5); 73 | } 74 | 75 | // send events to evaluator 76 | for event in events { 77 | sender.send(gh_event_to_eval_event(event) 78 | .expect("Unable to serialize event")) 79 | .expect("Unable to send eval event to evaluation consumer"); 80 | } 81 | } 82 | Err(err) => { 83 | error!("Error attempting to contact github: {}", err); 84 | } 85 | } 86 | debug!(target: LOG_TARGET, "Sleeping for {} seconds", sleep_seconds); 87 | sleep(Duration::from_secs(sleep_seconds)); 88 | } 89 | } 90 | 91 | fn serialize_and_filter_events(response: Response, past_events: &mut HashSet) -> Vec { 92 | match response.text() { 93 | Ok(body) => { 94 | match serde_json::from_str::>(&body) { 95 | Ok(parsed_json) => { 96 | debug!( 97 | target: LOG_TARGET, 98 | "Successfully queried {} values", 99 | parsed_json.len() 100 | ); 101 | let commit_changes = parsed_json.into_iter().filter(|event| { 102 | event.event_type == EventType::PushEvent 103 | || event.event_type == EventType::PullRequestEvent 104 | }); 105 | let (old_events, new_events): (Vec, Vec) = commit_changes 106 | .partition(|event| past_events.contains(&event.id.parse::().unwrap())); 107 | 108 | // TODO: configure this value 109 | // Only the last 100 events are really useful, using 1000 just to avoid cache 110 | // churn 111 | if past_events.len() > 800 { 112 | debug!(target: LOG_TARGET, "Clearing old event cache"); 113 | past_events.clear(); 114 | old_events.iter().for_each(|event| { 115 | past_events.insert(event.id.parse::().unwrap()); 116 | }); 117 | } 118 | 119 | new_events.iter().for_each(|event| { 120 | past_events.insert(event.id.parse::().unwrap()); 121 | }); 122 | debug!(target: LOG_TARGET, "Old events: {}", old_events.len()); 123 | debug!(target: LOG_TARGET, "New events: {}", new_events.len()); 124 | return new_events; 125 | } 126 | Err(err) => { 127 | error!( 128 | target: LOG_TARGET, 129 | "Unable to parse response from github to json: {:?}", err 130 | ); 131 | 132 | let mut tmpfile = std::env::temp_dir(); 133 | tmpfile.push("basinix"); 134 | tmpfile.push("failed_json_parse"); 135 | std::fs::create_dir_all(&tmpfile.as_path()).unwrap_or_else(|_| panic!("Unable to create directory {:?}", 136 | &tmpfile.as_path())); 137 | tmpfile.push(format!("{}.txt", Local::now().to_rfc3339())); 138 | let tmppath = tmpfile.as_path(); 139 | 140 | error!( 141 | target: LOG_TARGET, 142 | "Writing contents to {}", 143 | &tmpfile.display() 144 | ); 145 | std::fs::write(&tmppath, body.as_bytes()).unwrap(); 146 | } 147 | } 148 | } 149 | Err(err) => { 150 | error!("Unable to parse response from github: {:?}", err); 151 | } 152 | } 153 | 154 | Vec::::new() 155 | } 156 | -------------------------------------------------------------------------------- /server/src/main.rs: -------------------------------------------------------------------------------- 1 | use warp::Filter; 2 | use std::sync::mpsc; 3 | use log::{debug, info}; 4 | use std::thread; 5 | mod github_producer; 6 | use github_producer::produce_github_pr_events; 7 | use basinix_shared::read_config; 8 | use basinix_shared::types::{BuildRequest, GlobalConfig, Message}; 9 | use chrono::Local; 10 | use std::io::Write; 11 | use basinix_evaluator::eval_events; 12 | 13 | extern crate serde; 14 | 15 | pub mod models; 16 | pub mod cli; 17 | 18 | mod build_manager; 19 | 20 | const LOG_TARGET: &str = "basinix::server::main"; 21 | 22 | #[tokio::main] 23 | async fn main() { 24 | env_logger::Builder::from_default_env() 25 | .format(|buf, record| { 26 | writeln!(buf, 27 | "[{}] {:5} - {} - {}", 28 | Local::now().to_rfc3339(), 29 | record.level(), 30 | record.target(), 31 | record.args() 32 | ) 33 | }).init(); 34 | 35 | 36 | let _m = cli::build_cli().get_matches(); 37 | 38 | let global_config: GlobalConfig = read_config(); 39 | std::mem::forget(read_config()); 40 | 41 | debug!(target: LOG_TARGET, "Creating databse connection pool"); 42 | let pool = basinix_shared::db::create_connection_pool().await.expect("Unable to create database pool."); 43 | debug!(target: LOG_TARGET, "Checking if database needs to be initialized"); 44 | basinix_shared::db::init_database(&pool).await.expect("Unable to create database."); 45 | 46 | let (tx, rx) = mpsc::channel::(); 47 | let (build_request_sender, build_request_receiver) = mpsc::channel::(); 48 | 49 | // TODO: Allow for evaluator to exist on another machine 50 | info!(target: LOG_TARGET, "Starting evaluation thread"); 51 | let eval_config = global_config.clone(); 52 | thread::Builder::new().name("Evalutor".to_string()).spawn(move|| { 53 | eval_events(rx, build_request_sender, eval_config); 54 | }).unwrap(); 55 | 56 | info!(target: LOG_TARGET, "Starting github polling thread"); 57 | thread::Builder::new() 58 | .name("github_producer".to_string()) 59 | .spawn(move|| { 60 | produce_github_pr_events(tx); 61 | }).unwrap(); 62 | 63 | let bm_config = global_config.clone(); 64 | thread::Builder::new() 65 | .name("build_manager".to_string()) 66 | .spawn(move|| { 67 | build_manager::spawn_build_manager(bm_config, build_request_receiver); 68 | }).unwrap(); 69 | 70 | // GET /hello/warp => 200 OK with body "Hello, warp!" 71 | let hello = warp::path!("hello" / String) 72 | .map(|name| format!("Hello, {}!", name)); 73 | 74 | warp::serve(hello) 75 | .run(([127, 0, 0, 1], 3030)) 76 | .await 77 | } 78 | -------------------------------------------------------------------------------- /server/src/models.rs: -------------------------------------------------------------------------------- 1 | use serde::Serialize; 2 | 3 | #[derive(Serialize)] 4 | pub struct Project { 5 | pub id: i32, 6 | pub title: String, 7 | pub url: String, 8 | } 9 | -------------------------------------------------------------------------------- /shared/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "basinix_shared" 3 | version = "0.1.0" 4 | authors = [ 5 | "Jonathan Ringer ", 6 | ] 7 | edition = "2018" 8 | description = "Shared dependencies between the server and workers" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | bincode = "1.3.1" 14 | log = "0.4" 15 | reqwest = { workspace = true } 16 | serde = { version = "1.0", features = ["derive"] } 17 | serde_json = { workspace = true } 18 | sqlx = { version = "0.8", features = [ "sqlite", "runtime-tokio-rustls" ] } 19 | lazy_static = "1.4" 20 | dirs = "^3.0" 21 | derive_more = "0.99.17" 22 | -------------------------------------------------------------------------------- /shared/src/db.rs: -------------------------------------------------------------------------------- 1 | pub mod models; 2 | 3 | use log::info; 4 | use std::env; 5 | 6 | const LOG_TARGET: &str = "basinix::shared::db"; 7 | 8 | use sqlx::Executor; 9 | 10 | pub async fn init_database(pool: &sqlx::Pool) -> Result<(), sqlx::Error> { 11 | let branch_table = 12 | sqlx::query!("SELECT name FROM sqlite_master WHERE type='table' AND name='branches';") 13 | .fetch_one(pool) 14 | .await; 15 | match branch_table { 16 | Ok(_) => { 17 | info!(target: LOG_TARGET, "Database has already been initialized"); 18 | Ok(()) 19 | } 20 | Err(_) => { 21 | info!(target: LOG_TARGET, "Initializing database"); 22 | let sql_initialization = include_str!("db/sql/up.sql"); 23 | pool.execute(sql_initialization) 24 | .await 25 | .expect("Unable to initial database."); 26 | info!(target: LOG_TARGET, "Database initialized"); 27 | Ok(()) 28 | } 29 | } 30 | } 31 | 32 | pub async fn create_connection_pool() -> Result, sqlx::Error> { 33 | let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); 34 | 35 | if database_url != "sqlite::memory:" { 36 | let db_path = std::path::Path::new(&database_url); 37 | if !db_path.exists() { 38 | info!( 39 | target: LOG_TARGET, 40 | "{} not found, creating new database", 41 | db_path.to_str().unwrap() 42 | ); 43 | if !db_path.parent().unwrap().is_dir() { 44 | std::fs::create_dir_all(db_path.parent().unwrap()) 45 | .expect("Unable to write to create database directory"); 46 | } 47 | std::fs::File::create(db_path).expect(&format!( 48 | "Unable to create database at {}", 49 | db_path.to_str().unwrap() 50 | )); 51 | } 52 | } 53 | 54 | info!(target: LOG_TARGET, "Creating database connection pool"); 55 | sqlx::sqlite::SqlitePoolOptions::new() 56 | .max_connections(5u32) 57 | .connect(&database_url) 58 | .await 59 | } 60 | -------------------------------------------------------------------------------- /shared/src/db/models.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | // For nixpkgs base branches. E.g. master, staging, or staging-next 4 | #[derive(sqlx::FromRow, Debug, PartialEq, Serialize, Deserialize)] 5 | struct Branch { 6 | id: u64, 7 | title: String, 8 | } 9 | 10 | // Build status of a derivation 11 | #[derive(Debug, PartialEq, Serialize, Deserialize)] 12 | enum BuildStatus { 13 | Unknown, 14 | Queued, 15 | InProgress, 16 | Failed, 17 | Success, 18 | } 19 | 20 | #[derive(sqlx::FromRow, Debug, PartialEq, Serialize, Deserialize)] 21 | struct Commit { 22 | rev_hash: String, 23 | branch_id: Option, 24 | pull_request_id: Option, 25 | } 26 | 27 | #[derive(sqlx::FromRow, Debug, PartialEq, Serialize, Deserialize)] 28 | struct Drv { 29 | id: u64, 30 | drv_path: String, 31 | attr: String, // An attr path which can be used to "hydra" the drv 32 | previous_drv: Option, 33 | platform_id: u32, 34 | commit_rev_hash: String, 35 | build_status_id: BuildStatus, 36 | } 37 | 38 | #[derive(sqlx::FromRow, Debug, PartialEq, Serialize, Deserialize)] 39 | struct Platform { 40 | id: u32, 41 | platform: String, 42 | } 43 | 44 | #[derive(sqlx::FromRow, Debug, PartialEq, Serialize, Deserialize)] 45 | struct PullRequest { 46 | id: u64, // same as pull request number 47 | } 48 | -------------------------------------------------------------------------------- /shared/src/db/sql/down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE drvs; 2 | 3 | DROP TABLE platforms; 4 | 5 | DROP TABLE build_status; 6 | 7 | DROP TABLE pr_commits; 8 | 9 | DROP TABLE pull_requests; 10 | 11 | DROP TABLE branches; 12 | 13 | DROP TABLE commits; -------------------------------------------------------------------------------- /shared/src/db/sql/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE commits ( 2 | rev_hash VARCHAR NOT NULL PRIMARY KEY 3 | ); 4 | 5 | CREATE TABLE branches ( 6 | id NOT NULL PRIMARY KEY, 7 | title VARCHAR NOT NULL, 8 | head_rev VARCHAR NOT NULL, 9 | FOREIGN KEY (head_rev) 10 | REFERENCES commits(rev_hash) 11 | ); 12 | 13 | CREATE TABLE pull_requests ( 14 | id INT NOT NULL PRIMARY KEY, 15 | head_rev VARCHAR NOT NULL, 16 | base_branch_id INT NOT NULL, 17 | base_rev VARCHAR NOT NULL, -- Revision which review was performed against 18 | pr_review_status INT NOT NULL, -- e.g. In Progress, Queued 19 | FOREIGN KEY (head_rev) 20 | REFERENCES commits(rev_hash), 21 | FOREIGN KEY (base_branch_id) 22 | REFERENCES commits(rev_hash) 23 | FOREIGN KEY (pr_review_status) 24 | REFERENCES commits(rev_hash) 25 | ); 26 | 27 | -- This will be used for determing if queued jobs should be removed 28 | -- as commits that no longer exist should be removed, as well as 29 | -- related queued builds 30 | CREATE TABLE pr_commits ( 31 | id INT NOT NULL PRIMARY KEY, 32 | pull_request_id INT NOT NULL, 33 | commit_rev VARCHAR NOT NULL 34 | ); 35 | 36 | CREATE TABLE event_status ( 37 | id INT NOT NULL PRIMARY KEY, 38 | title VARCHAR NOT NULL -- e.g. Unknown, Queued, Success, Failed 39 | ); 40 | 41 | CREATE TABLE platforms ( 42 | id INT NOT NULL PRIMARY KEY, 43 | platform VARCHAR NOT NULL -- e.g. x86_64-linux 44 | ); 45 | 46 | CREATE TABLE build_status ( 47 | id INT NOT NULL PRIMARY KEY, 48 | status_name VARCHAR NOT NULL -- e.g. Queued, Success, Failed 49 | ); 50 | 51 | CREATE TABLE pr_status ( 52 | id INT NOT NULL PRIMARY KEY, 53 | status_name VARCHAR NOT NULL 54 | ); 55 | 56 | CREATE TABLE drvs ( 57 | drv_path VARCHAR NOT NULL PRIMARY KEY, -- e.g. kmgpsrjdqs4f1j8i46nm3yrg72140063-python3-3.8.8 in /nix/store/kmgpsrjdqs4f1j8i46nm3yrg72140063-python3-3.8.8.drv 58 | attribute VARCHAR NOT NULL, -- e.g. python38 59 | previous_drv VARCHAR NULL, -- e.g. yi9ndyp3pps70mw1kasiv6zaqgrmi057-python3-3.8.8 60 | platform_id INT NOT NULL, -- e.g. x86_64-linux 61 | commit_rev_hash VARCHAR NOT NULL, -- e.g. 0120f5e5b58e88b783b8149ed271a002e19babd3 62 | build_status_id INT NOT NULL, -- e.g. Unknown, Queued, Success, Failed 63 | FOREIGN KEY (commit_rev_hash) 64 | REFERENCES commits(rev_hash), 65 | FOREIGN KEY (platform_id) 66 | REFERENCES platforms(id), 67 | FOREIGN KEY (previous_drv) 68 | REFERENCES drvs(drv_path), 69 | FOREIGN KEY (build_status_id) 70 | REFERENCES build_status(id) 71 | ); 72 | 73 | INSERT INTO build_status 74 | VALUES 75 | (1, 'Unknown'), 76 | (2, 'Queued'), 77 | (3, 'In Progress'), 78 | (4, 'Success'), 79 | (5, 'Failed'); 80 | 81 | INSERT INTO pr_status 82 | VALUES 83 | (1, 'Unknown'), 84 | (2, 'Queued'), 85 | (3, 'In Progress'), 86 | (4, 'Closed'), 87 | (5, 'Success'), 88 | (6, 'Failed'); -------------------------------------------------------------------------------- /shared/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{str::Utf8Error, error::Error as StdError, fmt, process::ExitStatus}; 2 | 3 | use log::error; 4 | use reqwest; 5 | use derive_more::{From, Display}; 6 | 7 | pub type Result = std::result::Result; 8 | 9 | #[allow(dead_code)] 10 | trait ErrorLog { 11 | fn log_if_error(&self); 12 | } 13 | 14 | impl ErrorLog for Result { 15 | fn log_if_error(&self) { 16 | if let Err(e) = &self { 17 | error!("{}", e); 18 | } 19 | } 20 | } 21 | 22 | #[derive(Debug, derive_more::Error, From, Display)] 23 | pub enum Error { 24 | IoError(std::io::Error), 25 | ReqwestError(reqwest::Error), 26 | SerdeJson(serde_json::Error), 27 | Utf8Error(Utf8Error), 28 | Basinix(BasinixError), 29 | } 30 | 31 | /// Basinix-specific Errors 32 | #[derive(From)] 33 | pub struct BasinixError { 34 | inner: Box, 35 | } 36 | 37 | pub(crate) type BoxError = Box; 38 | 39 | struct Inner { 40 | kind: Kind, 41 | source: Option, 42 | } 43 | 44 | impl BasinixError { 45 | pub(crate) fn new(kind: Kind, source: Option) -> BasinixError 46 | where 47 | E: Into 48 | { 49 | BasinixError { 50 | inner: Box::new(Inner { 51 | kind, 52 | source: source.map(|e| e.into()), 53 | }), 54 | } 55 | } 56 | } 57 | 58 | impl fmt::Debug for BasinixError { 59 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 60 | let mut builder = f.debug_struct("basinix::shared::Error"); 61 | 62 | builder.field("kind", &self.inner.kind); 63 | 64 | if let Some(ref message) = self.inner.source { 65 | builder.field("message", message); 66 | } 67 | 68 | builder.finish() 69 | } 70 | } 71 | 72 | impl fmt::Display for BasinixError { 73 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 74 | match self.inner.kind { 75 | Kind::GitError => f.write_str("git error")?, 76 | Kind::ProcessError(exit_status) => f.write_str(&format!("process error: {}", exit_status))?, 77 | }; 78 | 79 | if let Some(ref e) = self.inner.source { 80 | write!(f, ": {}", e)?; 81 | } 82 | 83 | Ok(()) 84 | } 85 | } 86 | 87 | #[derive(Debug)] 88 | pub(crate) enum Kind { 89 | GitError, 90 | ProcessError(ExitStatus), 91 | } 92 | 93 | impl StdError for BasinixError { 94 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 95 | self.inner.source.as_ref().map(|e| &**e as _) 96 | } 97 | } 98 | 99 | // constructors 100 | 101 | pub fn git_error>(e: E) -> BasinixError { 102 | BasinixError::new(Kind::GitError, Some(e)) 103 | } 104 | 105 | pub fn process_error(exit_status: ExitStatus) -> BasinixError { 106 | BasinixError::new(Kind::ProcessError(exit_status), None::) 107 | } 108 | -------------------------------------------------------------------------------- /shared/src/eval_events.rs: -------------------------------------------------------------------------------- 1 | // A commit is the commit id 2 | pub type Commit = String; 3 | // E.g. #110430 4 | pub type PullRequestNum = u32; 5 | 6 | #[derive(Debug)] 7 | pub enum EvalRequest { 8 | PullRequestOpened(PullRequestNum), 9 | PushEvent(PullRequestNum), 10 | } 11 | -------------------------------------------------------------------------------- /shared/src/github.rs: -------------------------------------------------------------------------------- 1 | pub mod pull_request; 2 | pub mod repo_events; 3 | 4 | pub use repo_events::*; -------------------------------------------------------------------------------- /shared/src/github/pull_request.rs: -------------------------------------------------------------------------------- 1 | // Example code that deserializes and serializes the model. 2 | // extern crate serde; 3 | // #[macro_use] 4 | // extern crate serde_derive; 5 | // extern crate serde_json; 6 | // 7 | // use generated_module::[object Object]; 8 | // 9 | // fn main() { 10 | // let json = r#"{"answer": 42}"#; 11 | // let model: [object Object] = serde_json::from_str(&json).unwrap(); 12 | // } 13 | 14 | use serde; 15 | use serde::{Deserialize, Serialize}; 16 | use serde_json; 17 | 18 | #[derive(Serialize, Deserialize)] 19 | pub struct PullRequest { 20 | #[serde(rename = "url")] 21 | url: String, 22 | 23 | #[serde(rename = "id")] 24 | id: i64, 25 | 26 | #[serde(rename = "number")] 27 | number: i64, 28 | 29 | #[serde(rename = "state")] 30 | state: String, 31 | 32 | #[serde(rename = "locked")] 33 | locked: Option, 34 | 35 | #[serde(rename = "title")] 36 | title: String, 37 | 38 | #[serde(rename = "user")] 39 | user: User, 40 | 41 | #[serde(rename = "closed_at")] 42 | closed_at: Option, 43 | 44 | #[serde(rename = "merged_at")] 45 | merged_at: Option, 46 | 47 | #[serde(rename = "merge_commit_sha")] 48 | merge_commit_sha: Option, 49 | 50 | #[serde(rename = "assignee")] 51 | assignee: Option, 52 | 53 | #[serde(rename = "assignees")] 54 | assignees: Vec>, 55 | 56 | #[serde(rename = "requested_reviewers")] 57 | requested_reviewers: Vec, 58 | 59 | #[serde(rename = "requested_teams")] 60 | requested_teams: Vec>, 61 | 62 | #[serde(rename = "labels")] 63 | labels: Vec