tool for me to use if i drop nixos
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

derivation and builder stuff

IamPyu b22f4e0c 097bf4c2

+686 -13
+354 -2
Cargo.lock
··· 15 15 checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" 16 16 17 17 [[package]] 18 + name = "block-buffer" 19 + version = "0.12.0" 20 + source = "registry+https://github.com/rust-lang/crates.io-index" 21 + checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" 22 + dependencies = [ 23 + "hybrid-array", 24 + ] 25 + 26 + [[package]] 18 27 name = "cfg-if" 19 28 version = "1.0.4" 20 29 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 36 45 ] 37 46 38 47 [[package]] 48 + name = "const-oid" 49 + version = "0.10.2" 50 + source = "registry+https://github.com/rust-lang/crates.io-index" 51 + checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" 52 + 53 + [[package]] 54 + name = "cpufeatures" 55 + version = "0.3.0" 56 + source = "registry+https://github.com/rust-lang/crates.io-index" 57 + checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" 58 + dependencies = [ 59 + "libc", 60 + ] 61 + 62 + [[package]] 63 + name = "crypto-common" 64 + version = "0.2.1" 65 + source = "registry+https://github.com/rust-lang/crates.io-index" 66 + checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" 67 + dependencies = [ 68 + "hybrid-array", 69 + ] 70 + 71 + [[package]] 39 72 name = "demeter" 40 73 version = "0.1.0" 74 + dependencies = [ 75 + "deo", 76 + "dmx", 77 + "hex", 78 + "log", 79 + "serde", 80 + "sha2", 81 + "shlex", 82 + "tempfile", 83 + "thiserror", 84 + ] 41 85 42 86 [[package]] 43 87 name = "deo" ··· 48 92 ] 49 93 50 94 [[package]] 95 + name = "digest" 96 + version = "0.11.2" 97 + source = "registry+https://github.com/rust-lang/crates.io-index" 98 + checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" 99 + dependencies = [ 100 + "block-buffer", 101 + "const-oid", 102 + "crypto-common", 103 + ] 104 + 105 + [[package]] 51 106 name = "dirs" 52 107 version = "6.0.0" 53 108 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 76 131 "indexmap", 77 132 "rustyline", 78 133 "serde", 134 + "serde_json", 79 135 "strum", 80 136 "thiserror", 81 137 ] ··· 109 165 checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" 110 166 111 167 [[package]] 168 + name = "fastrand" 169 + version = "2.3.0" 170 + source = "registry+https://github.com/rust-lang/crates.io-index" 171 + checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 172 + 173 + [[package]] 112 174 name = "fd-lock" 113 175 version = "4.0.4" 114 176 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 120 182 ] 121 183 122 184 [[package]] 185 + name = "foldhash" 186 + version = "0.1.5" 187 + source = "registry+https://github.com/rust-lang/crates.io-index" 188 + checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 189 + 190 + [[package]] 123 191 name = "getrandom" 124 192 version = "0.2.17" 125 193 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 131 199 ] 132 200 133 201 [[package]] 202 + name = "getrandom" 203 + version = "0.4.2" 204 + source = "registry+https://github.com/rust-lang/crates.io-index" 205 + checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" 206 + dependencies = [ 207 + "cfg-if", 208 + "libc", 209 + "r-efi", 210 + "wasip2", 211 + "wasip3", 212 + ] 213 + 214 + [[package]] 215 + name = "hashbrown" 216 + version = "0.15.5" 217 + source = "registry+https://github.com/rust-lang/crates.io-index" 218 + checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 219 + dependencies = [ 220 + "foldhash", 221 + ] 222 + 223 + [[package]] 134 224 name = "hashbrown" 135 225 version = "0.16.1" 136 226 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 143 233 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 144 234 145 235 [[package]] 236 + name = "hex" 237 + version = "0.4.3" 238 + source = "registry+https://github.com/rust-lang/crates.io-index" 239 + checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 240 + 241 + [[package]] 146 242 name = "home" 147 243 version = "0.5.12" 148 244 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 152 248 ] 153 249 154 250 [[package]] 251 + name = "hybrid-array" 252 + version = "0.4.8" 253 + source = "registry+https://github.com/rust-lang/crates.io-index" 254 + checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" 255 + dependencies = [ 256 + "typenum", 257 + ] 258 + 259 + [[package]] 260 + name = "id-arena" 261 + version = "2.3.0" 262 + source = "registry+https://github.com/rust-lang/crates.io-index" 263 + checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" 264 + 265 + [[package]] 155 266 name = "indexmap" 156 267 version = "2.13.0" 157 268 source = "registry+https://github.com/rust-lang/crates.io-index" 158 269 checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" 159 270 dependencies = [ 160 271 "equivalent", 161 - "hashbrown", 272 + "hashbrown 0.16.1", 162 273 "serde", 163 274 "serde_core", 164 275 ] 276 + 277 + [[package]] 278 + name = "itoa" 279 + version = "1.0.18" 280 + source = "registry+https://github.com/rust-lang/crates.io-index" 281 + checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" 282 + 283 + [[package]] 284 + name = "leb128fmt" 285 + version = "0.1.0" 286 + source = "registry+https://github.com/rust-lang/crates.io-index" 287 + checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" 165 288 166 289 [[package]] 167 290 name = "libc" ··· 230 353 ] 231 354 232 355 [[package]] 356 + name = "once_cell" 357 + version = "1.21.4" 358 + source = "registry+https://github.com/rust-lang/crates.io-index" 359 + checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" 360 + 361 + [[package]] 233 362 name = "option-ext" 234 363 version = "0.2.0" 235 364 source = "registry+https://github.com/rust-lang/crates.io-index" 236 365 checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 237 366 238 367 [[package]] 368 + name = "prettyplease" 369 + version = "0.2.37" 370 + source = "registry+https://github.com/rust-lang/crates.io-index" 371 + checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" 372 + dependencies = [ 373 + "proc-macro2", 374 + "syn", 375 + ] 376 + 377 + [[package]] 239 378 name = "proc-macro2" 240 379 version = "1.0.106" 241 380 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 254 393 ] 255 394 256 395 [[package]] 396 + name = "r-efi" 397 + version = "6.0.0" 398 + source = "registry+https://github.com/rust-lang/crates.io-index" 399 + checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" 400 + 401 + [[package]] 257 402 name = "radix_trie" 258 403 version = "0.2.1" 259 404 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 269 414 source = "registry+https://github.com/rust-lang/crates.io-index" 270 415 checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" 271 416 dependencies = [ 272 - "getrandom", 417 + "getrandom 0.2.17", 273 418 "libredox", 274 419 "thiserror", 275 420 ] ··· 310 455 ] 311 456 312 457 [[package]] 458 + name = "semver" 459 + version = "1.0.27" 460 + source = "registry+https://github.com/rust-lang/crates.io-index" 461 + checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" 462 + 463 + [[package]] 313 464 name = "serde" 314 465 version = "1.0.228" 315 466 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 340 491 ] 341 492 342 493 [[package]] 494 + name = "serde_json" 495 + version = "1.0.149" 496 + source = "registry+https://github.com/rust-lang/crates.io-index" 497 + checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" 498 + dependencies = [ 499 + "itoa", 500 + "memchr", 501 + "serde", 502 + "serde_core", 503 + "zmij", 504 + ] 505 + 506 + [[package]] 507 + name = "sha2" 508 + version = "0.11.0" 509 + source = "registry+https://github.com/rust-lang/crates.io-index" 510 + checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" 511 + dependencies = [ 512 + "cfg-if", 513 + "cpufeatures", 514 + "digest", 515 + ] 516 + 517 + [[package]] 518 + name = "shlex" 519 + version = "1.3.0" 520 + source = "registry+https://github.com/rust-lang/crates.io-index" 521 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 522 + 523 + [[package]] 343 524 name = "smallvec" 344 525 version = "1.15.1" 345 526 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 378 559 ] 379 560 380 561 [[package]] 562 + name = "tempfile" 563 + version = "3.27.0" 564 + source = "registry+https://github.com/rust-lang/crates.io-index" 565 + checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" 566 + dependencies = [ 567 + "fastrand", 568 + "getrandom 0.4.2", 569 + "once_cell", 570 + "rustix", 571 + "windows-sys 0.61.2", 572 + ] 573 + 574 + [[package]] 381 575 name = "thiserror" 382 576 version = "2.0.18" 383 577 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 398 592 ] 399 593 400 594 [[package]] 595 + name = "typenum" 596 + version = "1.19.0" 597 + source = "registry+https://github.com/rust-lang/crates.io-index" 598 + checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" 599 + 600 + [[package]] 401 601 name = "unicode-ident" 402 602 version = "1.0.24" 403 603 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 416 616 checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" 417 617 418 618 [[package]] 619 + name = "unicode-xid" 620 + version = "0.2.6" 621 + source = "registry+https://github.com/rust-lang/crates.io-index" 622 + checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 623 + 624 + [[package]] 419 625 name = "utf8parse" 420 626 version = "0.2.2" 421 627 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 428 634 checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 429 635 430 636 [[package]] 637 + name = "wasip2" 638 + version = "1.0.2+wasi-0.2.9" 639 + source = "registry+https://github.com/rust-lang/crates.io-index" 640 + checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" 641 + dependencies = [ 642 + "wit-bindgen", 643 + ] 644 + 645 + [[package]] 646 + name = "wasip3" 647 + version = "0.4.0+wasi-0.3.0-rc-2026-01-06" 648 + source = "registry+https://github.com/rust-lang/crates.io-index" 649 + checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" 650 + dependencies = [ 651 + "wit-bindgen", 652 + ] 653 + 654 + [[package]] 655 + name = "wasm-encoder" 656 + version = "0.244.0" 657 + source = "registry+https://github.com/rust-lang/crates.io-index" 658 + checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" 659 + dependencies = [ 660 + "leb128fmt", 661 + "wasmparser", 662 + ] 663 + 664 + [[package]] 665 + name = "wasm-metadata" 666 + version = "0.244.0" 667 + source = "registry+https://github.com/rust-lang/crates.io-index" 668 + checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" 669 + dependencies = [ 670 + "anyhow", 671 + "indexmap", 672 + "wasm-encoder", 673 + "wasmparser", 674 + ] 675 + 676 + [[package]] 677 + name = "wasmparser" 678 + version = "0.244.0" 679 + source = "registry+https://github.com/rust-lang/crates.io-index" 680 + checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" 681 + dependencies = [ 682 + "bitflags", 683 + "hashbrown 0.15.5", 684 + "indexmap", 685 + "semver", 686 + ] 687 + 688 + [[package]] 431 689 name = "windows-link" 432 690 version = "0.2.1" 433 691 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 588 846 version = "0.53.1" 589 847 source = "registry+https://github.com/rust-lang/crates.io-index" 590 848 checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 849 + 850 + [[package]] 851 + name = "wit-bindgen" 852 + version = "0.51.0" 853 + source = "registry+https://github.com/rust-lang/crates.io-index" 854 + checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" 855 + dependencies = [ 856 + "wit-bindgen-rust-macro", 857 + ] 858 + 859 + [[package]] 860 + name = "wit-bindgen-core" 861 + version = "0.51.0" 862 + source = "registry+https://github.com/rust-lang/crates.io-index" 863 + checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" 864 + dependencies = [ 865 + "anyhow", 866 + "heck", 867 + "wit-parser", 868 + ] 869 + 870 + [[package]] 871 + name = "wit-bindgen-rust" 872 + version = "0.51.0" 873 + source = "registry+https://github.com/rust-lang/crates.io-index" 874 + checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" 875 + dependencies = [ 876 + "anyhow", 877 + "heck", 878 + "indexmap", 879 + "prettyplease", 880 + "syn", 881 + "wasm-metadata", 882 + "wit-bindgen-core", 883 + "wit-component", 884 + ] 885 + 886 + [[package]] 887 + name = "wit-bindgen-rust-macro" 888 + version = "0.51.0" 889 + source = "registry+https://github.com/rust-lang/crates.io-index" 890 + checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" 891 + dependencies = [ 892 + "anyhow", 893 + "prettyplease", 894 + "proc-macro2", 895 + "quote", 896 + "syn", 897 + "wit-bindgen-core", 898 + "wit-bindgen-rust", 899 + ] 900 + 901 + [[package]] 902 + name = "wit-component" 903 + version = "0.244.0" 904 + source = "registry+https://github.com/rust-lang/crates.io-index" 905 + checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" 906 + dependencies = [ 907 + "anyhow", 908 + "bitflags", 909 + "indexmap", 910 + "log", 911 + "serde", 912 + "serde_derive", 913 + "serde_json", 914 + "wasm-encoder", 915 + "wasm-metadata", 916 + "wasmparser", 917 + "wit-parser", 918 + ] 919 + 920 + [[package]] 921 + name = "wit-parser" 922 + version = "0.244.0" 923 + source = "registry+https://github.com/rust-lang/crates.io-index" 924 + checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" 925 + dependencies = [ 926 + "anyhow", 927 + "id-arena", 928 + "indexmap", 929 + "log", 930 + "semver", 931 + "serde", 932 + "serde_derive", 933 + "serde_json", 934 + "unicode-xid", 935 + "wasmparser", 936 + ] 937 + 938 + [[package]] 939 + name = "zmij" 940 + version = "1.0.21" 941 + source = "registry+https://github.com/rust-lang/crates.io-index" 942 + checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+2
Cargo.toml
··· 13 13 deo = { version = "0.1.0", path = "crates/deo" } 14 14 15 15 nix = { version = "0.31.2", features = ["hostname", "user"] } 16 + sha2 = "0.11.0" 16 17 log = "0.4.29" 17 18 thiserror = "2.0.18" 18 19 anyhow = "1.0.102" 19 20 serde = "1.0.228" 21 + serde_json = "1.0.149" 20 22 regex = "1.12.3" 21 23 clap = { version = "4.6.0", features = ["derive"] } 22 24 bytes = "1.11.1"
+1 -1
README.md
··· 1 1 # demeter 2 2 3 3 <!-- TODO: include doc link for definition of package wrapping --> 4 - [package wrapping](), system configuration, dotfiles management all in one. 4 + declarative (but not exactly reproducable) [package wrapping](), system configuration, dotfiles management all in one. 5 5 6 6 heavily inspired by [Nix](https://nixos.org)
+13 -1
crates/demeter/Cargo.toml
··· 2 2 name = "demeter" 3 3 version = "0.1.0" 4 4 edition.workspace = true 5 - license.workspace = true 5 + license.workspace = true 6 + 7 + [dependencies] 8 + deo.workspace = true 9 + dmx.workspace = true 10 + serde = { workspace = true, features = ["derive"] } 11 + sha2.workspace = true 12 + hex = "0.4.3" 13 + tempfile = "3.27.0" 14 + log.workspace = true 15 + thiserror.workspace = true 16 + shlex = "1.3.0" 17 +
+101
crates/demeter/src/derivation.rs
··· 1 + use sha2::Digest; 2 + use std::{io, path::PathBuf, process::Command}; 3 + 4 + pub mod builders; 5 + 6 + /// Similar to a Nix Derivation 7 + #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] 8 + #[serde(rename = "kebab-case")] 9 + pub struct Derivation { 10 + pub name: String, 11 + pub builder: String, 12 + pub arguments: Vec<String>, 13 + } 14 + 15 + impl Derivation { 16 + pub fn get_hash(&self) -> String { 17 + let hash256 = sha2::Sha256::new() 18 + .chain_update(&self.name) 19 + .chain_update(&self.builder) 20 + .chain_update(self.arguments.join("")) 21 + .finalize(); 22 + hex::encode(hash256) 23 + } 24 + 25 + pub fn get_hash_name(&self) -> String { 26 + let hash = self.get_hash(); 27 + let name = &self.name; 28 + format!("{hash}-{name}") 29 + } 30 + 31 + pub fn get_store_path(&self) -> PathBuf { 32 + let store = deo::get_path(deo::Path::Store); 33 + store.join(self.get_hash_name()) 34 + } 35 + 36 + pub fn run_derivation(&self) -> Result<(), DerivationError> { 37 + let dir = tempfile::TempDir::with_prefix_in( 38 + format!("{}", self.get_hash_name()), 39 + deo::get_path(deo::Path::Builder), 40 + )?; 41 + log::info!("building derivation: {}", self.name); 42 + 43 + let output = Command::new(self.builder.clone()) 44 + .current_dir(dir.path()) 45 + .env("out", self.get_store_path()) 46 + .env("HOME", "/homeless") 47 + .args(self.arguments.clone()) 48 + .spawn()? 49 + .wait_with_output()?; 50 + dir.close()?; 51 + 52 + if !output.status.success() { 53 + Err(io::Error::new(io::ErrorKind::Other, "derivation build failed").into()) 54 + } else { 55 + Ok(()) 56 + } 57 + } 58 + } 59 + 60 + impl ToString for Derivation { 61 + fn to_string(&self) -> String { 62 + format!("{}", self.get_store_path().display()) 63 + } 64 + } 65 + 66 + pub trait IntoDerivation<'de>: serde::Serialize + serde::Deserialize<'de> { 67 + fn into_derivation(self) -> Result<Derivation, DerivationError>; 68 + } 69 + 70 + impl<'de> IntoDerivation<'de> for Derivation { 71 + fn into_derivation(self) -> Result<Derivation, DerivationError> { 72 + Ok(self) 73 + } 74 + } 75 + 76 + #[derive(Debug, thiserror::Error)] 77 + pub enum DerivationError { 78 + #[error("{0}")] 79 + IO(#[from] io::Error), 80 + #[error("shell quote error: {0}")] 81 + QuoteError(#[from] shlex::QuoteError), 82 + #[error("{0}")] 83 + Custom(String), 84 + } 85 + 86 + #[cfg(test)] 87 + mod tests { 88 + use super::*; 89 + 90 + #[test] 91 + fn derivation_hash() { 92 + let d = Derivation { 93 + name: "script".to_owned(), 94 + builder: "bash".to_owned(), 95 + arguments: vec!["-c".to_owned(), "echo hi > $out".to_owned()], 96 + }; 97 + d.get_hash(); 98 + 99 + println!("{}", d.get_store_path().display()); 100 + } 101 + }
+139
crates/demeter/src/derivation/builders.rs
··· 1 + use std::collections::HashMap; 2 + 3 + use super::{Derivation, DerivationError, IntoDerivation}; 4 + 5 + #[derive(serde::Serialize, serde::Deserialize)] 6 + #[serde(rename = "kebab-case")] 7 + pub struct WriteText { 8 + pub name: String, 9 + pub text: String, 10 + } 11 + 12 + impl<'de> IntoDerivation<'de> for WriteText { 13 + fn into_derivation(self) -> Result<Derivation, DerivationError> { 14 + let escaped = shlex::try_quote(&self.text)?; 15 + let drv = Derivation { 16 + name: self.name, 17 + builder: "sh".to_owned(), 18 + arguments: vec!["-c".to_owned(), format!("printf {escaped} > $out")], 19 + }; 20 + 21 + Ok(drv) 22 + } 23 + } 24 + 25 + #[derive(serde::Serialize, serde::Deserialize)] 26 + #[serde(rename = "kebab-case")] 27 + pub struct WriteShell { 28 + pub name: String, 29 + pub text: String, 30 + // dependency executable names 31 + pub depends: Vec<String>, 32 + } 33 + 34 + impl<'de> IntoDerivation<'de> for WriteShell { 35 + fn into_derivation(self) -> Result<Derivation, DerivationError> { 36 + let paths = 37 + deo::split_paths().ok_or(DerivationError::Custom("could not split PATH".to_owned()))?; 38 + let depends_fulfilled = self 39 + .depends 40 + .iter() 41 + .map(|s| deo::find_exec(&paths, &s)) 42 + .all(|o| o.is_some()); 43 + if !depends_fulfilled { 44 + return Err(DerivationError::Custom(format!( 45 + "some dependencies not fulfilled, required executables: {:?}", 46 + &self.depends 47 + ))); 48 + } 49 + 50 + let src = format!("#!/bin/sh\n{}", self.text); 51 + let script = shlex::try_quote(&src)?; 52 + 53 + let drv = Derivation { 54 + name: self.name, 55 + builder: "sh".to_owned(), 56 + arguments: vec![ 57 + "-c".to_owned(), 58 + format!("printf {} > $out\nchmod +x $out", script), 59 + ], 60 + }; 61 + Ok(drv) 62 + } 63 + } 64 + 65 + #[derive(serde::Serialize, serde::Deserialize)] 66 + #[serde(rename = "kebab-case")] 67 + pub struct WrapProgram { 68 + pub name: String, 69 + pub bin_name: String, 70 + pub env: HashMap<String, String>, 71 + pub args: Vec<String>, 72 + } 73 + 74 + impl<'de> IntoDerivation<'de> for WrapProgram { 75 + fn into_derivation(self) -> Result<Derivation, DerivationError> { 76 + let env: String = self 77 + .env 78 + .into_iter() 79 + .map(|(k, v)| format!("export {k}={}", shlex::try_quote(&v).expect("nul"))) 80 + .fold(String::new(), |acc, s| format!("{acc}\n{s}")); 81 + let args = shlex::try_join(self.args.iter().map(|s| s.as_str()))?; 82 + let paths = 83 + deo::split_paths().ok_or(DerivationError::Custom("failed to get path".to_owned()))?; 84 + let exec = deo::find_exec(&paths, &self.bin_name).ok_or(DerivationError::Custom( 85 + "failed to find executable to wrap".to_owned(), 86 + ))?; 87 + 88 + let src = format!("{env}\n{} {args}", exec.display()); 89 + 90 + let drv = WriteShell { 91 + name: self.name, 92 + text: src, 93 + depends: vec![], 94 + } 95 + .into_derivation()?; 96 + Ok(drv) 97 + } 98 + } 99 + 100 + #[cfg(test)] 101 + mod tests { 102 + use super::*; 103 + 104 + #[test] 105 + fn write_text() { 106 + let builder = WriteText { 107 + name: "hello".to_owned(), 108 + text: "random text 'file' <3".to_string(), 109 + }; 110 + let drv = builder.into_derivation().unwrap(); 111 + println!("{drv:?}"); 112 + println!("{}", drv.get_store_path().display()); 113 + } 114 + 115 + #[test] 116 + fn write_shell() { 117 + let builder = WriteShell { 118 + name: "cpfiles".to_owned(), 119 + text: "cp $@".to_owned(), 120 + depends: vec!["cp".to_owned()], 121 + }; 122 + let drv = builder.into_derivation().unwrap(); 123 + println!("{drv:?}"); 124 + println!("{}", drv.get_store_path().display()); 125 + } 126 + 127 + #[test] 128 + fn wrap_program() { 129 + let builder = WrapProgram { 130 + name: "hello".to_owned(), 131 + bin_name: "nvim".to_owned(), 132 + args: vec!["--clean".to_owned()], 133 + env: HashMap::from([("NVIM_APPNAME".to_owned(), "custom-nvim".to_owned())]), 134 + }; 135 + let drv = builder.into_derivation().unwrap(); 136 + println!("{drv:?}"); 137 + println!("{}", drv.get_store_path().display()); 138 + } 139 + }
+2
crates/demeter/src/lib.rs
··· 1 + pub mod derivation; 2 + pub mod wrappers;
+2
crates/demeter/src/main.rs
··· 1 + extern crate demeter; 2 + 1 3 fn main() { 2 4 println!("hello"); 3 5 }
+9
crates/demeter/src/wrappers.rs
··· 1 + use std::collections::HashMap; 2 + 3 + #[derive(serde::Serialize, serde::Deserialize)] 4 + #[serde(rename = "kebab-case")] 5 + pub struct Wrapper { 6 + pub bin_name: String, 7 + pub env: HashMap<String, String>, 8 + pub args: Vec<String>, 9 + }
+18 -4
crates/deo/src/lib.rs
··· 1 - use std::{env, ffi::OsString, path::PathBuf, sync::LazyLock}; 1 + use std::{ 2 + env, 3 + ffi::OsString, 4 + path::{self, PathBuf}, 5 + sync::LazyLock, 6 + }; 2 7 3 8 pub fn is_root() -> bool { 4 9 nix::unistd::getuid().is_root() 5 10 } 6 11 7 - pub const DEMETER_DIR: &str = "/var/lib/demeter"; 12 + pub const DEMETER_DIR: &str = "/var/demeter"; 8 13 9 14 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] 10 15 pub enum Path { 11 16 /// [DEMETER_DIR] 12 17 #[default] 13 18 Root, 14 - /// Binary path 19 + /// Binary path (/bin) 15 20 Bin, 16 - /// Store path 21 + /// Store path (/store) 17 22 Store, 23 + /// Builder path /build 24 + Builder, 18 25 } 19 26 20 27 pub fn get_path(p: Path) -> PathBuf { ··· 24 31 Path::Root => root, 25 32 Path::Bin => root.join("bin"), 26 33 Path::Store => root.join("store"), 34 + Path::Builder => root.join("builder"), 27 35 } 28 36 } 29 37 ··· 49 57 pub fn join_paths() -> Option<OsString> { 50 58 env::join_paths(split_paths()?).ok() 51 59 } 60 + 61 + pub fn find_exec<P: AsRef<path::Path>>(path: &[P], exec: &str) -> Option<PathBuf> { 62 + path.iter() 63 + .find(|p| p.as_ref().join(exec).exists()) 64 + .map(|p| p.as_ref().join(exec)) 65 + }
+3 -2
crates/dmx/Cargo.toml
··· 5 5 license.workspace = true 6 6 7 7 [dependencies] 8 - serde = { workspace = true, optional = true } 8 + serde = { workspace = true, optional = true, features = ["derive", "rc"] } 9 + serde_json = { workspace = true, optional = true } 9 10 indexmap.workspace = true 10 11 strum.workspace = true 11 12 thiserror.workspace = true ··· 14 15 15 16 [features] 16 17 default = [] 17 - serde = ["dep:serde", "serde/derive", "indexmap/serde"] 18 + serde = ["dep:serde", "dep:serde_json", "indexmap/serde"]
+42 -3
crates/dmx/src/value.rs
··· 8 8 pub type Int = i64; 9 9 pub type Float = f64; 10 10 11 + /// dmx types are similar enough to JSON types. 12 + #[cfg(feature = "serde")] 13 + pub use serde_json as ser; 14 + 11 15 /// Map 12 - pub type Map<K, V> = IndexMap<K, V>; 16 + pub type Map = IndexMap<String, ExprRef>; 13 17 14 18 #[derive(Debug, Clone, PartialEq)] 15 19 pub struct Func { ··· 51 55 52 56 /// Dynamic Expression 53 57 #[derive(Default, Debug, Clone, PartialEq)] 58 + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 59 + #[cfg_attr(feature = "serde", serde(untagged))] 54 60 pub enum Expr { 55 61 #[default] 56 62 Nil, 57 63 Bool(bool), 58 64 Int(Int), 59 65 Float(Float), 60 - Symbol(crate::scope::Symbol), 61 66 String(String), 67 + Symbol(crate::scope::Symbol), 62 68 List(Vec<Arc<Expr>>), 63 - Map(Map<String, Arc<Expr>>), 69 + Map(Map), 64 70 Quote(Arc<Expr>), 71 + #[cfg_attr(feature = "serde", serde(skip))] 65 72 Function(Func), 73 + #[cfg_attr(feature = "serde", serde(skip))] 66 74 PrimOp(PrimOp), 75 + #[cfg_attr(feature = "serde", serde(skip))] 67 76 Macro(Macro), 68 77 } 69 78 ··· 229 238 self.type_of().as_str() 230 239 } 231 240 } 241 + 242 + #[cfg(test)] 243 + mod tests { 244 + use super::*; 245 + 246 + #[cfg(feature = "serde")] 247 + #[test] 248 + fn deserialize() { 249 + #[derive(Debug, serde::Serialize, serde::Deserialize)] 250 + struct Person { 251 + name: String, 252 + age: u64, 253 + } 254 + 255 + let expr = Expr::Map(IndexMap::from([ 256 + ( 257 + "name".to_owned(), 258 + Arc::new(Expr::String("hello".to_owned())), 259 + ), 260 + ("age".to_owned(), Arc::new(Expr::Int(32))), 261 + ])); 262 + let val = ser::to_value(expr).unwrap(); 263 + 264 + let p: Person = ser::from_value(val).unwrap(); 265 + println!("{p:?}"); 266 + 267 + let expr: Expr = ser::from_value(ser::to_value(p).unwrap()).unwrap(); 268 + println!("{expr}"); 269 + } 270 + }