difftreelog
feat remowt integration
46 files changed
Cargo.lockdiffbeforeafterboth576 packageslockfile v4
Might be heavy and slow!
adler2
2.0.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefaused byaead
0.5.2crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0depends onaead
0.6.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumef60ac202874e574ce7a7158cc8bca7313dd344322482e4fadee288bf4a306b8depends onaes
0.8.4crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0depends onused byaes
0.9.1crates.io↘ 4↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138aes-gcm
0.10.3crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1used byaes-gcm
0.11.0-rc.4crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumda8c919c118108f144adecad74b425b804ad075580d605d9b33c2d6d1c62a2f8used byage
0.11.3crates.io↘ 29↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma07d86e4272c093c88caf7864a2d09af52a5159180848ca4832a3cdbd7d014d5depends on- aes
0.8.4 - aes-gcm
0.10.3 - age-core
0.11.0 - base64
0.21.7 - bcrypt-pbkdf
0.10.0 - bech32
0.9.1 - cbc
0.1.2 - chacha20poly1305
0.10.1 - cipher
0.4.4 - cookie-factory
0.3.3 - ctr
0.9.2 - curve25519-dalek
4.1.3 - hmac
0.12.1 - i18n-embed
0.15.4 - i18n-embed-fl
0.9.4 - lazy_static
1.5.0 - nom
7.1.3 - num-traits
0.2.19 - pin-project
1.1.13 - rand
0.8.6 - rsa
0.9.10 - rust-embed
8.11.0 - scrypt
0.11.0 - sha2
0.10.9 - subtle
2.6.1 - which
4.4.2 - wsl
0.1.0 - x25519-dalek
2.0.1 - zeroize
1.9.0
- aes
age-core
0.11.0crates.io↘ 10↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume2bf6a89c984ca9d850913ece2da39e1d200563b0a94b002b253beee4c5acf99depends onused byaho-corasick
1.1.4crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301depends onandroid_system_properties
0.1.5crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311depends onused byanstream
1.0.0crates.io↘ 7↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28ddepends onanstyle
1.0.14crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000anstyle-parse
1.0.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130edepends onused byanstyle-query
1.1.5crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadcdepends onused byanstyle-wincon
3.0.11crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747dused byanyhow
1.0.102crates.io↘ 0↖ 18sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842cused by- fleet
0.2.0 - fleet-base
0.1.0 - fleet-generator-helper
0.1.0 - fleet-install-secrets
0.1.0 - nix-eval
0.1.0 - prost-derive
0.14.4 - remowt-client
0.1.7 - remowt-endpoints
0.1.7 - remowt-fleet
0.1.0 - remowt-plugin
0.1.7 - remowt-plugin-fleet
0.1.0 - remowt-ui-prompt
0.1.7 - wasm-metadata
0.244.0 - wit-bindgen-core
0.51.0 - wit-bindgen-rust
0.51.0 - wit-bindgen-rust-macro
0.51.0 - wit-component
0.244.0 - wit-parser
0.244.0
- fleet
arc-swap
1.9.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207depends onused byargon2
0.6.0-rc.8crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7af50940b73bf4e16c15c448a2b121c63f2d68e3e54b6a8731673cb4aa0cdff5used byasync_fn_traits
0.1.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbc58d489c5f2d2c5be31b9004cec7af25a70d23df4d8111715eee736234cf217depends onused byasync-broadcast
0.7.2crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532used byasync-channel
2.5.0crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2async-executor
1.14.0crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812adepends onused byasync-io
2.6.0crates.io↘ 10↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fcdepends onasync-lock
3.4.2crates.io↘ 3↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311async-process
2.5.0crates.io↘ 10↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75depends onused byasync-recursion
1.1.1crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11depends onused byasync-signal
0.2.14crates.io↘ 10↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485depends onused byasync-task
4.7.1crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3deasync-trait
0.1.89crates.io↘ 3↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbbdepends onatomic-waker
1.1.2crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0autocfg
1.5.1crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53base16ct
1.0.0crates.io↘ 0↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6base64
0.21.7crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567used bybase64
0.22.1crates.io↘ 0↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6base64ct
1.8.3crates.io↘ 0↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06basic-toml
0.1.10crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178adepends onused bybcrypt-pbkdf
0.10.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2depends onused bybcrypt-pbkdf
0.11.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum144e573728da132683b9488acd528274c790e07fc06ff81ee29f9d8f8b1041e0depends onused bybifrostlink
0.2.6crates.io↘ 11↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2fb01af731c11dd31b23783a83a36a29f644cc1972481f6fa4f4fabc709079ebdepends onbifrostlink-macros
0.2.6crates.io↘ 3↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8c4b7a5fb38b36bd81910c17ebf369f9296e508d92b1277a768a63c8a2254fdbdepends onbifrostlink-ports
0.2.6crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum977acfcb8ed3c24ab7c2f76fb3eeebff1533c72708733ce6020f2501980b7cf2bindgen
0.72.1crates.io↘ 12↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895depends onused bybitflags
2.13.0crates.io↘ 0↖ 14sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8blake2
0.11.0-rc.6crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum061f1a09225e328e1ffbb378d2d49923c0ca5fee19fb5ac1cc9c1e9d52b93690depends onused byblock-buffer
0.10.4crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71depends onused byblock-buffer
0.12.1crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aadepends onused byblock-padding
0.3.3crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93depends onused byblock-padding
0.4.2crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068bdepends onused byblocking
1.6.2crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21used byblowfish
0.9.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7depends onused byblowfish
0.10.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum62ce3946557b35e71d1bbe07ec385073ce9eda05043f95de134eb578fcf1a298depends onused bybstr
1.12.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cabdepends onused bybumpalo
3.20.3crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649bytecount
0.6.9crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365eused bybyteorder
1.5.0crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64bbytes
1.11.1crates.io↘ 0↖ 23sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33used by- bifrostlink
0.2.6 - bifrostlink-ports
0.2.6 - h2
0.4.14 - http
1.4.2 - http-body
1.0.1 - http-body-util
0.1.3 - hyper
1.10.1 - hyper-util
0.1.20 - opentelemetry-http
0.31.0 - pageant
0.2.1 - prost
0.14.4 - quinn
0.11.9 - quinn-proto
0.11.14 - remowt-client
0.1.7 - remowt-link-shared
0.1.7 - reqwest
0.12.28 - russh
0.61.2 - ssh-encoding
0.3.0-rc.9 - tokio
1.52.3 - tokio-util
0.7.18 - tonic
0.14.6 - tonic-prost
0.14.6 - tower-http
0.6.11
- bifrostlink
camino
1.2.2crates.io↘ 1↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48depends oncbc
0.1.2crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6depends onused bycbc
0.2.1crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896depends oncc
1.2.64crates.io↘ 2↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501fdepends oncexpr
0.6.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766depends onused bycfg_aliases
0.2.1crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724cfg-if
1.0.4crates.io↘ 0↖ 29sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801used by- aes
0.8.4 - async-io
2.6.0 - async-process
2.5.0 - async-signal
0.2.14 - chacha20
0.9.1 - chacha20
0.10.0 - const-hex
1.19.1 - crc32fast
1.5.0 - curve25519-dalek
4.1.3 - curve25519-dalek
5.0.0-rc.0 - getrandom
0.2.17 - getrandom
0.3.4 - getrandom
0.4.2 - hostname
0.4.2 - js-sys
0.3.102 - keccak
0.2.0 - libloading
0.8.9 - nix
0.31.3 - parking_lot_core
0.9.12 - polling
3.11.0 - polyval
0.6.2 - ring
0.17.14 - salsa20
0.11.0 - scrypt
0.12.0 - sha1
0.11.0 - sha2
0.10.9 - sha2
0.11.0 - thread_local
1.1.9 - wasm-bindgen
0.2.125
- aes
chacha20
0.9.1crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818depends onused bychacha20
0.10.0crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601chacha20poly1305
0.10.1crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35used bychrono
0.4.45crates.io↘ 6↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327depends oncipher
0.4.4crates.io↘ 3↖ 9sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3daddepends oncipher
0.5.2crates.io↘ 4↖ 10sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6cclang-sys
1.8.1crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4depends onused byclap
4.6.1crates.io↘ 2↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51depends onclap_builder
4.6.0crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069fdepends onused byclap_complete
4.6.5crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume0a7a9bfdb35811f9e59832f0f05975114d2251b415fb534108e6f34060fd772depends onused byclap_derive
4.6.1crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9used byclap_lex
1.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9used bycmov
0.5.4crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027aused bycodespan-reporting
0.13.1crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumaf491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681colorchoice
1.0.5crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570used byconcurrent-queue
2.5.0crates.io↘ 1↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973depends onconsole
0.16.3crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87used byconst-hex
1.19.1crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558used byconst-oid
0.9.6crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8const-oid
0.10.2crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55ccookie-factory
0.3.3crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2depends onused bycore-foundation
0.10.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6depends onused bycore-foundation-sys
0.8.7crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888bcpubits
0.1.1crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06aecpufeatures
0.2.17crates.io↘ 1↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280depends oncpufeatures
0.3.0crates.io↘ 1↖ 9sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201depends oncrc32fast
1.5.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511depends onused bycrossbeam-utils
0.8.21crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28used bycrypto-bigint
0.7.3crates.io↘ 9↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum42a0d26b245348befa0c121944541476763dcc46ede886c88f9d12e1697d27c3depends oncrypto-common
0.1.7crates.io↘ 3↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60acrypto-common
0.2.2crates.io↘ 3↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453crypto-primes
0.7.2crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3633a51a39c69ebbaa4feaa694bd83d241e4093901c84a0963b19d9bb3f0cf8fdepends onused byctr
0.9.2crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835depends onused byctr
0.10.1crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbaaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21depends onctutils
0.4.2crates.io↘ 2↖ 10sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29edepends oncursor-icon
1.2.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732fused bycurve25519-dalek
4.1.3crates.io↘ 8↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2bedepends oncurve25519-dalek
5.0.0-rc.0crates.io↘ 8↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4f359e08ca85e7bd759e1fd933ff2bccd81864c60a8fba0e259c7f822b0924bfdepends oncurve25519-dalek-derive
0.1.1crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3depends oncxx
1.0.194crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum747d8437319e3a2f43d93b341c137927ca70c0f5dabeea7a005a73665e247c7edepends onused bycxx-build
1.0.194crates.io↘ 7↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb0f4697d190a142477b16aef7da8a99bfdc41e7e8b1687583c0d23a79c7afc1edepends onused bycxxbridge-cmd
1.0.194crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd0956799fa8678d4c50eed028f2de1c0552ae183c76e976cf7ca8c4e36a7c328used bycxxbridge-flags
1.0.194crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum23384a836ab4f0ad98ace7e3955ad2de39de42378ab487dc28d3990392cb283aused bycxxbridge-macro
1.0.194crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume6acc6b5822b9526adfb4fc377b67128fdd60aac757cc4a741a6278603f763cfused bydata-encoding
2.11.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8used bydelegate
0.13.5crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum780eb241654bf097afb00fc5f054a09b687dad862e485fdcf8399bb056565370depends onused byder
0.7.10crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcbdepends onder
0.8.0crates.io↘ 3↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411bderanged
0.5.8crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211cused byderivative
2.2.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770bdepends onused bydes
0.9.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum916a94e407b54f9034d71dd748234cd1e516ced6284009906ae246f177eafe5adepends onused bydigest
0.10.7crates.io↘ 4↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292digest
0.11.3crates.io↘ 4↖ 13sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2displaydoc
0.2.6crates.io↘ 3↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4fdepends onecdsa
0.17.0-rc.18crates.io↘ 7↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum54fb064faabbee66e1fc8e5c5a9458d4269dc2d8b638fe86a425adb2510d1a96depends oned25519
2.2.3crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53depends onused byed25519
3.0.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980adepends onused byed25519-dalek
2.2.0crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9used byed25519-dalek
3.0.0-rc.0crates.io↘ 8↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb011170fe4f04665565b4110afef66774fe9ffff278f3eb5b81cc73d26e27d60depends oneither
1.16.0crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679eelliptic-curve
0.14.0-rc.33crates.io↘ 15↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum102d3643d30dd8b559613c5cced68317199597fffb278cdc88daa2ef7fafc935depends onencode_unicode
1.0.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0used byendi
1.1.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099used byenum_dispatch
0.3.13crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumaa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecdused byenumflags2
0.7.12crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecefdepends onused byenumflags2_derive
0.7.12crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827depends onused byenv_filter
1.0.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eefdepends onused byenv_logger
0.11.10crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56aused byequivalent
1.0.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0fused byerrno
0.3.14crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efebdepends onevent-listener
5.4.1crates.io↘ 3↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856abevent-listener-strategy
0.5.4crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93fastrand
2.4.1crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6ff
0.14.0crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489fdepends onfiat-crypto
0.2.9crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811dused byfiat-crypto
0.3.0crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24find-crate
0.6.3crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2depends onfind-msvc-tools
0.1.9crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582used byflate2
1.1.9crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573cdepends onused byfleet
0.2.0workspace↘ 25↖ 0depends on- anyhow
1.0.102 - camino
1.2.2 - clap
4.6.1 - clap_complete
4.6.5 - fleet-base
0.1.0 - futures
0.3.32 - human-repr
1.1.0 - indicatif
0.18.4 - itertools
0.14.0 - nix-eval
0.1.0 - opentelemetry
0.31.0 - opentelemetry-appender-tracing
0.31.1 - opentelemetry-exporter-env
0.1.0 - opentelemetry_sdk
0.31.0 - remowt-fleet
0.1.0 - serde
1.0.228 - serde_json
1.0.150 - shlex
1.3.0 - tabled
0.20.0 - tempfile
3.27.0 - tokio
1.52.3 - tracing
0.1.44 - tracing-indicatif
0.3.14 - tracing-opentelemetry
0.32.1 - tracing-subscriber
0.3.23
- anyhow
fleet-base
0.1.0workspace↘ 26↖ 2depends on- age
0.11.3 - anyhow
1.0.102 - camino
1.2.2 - chrono
0.4.45 - clap
4.6.1 - fleet-shared
0.1.0 - futures
0.3.32 - hostname
0.4.2 - indoc
2.0.7 - itertools
0.14.0 - nix-eval
0.1.0 - nixlike
0.1.0 - nom
8.0.0 - rand
0.10.1 - remowt-client
0.1.7 - remowt-endpoints
0.1.7 - remowt-fleet
0.1.0 - remowt-link-shared
0.1.7 - remowt-ui-prompt
0.1.7 - serde
1.0.228 - serde_json
1.0.150 - tabled
0.20.0 - tempfile
3.27.0 - time
0.3.49 - tokio
1.52.3 - tracing
0.1.44
- age
fleet-generator-helper
0.1.0workspace↘ 12↖ 0fleet-install-secrets
0.1.0workspace↘ 10↖ 0fluent
0.16.1crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555adepends onfluent-bundle
0.15.3crates.io↘ 8↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493depends onused byfluent-langneg
0.13.1crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0depends onfluent-syntax
0.11.1crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33ddepends onfnv
1.0.7crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1used byfoldhash
0.1.5crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2used byfoldhash
0.2.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdbused byform_urlencoded
1.2.2crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcfdepends onfutures
0.3.32crates.io↘ 7↖ 9sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382ddepends onfutures-channel
0.3.32crates.io↘ 2↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1ddepends onfutures-core
0.3.32crates.io↘ 0↖ 19sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1dused by- async-broadcast
0.7.2 - async-channel
2.5.0 - async-signal
0.2.14 - futures
0.3.32 - futures-channel
0.3.32 - futures-executor
0.3.32 - futures-lite
2.6.1 - futures-util
0.3.32 - h2
0.4.14 - http-body-util
0.1.3 - hyper
1.10.1 - opentelemetry
0.31.0 - ordered-stream
0.2.0 - reqwest
0.12.28 - sync_wrapper
1.0.2 - tokio-stream
0.1.18 - tokio-util
0.7.18 - tower
0.5.3 - zbus
5.16.0
- async-broadcast
futures-executor
0.3.32crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbaf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579dfutures-io
0.3.32crates.io↘ 0↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718futures-lite
2.6.1crates.io↘ 5↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44adfutures-macro
0.3.32crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447bdepends onused byfutures-sink
0.3.32crates.io↘ 0↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893futures-task
0.3.32crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393futures-util
0.3.32crates.io↘ 9↖ 8sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6depends ongeneric-array
0.14.7crates.io↘ 2↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9adepends ongeneric-array
1.4.3crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc2e55f16dcf0e9c00efbe2e655ffe45fc98e7066b52bc92f8a79e64060a79351used bygetrandom
0.2.17crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0used bygetrandom
0.3.4crates.io↘ 6↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fdgetrandom
0.4.2crates.io↘ 8↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555depends onghash
0.5.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1depends onused byghash
0.6.0crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5depends onglob
0.3.3crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280used byglobset
0.4.18crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3used bygroup
0.14.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4depends onused byh2
0.4.14crates.io↘ 11↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733depends onused byhashbrown
0.15.5crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1depends onused byhashbrown
0.17.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84aused byheck
0.5.0crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55eahermit-abi
0.5.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849cused byhex
0.4.3crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70hex-literal
1.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1used byhkdf
0.12.4crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7depends onused byhkdf
0.13.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018depends onused byhmac
0.12.1crates.io↘ 1↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5edepends onhmac
0.13.0crates.io↘ 1↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863fdepends onhome
0.5.12crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728ddepends onused byhostname
0.4.2crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbddepends onused byhttp
1.4.2crates.io↘ 2↖ 11sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425depends onhttp-body
1.0.1crates.io↘ 2↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184depends onhttp-body-util
0.1.3crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64aused byhttparse
1.10.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87used byhuman-repr
1.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf58b778a5761513caf593693f8951c97a5b610841e754788400f32102eefdff1used byhybrid-array
0.4.12crates.io↘ 4↖ 9sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857dahyper
1.10.1crates.io↘ 13↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498depends onhyper-rustls
0.27.9crates.io↘ 8↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0fdepends onused byhyper-timeout
0.5.2crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0used byhyper-util
0.1.20crates.io↘ 15↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0depends oni18n-config
0.4.8crates.io↘ 6↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3e06b90c8a0d252e203c94344b21e35a30f3a3a85dc7db5af8f8df9f3e0c63efi18n-embed
0.15.4crates.io↘ 12↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum669ffc2c93f97e6ddf06ddbe999fcd6782e3342978bb85f7d3c087c7978404c4depends onused byi18n-embed-fl
0.9.4crates.io↘ 11↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum04b2969d0b3fc6143776c535184c19722032b43e6a642d710fa3f88faec53c2ddepends onused byi18n-embed-impl
0.8.4crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0f2cc0e0523d1fe6fc2c6f66e5038624ea8091b3e7748b5e8e0c84b1698db6c2used byiana-time-zone
0.1.65crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470depends onused byiana-time-zone-haiku
0.1.2crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269fdepends onused byicu_collections
2.2.0crates.io↘ 6↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191cicu_locale_core
2.2.0crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29icu_normalizer
2.2.0crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4depends onused byicu_normalizer_data
2.2.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumda3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38used byicu_properties
2.2.0crates.io↘ 6↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70dedepends onicu_properties_data
2.2.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14used byicu_provider
2.2.0crates.io↘ 7↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421depends onid-arena
2.3.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954used byidna
1.1.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4deused byidna_adapter
1.2.2crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714depends onused byindexmap
2.14.0crates.io↘ 4↖ 11sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9indicatif
0.18.4crates.io↘ 6↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9ebdepends onindoc
2.0.7crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706depends onused byinout
0.1.4crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01depends onused byinout
0.2.2crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7depends oninternal-russh-num-bigint
0.5.0crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumae8e22120c32fb4d19ec55fba35015f57095cd95a2e3b732e44457f5915b2ee8used byintl_pluralrules
7.0.2crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972depends onused byintl-memoizer
0.5.3crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163fdepends onio_tee
0.1.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4b3f7cef34251886990511df1c61443aa928499d598a9473929ab5a90a527304used byipnet
2.12.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2used byis_terminal_polyfill
1.70.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695used byitertools
0.13.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186depends onused byitertools
0.14.0crates.io↘ 1↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285depends onitoa
1.0.18crates.io↘ 0↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682js-sys
0.3.102crates.io↘ 3↖ 12sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31keccak
0.2.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aadepends onused bykem
0.3.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum01737161ba802849cfd486b5bd209d38ba4943494c249a8126005170c7621edddepends onused bylazy_static
1.5.0crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fedepends onleb128fmt
0.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2used bylibc
0.2.186crates.io↘ 0↖ 27sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66used by- android_system_properties
0.1.5 - clang-sys
1.8.1 - console
0.16.3 - core-foundation
0.10.1 - cpufeatures
0.2.17 - cpufeatures
0.3.0 - errno
0.3.14 - getrandom
0.2.17 - getrandom
0.3.4 - getrandom
0.4.2 - hostname
0.4.2 - hyper-util
0.1.20 - libredox
0.1.17 - mio
1.2.1 - nix
0.31.3 - parking_lot_core
0.9.12 - quinn-udp
0.5.14 - rand
0.8.6 - ring
0.17.14 - rustix
0.38.44 - rustix
1.1.4 - security-framework
3.7.0 - security-framework-sys
2.17.0 - signal-hook-registry
1.4.8 - socket2
0.6.4 - tokio
1.52.3 - zbus
5.16.0
- android_system_properties
libloading
0.8.9crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55depends onused bylibm
0.2.16crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981libredox
0.1.17crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3used bylink-cplusplus
1.0.12crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82depends onused bylinked-hash-map
0.5.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770fused bylinux-raw-sys
0.4.15crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807abused bylinux-raw-sys
0.12.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53used bylitemap
0.8.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0used bylock_api
0.4.14crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965depends onused bylog
0.4.32crates.io↘ 0↖ 16sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3alru-slab
0.1.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154used bymatchers
0.2.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9depends onused bymd5
0.8.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0used bymemchr
2.8.2crates.io↘ 0↖ 10sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4memoffset
0.9.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218adepends onused byminimal-lexical
0.2.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79aused byminiz_oxide
0.8.9crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316depends onused bymio
1.2.1crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fdaused byml-kem
0.3.2crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5e15f3e5b957493873e396a66914e83e616b6afe335cdef7efe5c6e1216aba66used bymodule-lattice
0.2.3crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febeused bynix
0.31.3crates.io↘ 4↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3dnix-eval
0.1.0workspace↘ 16↖ 3nix-plugin-fleet
0.1.0workspace↘ 1↖ 0depends onnixlike
0.1.0workspace↘ 5↖ 2nom
7.1.3crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4adepends onnom
8.0.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdf9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405depends onused bynu-ansi-term
0.50.3crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5depends onused bynum-bigint
0.4.6crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9depends onused bynum-bigint-dig
0.8.6crates.io↘ 8↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7depends onused bynum-conv
0.2.2crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441used bynum-integer
0.1.46crates.io↘ 1↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858fdepends onnum-iter
0.1.45crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bfused bynum-traits
0.2.19crates.io↘ 2↖ 11sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841depends ononce_cell
1.21.4crates.io↘ 0↖ 10sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50once_cell_polyfill
1.70.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4feused byopaque-debug
0.3.1crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381openssl-probe
0.2.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbeused byopentelemetry
0.31.0crates.io↘ 6↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0depends onopentelemetry_sdk
0.31.0crates.io↘ 7↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bddepends onopentelemetry-appender-tracing
0.31.1crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumef6a1ac5ca3accf562b8c306fa8483c85f4390f768185ab775f242f7fe8fdcc2used byopentelemetry-exporter-env
0.1.0workspace↘ 3↖ 1used byopentelemetry-http
0.31.0crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855dused byopentelemetry-otlp
0.31.1crates.io↘ 12↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71fdepends onopentelemetry-proto
0.31.0crates.io↘ 9↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30fdepends onused byordered-stream
0.2.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50depends onused byp256
0.14.0-rc.10crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum41adc63effe99d48837a8cc0e6d7a77e32ae6a07f6000df466178dbc2193093edepends onp384
0.14.0-rc.10crates.io↘ 6↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9bd5333afa5ae0347f39e6a0f2c9c155da431583fd71fe5555bd0521b4ccaf02depends onp521
0.14.0-rc.10crates.io↘ 6↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma3a5297f53dc16d35909060ba3032cff7867e8809f01e273ff325579d5f0ceaedepends onpageant
0.2.1crates.io↘ 12↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4f3a5ae18f65a85c67a77d18d42d3606c07948e3c17c1e5f74852b26589e88a5depends onused bypapergrid
0.17.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6978128c8b51d8f4080631ceb2302ab51e32cc6e8615f735ee2f83fd269ae3f1depends onused byparking
2.2.1crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dcebaparking_lot
0.12.5crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1adepends onused byparking_lot_core
0.9.12crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1used bypassword-hash
0.6.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumaab41826031698d6ffcd9cff78ef56ef998e39dc7e5067cdfebe373842d4723bdepends onused bypaste
1.0.15crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0aused bypbkdf2
0.12.2crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2depends onpbkdf2
0.13.0crates.io↘ 2↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629depends onpeg
0.8.6crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0aad070be5b63aa72103f2fcdd70a83adbd5e90112ce5b574171ff1c65501773depends onused bypeg-macros
0.8.6crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumddd8ef6825cae95355031ae26a99b616a2a21f22ba2de0197c43dfb05acbe7eeused bypeg-runtime
0.8.6crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7011d97b484a5ebdc4b1fdb3b12d5e4bbbea56e9d22b688f2e79e04b65a7d8a6used bypem-rfc7468
1.0.0crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9depends onpercent-encoding
2.3.2crates.io↘ 0↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220phc
0.6.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum44dc769b75f93afdddd8c7fa12d685292ddeff1e66f7f0f3a234cf1818afe892depends onused bypin-project
1.1.13crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924depends onused bypin-project-internal
1.1.13crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8bdepends onused bypin-project-lite
0.2.17crates.io↘ 0↖ 23sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cdused by- async-broadcast
0.7.2 - async-channel
2.5.0 - async-executor
1.14.0 - async-lock
3.4.2 - event-listener
5.4.1 - event-listener-strategy
0.5.4 - futures-lite
2.6.1 - futures-util
0.3.32 - http-body-util
0.1.3 - hyper
1.10.1 - hyper-timeout
0.5.2 - hyper-util
0.1.20 - opentelemetry
0.31.0 - ordered-stream
0.2.0 - polling
3.11.0 - quinn
0.11.9 - reqwest
0.12.28 - tokio
1.52.3 - tokio-stream
0.1.18 - tokio-util
0.7.18 - tower
0.5.3 - tower-http
0.6.11 - tracing
0.1.44
- async-broadcast
piper
0.2.5crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1used bypkcs1
0.7.5crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47fdepends onused bypkcs1
0.8.0-rc.4crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088eused bypkcs5
0.8.0crates.io↘ 8↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum279a91971a1d8eb1260a30938eae3be9cb67b472dffecb222fbbbe2fd2dc1453used bypkcs8
0.10.2crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7pkcs8
0.11.0crates.io↘ 4↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7pkg-config
0.3.33crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569eused byplain
0.2.3crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6used bypolling
3.11.0crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218depends onused bypoly1305
0.8.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abfused bypoly1305
0.9.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma00baa632505d05512f48a963e16051c54fda9a95cc9acea1a4e3c90991c4a2eused bypolyval
0.6.2crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25used bypolyval
0.7.1crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7dfc63250416fea14f5749b90725916a6c903f599d51cb635aa7a52bfd03eedeused byportable-atomic
1.13.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49used bypotential_utf
0.1.5crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564depends onused bypowerfmt
0.2.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391used byppv-lite86
0.2.21crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9depends onprettyplease
0.2.37crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62bdepends onprimefield
0.14.0-rc.11crates.io↘ 6↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb1d7e42f46a29abc16fb621a3466ee453358ebaae48a9e515f287e0af052ed8fprimeorder
0.14.0-rc.10crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7d2793f22b9b6fd11ef3ac1d59bf003c2573593e4968702341605c2748fd90bfdepends onproc-macro-crate
3.5.0crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614fdepends onproc-macro-error-attr2
2.0.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5depends onused byproc-macro-error2
2.0.1crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802proc-macro2
1.0.106crates.io↘ 1↖ 48sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934depends onused by- async-recursion
1.1.1 - async-trait
0.1.89 - bifrostlink-macros
0.2.6 - bindgen
0.72.1 - clap_derive
4.6.1 - curve25519-dalek-derive
0.1.1 - cxx-build
1.0.194 - cxxbridge-cmd
1.0.194 - cxxbridge-macro
1.0.194 - delegate
0.13.5 - derivative
2.2.0 - displaydoc
0.2.6 - enum_dispatch
0.3.13 - enumflags2_derive
0.7.12 - futures-macro
0.3.32 - i18n-embed-fl
0.9.4 - i18n-embed-impl
0.8.4 - peg-macros
0.8.6 - pin-project-internal
1.1.13 - prettyplease
0.2.37 - proc-macro-error-attr2
2.0.0 - proc-macro-error2
2.0.1 - prost-derive
0.14.4 - quote
1.0.45 - rust-embed-impl
8.11.0 - serde_derive
1.0.228 - serde_repr
0.1.20 - syn
1.0.109 - syn
2.0.117 - synstructure
0.13.2 - tabled_derive
0.11.0 - test-log-core
0.2.21 - thiserror-impl
1.0.69 - thiserror-impl
2.0.18 - tokio-macros
2.7.0 - tracing-attributes
0.1.31 - wasm-bindgen-macro-support
0.2.125 - windows-implement
0.60.2 - windows-interface
0.59.3 - wit-bindgen-rust-macro
0.51.0 - yoke-derive
0.8.2 - zbus_macros
5.16.0 - zerocopy-derive
0.8.52 - zerofrom-derive
0.1.7 - zeroize_derive
1.5.0 - zerovec-derive
0.11.3 - zvariant_derive
5.12.0 - zvariant_utils
3.4.0
- async-recursion
proptest
1.11.0crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744depends onused byprost
0.14.4crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1depends onprost-derive
0.14.4crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adfused byquinn
0.11.9crates.io↘ 12↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20depends onused byquinn-proto
0.11.14crates.io↘ 13↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098depends onused byquinn-udp
0.5.14crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumaddec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbdused byquote
1.0.45crates.io↘ 1↖ 47sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924depends onused by- async-recursion
1.1.1 - async-trait
0.1.89 - bifrostlink-macros
0.2.6 - bindgen
0.72.1 - clap_derive
4.6.1 - curve25519-dalek-derive
0.1.1 - cxx-build
1.0.194 - cxxbridge-cmd
1.0.194 - cxxbridge-macro
1.0.194 - delegate
0.13.5 - derivative
2.2.0 - displaydoc
0.2.6 - enum_dispatch
0.3.13 - enumflags2_derive
0.7.12 - futures-macro
0.3.32 - i18n-embed-fl
0.9.4 - i18n-embed-impl
0.8.4 - peg-macros
0.8.6 - pin-project-internal
1.1.13 - proc-macro-error-attr2
2.0.0 - proc-macro-error2
2.0.1 - prost-derive
0.14.4 - rust-embed-impl
8.11.0 - serde_derive
1.0.228 - serde_repr
0.1.20 - syn
1.0.109 - syn
2.0.117 - synstructure
0.13.2 - tabled_derive
0.11.0 - test-log-core
0.2.21 - thiserror-impl
1.0.69 - thiserror-impl
2.0.18 - tokio-macros
2.7.0 - tracing-attributes
0.1.31 - wasm-bindgen-macro
0.2.125 - wasm-bindgen-macro-support
0.2.125 - windows-implement
0.60.2 - windows-interface
0.59.3 - wit-bindgen-rust-macro
0.51.0 - yoke-derive
0.8.2 - zbus_macros
5.16.0 - zerocopy-derive
0.8.52 - zerofrom-derive
0.1.7 - zeroize_derive
1.5.0 - zerovec-derive
0.11.3 - zvariant_derive
5.12.0 - zvariant_utils
3.4.0
- async-recursion
r-efi
5.3.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0fused byr-efi
6.0.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bfused byrand
0.8.6crates.io↘ 3↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8arand
0.9.4crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76eadepends onrand
0.10.1crates.io↘ 3↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207rand_chacha
0.3.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88depends onused byrand_chacha
0.9.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cbdepends onused byrand_core
0.6.4crates.io↘ 1↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922cdepends onrand_core
0.9.5crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83cdepends onrand_core
0.10.1crates.io↘ 0↖ 20sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69used by- chacha20
0.10.0 - crypto-bigint
0.7.3 - crypto-common
0.2.2 - crypto-primes
0.7.2 - ed25519-dalek
3.0.0-rc.0 - elliptic-curve
0.14.0-rc.33 - ff
0.14.0 - getrandom
0.4.2 - group
0.14.0 - internal-russh-num-bigint
0.5.0 - kem
0.3.0 - ml-kem
0.3.2 - pkcs5
0.8.0 - pkcs8
0.11.0 - primefield
0.14.0-rc.11 - rand
0.10.1 - rsa
0.10.0-rc.18 - russh
0.61.2 - signature
3.0.0 - ssh-key
0.7.0-rc.10
- chacha20
rand_xorshift
0.4.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5adepends onused byredox_syscall
0.5.18crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362ddepends onused byredox_syscall
0.8.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7depends onused byregex
1.12.4crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6baused byregex-automata
0.4.14crates.io↘ 3↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8fregex-syntax
0.8.11crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4remowt-client
0.1.7crates.io↘ 17↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum34d59c0ce311b4b3c094b0b196a1004aa438b9947c3eace2ca4d2a0ac08fac59depends onremowt-endpoints
0.1.7crates.io↘ 12↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcb203856cd5cff27504bd2023c59195b1f1ce1cf5d8ea836598993894eb1b9c0depends onremowt-plugin
0.1.7crates.io↘ 8↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumef73ef3eea5bb6152d01019b5062e51ef258a1ac1c7a6f8cdcdf6fe1eb192cdddepends onused byremowt-plugin-fleet
0.1.0workspace↘ 3↖ 0remowt-ui-prompt
0.1.7crates.io↘ 9↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumacf28ba68e6f8087657157695e9ab42b82a21130e77f6dffd27781062109325ddepends onreqwest
0.12.28crates.io↘ 32↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumeddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147depends on- base64
0.22.1 - bytes
1.11.1 - futures-channel
0.3.32 - futures-core
0.3.32 - futures-util
0.3.32 - http
1.4.2 - http-body
1.0.1 - http-body-util
0.1.3 - hyper
1.10.1 - hyper-rustls
0.27.9 - hyper-util
0.1.20 - js-sys
0.3.102 - log
0.4.32 - percent-encoding
2.3.2 - pin-project-lite
0.2.17 - quinn
0.11.9 - rustls
0.23.40 - rustls-native-certs
0.8.4 - rustls-pki-types
1.14.1 - serde
1.0.228 - serde_json
1.0.150 - serde_urlencoded
0.7.1 - sync_wrapper
1.0.2 - tokio
1.52.3 - tokio-rustls
0.26.4 - tower
0.5.3 - tower-http
0.6.11 - tower-service
0.3.3 - url
2.5.8 - wasm-bindgen
0.2.125 - wasm-bindgen-futures
0.4.75 - web-sys
0.3.102
- base64
rfc6979
0.5.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5236ce872cac07e0fb3969b0cbf468c7d2f37d432f1b627dcb7b8d34563fb0c3depends onused byring
0.17.14crates.io↘ 6↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7rsa
0.9.10crates.io↘ 12↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12ddepends onused byrsa
0.10.0-rc.18crates.io↘ 11↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum30b2aa4ba0d89f73d1e332df05be0eeab8840351c36ca5654341dfdb57bb3cafdepends onrussh
0.61.2crates.io↘ 64↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbbf893f64684e58da8a68d56a5e84d1cf0440226274c515770fe267707a7d0b0depends on- aes
0.9.1 - bitflags
2.13.0 - block-padding
0.4.2 - byteorder
1.5.0 - bytes
1.11.1 - cbc
0.2.1 - cipher
0.5.2 - crypto-bigint
0.7.3 - ctr
0.10.1 - curve25519-dalek
5.0.0-rc.0 - data-encoding
2.11.0 - delegate
0.13.5 - der
0.8.0 - digest
0.11.3 - ecdsa
0.17.0-rc.18 - ed25519-dalek
3.0.0-rc.0 - elliptic-curve
0.14.0-rc.33 - enum_dispatch
0.3.13 - flate2
1.1.9 - futures
0.3.32 - generic-array
1.4.3 - getrandom
0.4.2 - ghash
0.6.0 - hex-literal
1.1.0 - hmac
0.13.0 - inout
0.2.2 - internal-russh-num-bigint
0.5.0 - keccak
0.2.0 - log
0.4.32 - md5
0.8.0 - ml-kem
0.3.2 - module-lattice
0.2.3 - num-bigint
0.4.6 - p256
0.14.0-rc.10 - p384
0.14.0-rc.10 - p521
0.14.0-rc.10 - pageant
0.2.1 - pbkdf2
0.13.0 - pkcs1
0.8.0-rc.4 - pkcs5
0.8.0 - pkcs8
0.11.0 - polyval
0.7.1 - rand
0.10.1 - rand_core
0.10.1 - ring
0.17.14 - rsa
0.10.0-rc.18 - russh-cryptovec
0.61.0 - russh-util
0.52.0 - salsa20
0.11.0 - scrypt
0.12.0 - sec1
0.8.1 - sha1
0.11.0 - sha2
0.11.0 - sha3
0.11.0 - signature
3.0.0 - spki
0.8.0 - ssh-encoding
0.3.0-rc.9 - ssh-key
0.7.0-rc.10 - subtle
2.6.1 - thiserror
2.0.18 - tokio
1.52.3 - typenum
1.20.1 - universal-hash
0.6.1 - zeroize
1.9.0
used by- aes
russh-config
0.58.0crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum993346101d4741a59c82bafc6b645c52ce3e7b0820f13e4b5d48cdb591e3d955used byrussh-cryptovec
0.61.0crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum443f6bbcfacb34a1aab2b12b99bf08e0c63abdc5a0db261901365df9d57fff51used byrussh-util
0.52.0crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum668424a5dde0bcb45b55ba7de8476b93831b4aa2fa6947e145f3b053e22c60b6used byrust-embed
8.11.0crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27used byrust-embed-impl
8.11.0crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumda0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaaused byrust-embed-utils
8.11.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1depends onrustc_version
0.4.1crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92depends onrustc-hash
1.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2used byrustc-hash
2.1.2crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dberustix
0.38.44crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154used byrustix
1.1.4crates.io↘ 5↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190rustls
0.23.40crates.io↘ 6↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168bdepends onrustls-native-certs
0.8.4crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4drustls-pki-types
1.14.1crates.io↘ 2↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9depends onrustls-webpki
0.103.13crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756eused byrustversion
1.0.22crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46dryu
1.0.23crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477fused bysalsa20
0.10.2crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213depends onused bysalsa20
0.11.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2f874456e72520ff1375a06c588eaf074b0f01f9e9e1aada45bd9b7954a6e42cdepends onused bysame-file
1.0.6crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502depends onused byschannel
0.1.29crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939depends onused byscopeguard
1.2.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49used byscratch
1.0.9crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2used byscrypt
0.11.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1fdepends onused byscrypt
0.12.0crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd87af57419b594aa23fa95f09f0e06d80d84ba01c26148c43844cad6ff4485f0used bysec1
0.8.1crates.io↘ 6↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4dsecrecy
0.10.3crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5adepends onused bysecurity-framework
3.7.0crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1ddepends onused bysecurity-framework-sys
2.17.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3depends onused byself_cell
0.10.3crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915ddepends onused byself_cell
1.2.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89used bysemver
1.0.28crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cdserde
1.0.228crates.io↘ 2↖ 37sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9edepends onused by- basic-toml
0.1.10 - bifrostlink
0.2.6 - bstr
1.12.1 - chrono
0.4.45 - codespan-reporting
0.13.1 - ed25519-dalek
2.2.0 - ed25519-dalek
3.0.0-rc.0 - enumflags2
0.7.12 - fleet
0.2.0 - fleet-base
0.1.0 - fleet-install-secrets
0.1.0 - fleet-shared
0.1.0 - i18n-config
0.4.8 - indexmap
2.14.0 - nix-eval
0.1.0 - nixlike
0.1.0 - opentelemetry-proto
0.31.0 - remowt-client
0.1.7 - remowt-endpoints
0.1.7 - remowt-fleet
0.1.0 - remowt-link-shared
0.1.7 - remowt-ui-prompt
0.1.7 - reqwest
0.12.28 - serde_json
1.0.150 - serde_urlencoded
0.7.1 - serdect
0.4.3 - toml
0.5.11 - unic-langid-impl
0.9.6 - url
2.5.8 - wit-component
0.244.0 - wit-parser
0.244.0 - x25519-dalek
2.0.1 - zbus
5.16.0 - zbus_names
4.3.2 - zerovec
0.11.6 - zvariant
5.12.0 - zvariant_utils
3.4.0
- basic-toml
serde_core
1.0.228crates.io↘ 1↖ 9sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67addepends onserde_derive
1.0.228crates.io↘ 3↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79depends onserde_json
1.0.150crates.io↘ 5↖ 14sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9serde_repr
0.1.20crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59cdepends onused byserde_urlencoded
0.7.1crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fdused byserdect
0.4.3crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum66cf8fedced2fcf12406bcb34223dffb92eaf34908ede12fed414c82b7f00b3edepends onused bysha1
0.11.0crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumaacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214depends onsha2
0.10.9crates.io↘ 3↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283depends onsha2
0.11.0crates.io↘ 3↖ 11sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4depends onsha3
0.11.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbe176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1depends onused bysharded-slab
0.1.7crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6depends onused byshlex
1.3.0crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64used bysignal-hook-registry
1.4.8crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1bdepends onsignature
2.2.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329dedepends onused bysignature
3.0.0crates.io↘ 2↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5depends onsimd-adler32
0.3.9crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214used byslab
0.4.12crates.io↘ 0↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5smallvec
1.15.2crates.io↘ 0↖ 8sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90socket2
0.6.4crates.io↘ 2↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51depends onspin
0.9.8crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67used byspki
0.7.3crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29ddepends onspki
0.8.0crates.io↘ 2↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6fdepends onssh-cipher
0.3.0-rc.9crates.io↘ 12↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum10db6f219196a8528f9ec904d9d45cdad692d65b0e57e72be4dedd1c5fddce36depends onused byssh-encoding
0.3.0-rc.9crates.io↘ 7↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7abf34aa716da5d5b4c496936d042ea282ab392092cd68a72ef6a8863ff8c96adepends onssh-key
0.7.0-rc.10crates.io↘ 18↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum45735ce3dea95690e4a9e414c4cfde7f79835063c3dcd35881df85a84118e74bdepends onused bystable_deref_trait
1.2.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596used bystrsim
0.11.1crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4fsubtle
2.6.1crates.io↘ 0↖ 21sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292used by- aes-gcm
0.10.3 - aes-gcm
0.11.0-rc.4 - age
0.11.3 - crypto-bigint
0.7.3 - ctutils
0.4.2 - curve25519-dalek
4.1.3 - curve25519-dalek
5.0.0-rc.0 - digest
0.10.7 - ed25519-dalek
2.2.0 - ed25519-dalek
3.0.0-rc.0 - elliptic-curve
0.14.0-rc.33 - ff
0.14.0 - group
0.14.0 - hybrid-array
0.4.12 - primefield
0.14.0-rc.11 - rfc6979
0.5.0 - rsa
0.9.10 - russh
0.61.2 - rustls
0.23.40 - sec1
0.8.1 - universal-hash
0.5.1
- aes-gcm
syn
1.0.109crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237used bysyn
2.0.117crates.io↘ 3↖ 44sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99used by- async-recursion
1.1.1 - async-trait
0.1.89 - bifrostlink-macros
0.2.6 - bindgen
0.72.1 - clap_derive
4.6.1 - curve25519-dalek-derive
0.1.1 - cxx-build
1.0.194 - cxxbridge-cmd
1.0.194 - cxxbridge-macro
1.0.194 - delegate
0.13.5 - displaydoc
0.2.6 - enum_dispatch
0.3.13 - enumflags2_derive
0.7.12 - futures-macro
0.3.32 - i18n-embed-fl
0.9.4 - i18n-embed-impl
0.8.4 - pin-project-internal
1.1.13 - prettyplease
0.2.37 - proc-macro-error2
2.0.1 - prost-derive
0.14.4 - rust-embed-impl
8.11.0 - serde_derive
1.0.228 - serde_repr
0.1.20 - synstructure
0.13.2 - tabled_derive
0.11.0 - test-log-core
0.2.21 - test-log-macros
0.2.21 - thiserror-impl
1.0.69 - thiserror-impl
2.0.18 - tokio-macros
2.7.0 - tracing-attributes
0.1.31 - wasm-bindgen-macro-support
0.2.125 - windows-implement
0.60.2 - windows-interface
0.59.3 - wit-bindgen-rust
0.51.0 - wit-bindgen-rust-macro
0.51.0 - yoke-derive
0.8.2 - zbus_macros
5.16.0 - zerocopy-derive
0.8.52 - zerofrom-derive
0.1.7 - zeroize_derive
1.5.0 - zerovec-derive
0.11.3 - zvariant_derive
5.12.0 - zvariant_utils
3.4.0
- async-recursion
sync_wrapper
1.0.2crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263depends onsynstructure
0.13.2crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2depends ontabled
0.20.0crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume39a2ee1fbcd360805a771e1b300f78cc88fec7b8d3e2f71cd37bbf23e725c7dused bytabled_derive
0.11.0crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0ea5d1b13ca6cff1f9231ffd62f15eefd72543dab5e468735f1a456728a02846used bytempfile
3.27.0crates.io↘ 5↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bdtermcolor
1.4.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755depends onused byterminal_size
0.4.4crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874depends onused bytest-log
0.2.21crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9b9c218384242b5c89b68303ab6f6fc53a312d923f0c14dc6bb860c6aeee40f1used bytest-log-core
0.2.21crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc26ef8b00e4d382e59f6a8ddb3cd790b3a5bb29f21a358a9a69ea2f29f13f27bdepends onused bytest-log-macros
0.2.21crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum944ad38adcbb71eaa682c56bceeb079e4ca82b4b3edc2a0fde5cb297b77dac8ddepends onused bytesting_table
0.3.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0f8daae29995a24f65619e19d8d31dea5b389f3d853d8bf297bbf607cd0014ccdepends onused bythiserror
1.0.69crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52depends onthiserror
2.0.18crates.io↘ 1↖ 14sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4depends onthiserror-impl
1.0.69crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1depends onused bythiserror-impl
2.0.18crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5depends onused bythread_local
1.1.9crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185depends onused bytime
0.3.49crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469used bytime-core
0.1.9crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109used bytime-macros
0.2.29crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17ddepends onused bytinystr
0.8.3crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96dtinyvec
1.11.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3depends onused bytinyvec_macros
0.1.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20used bytokio
1.52.3crates.io↘ 8↖ 28sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffedepends onused by- bifrostlink
0.2.6 - bifrostlink-ports
0.2.6 - fleet
0.2.0 - fleet-base
0.1.0 - h2
0.4.14 - hyper
1.10.1 - hyper-rustls
0.27.9 - hyper-timeout
0.5.2 - hyper-util
0.1.20 - nix-eval
0.1.0 - opentelemetry-otlp
0.31.1 - pageant
0.2.1 - quinn
0.11.9 - remowt-client
0.1.7 - remowt-endpoints
0.1.7 - remowt-fleet
0.1.0 - remowt-link-shared
0.1.7 - remowt-plugin
0.1.7 - remowt-ui-prompt
0.1.7 - reqwest
0.12.28 - russh
0.61.2 - russh-config
0.58.0 - russh-util
0.52.0 - tokio-rustls
0.26.4 - tokio-stream
0.1.18 - tokio-util
0.7.18 - tonic
0.14.6 - tower
0.5.3
- bifrostlink
tokio-macros
2.7.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496depends onused bytokio-rustls
0.26.4crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61depends ontokio-stream
0.1.18crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70used bytokio-util
0.7.18crates.io↘ 5↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098toml
0.5.11crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234depends onused bytoml_datetime
1.1.1+spec-1.1.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7depends onused bytoml_edit
0.25.12+spec-1.1.0crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7used bytoml_parser
1.1.2+spec-1.1.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526depends onused bytonic
0.14.6crates.io↘ 19↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445efdepends ontonic-prost
0.14.6crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0depends onused bytower
0.5.3crates.io↘ 11↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4depends ontower-http
0.6.11crates.io↘ 10↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840depends onused bytower-layer
0.3.3crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780etower-service
0.3.3crates.io↘ 0↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3tracing
0.1.44crates.io↘ 3↖ 26sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100used by- bifrostlink
0.2.6 - bifrostlink-ports
0.2.6 - fleet
0.2.0 - fleet-base
0.1.0 - fleet-install-secrets
0.1.0 - h2
0.4.14 - hyper-util
0.1.20 - nix-eval
0.1.0 - opentelemetry
0.31.0 - opentelemetry-appender-tracing
0.31.1 - opentelemetry-otlp
0.31.1 - quinn
0.11.9 - quinn-proto
0.11.14 - quinn-udp
0.5.14 - remowt-client
0.1.7 - remowt-endpoints
0.1.7 - remowt-fleet
0.1.0 - remowt-link-shared
0.1.7 - remowt-plugin
0.1.7 - remowt-ui-prompt
0.1.7 - tonic
0.14.6 - tower
0.5.3 - tracing-indicatif
0.3.14 - tracing-opentelemetry
0.32.1 - tracing-subscriber
0.3.23 - zbus
5.16.0
- bifrostlink
tracing-attributes
0.1.31crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8dadepends onused bytracing-core
0.1.36crates.io↘ 2↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdb97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79adepends ontracing-indicatif
0.3.14crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume1ef6990e0438749f0080573248e96631171a0b5ddfddde119aa5ba8c3a9c47eused bytracing-log
0.2.0crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3tracing-opentelemetry
0.32.1crates.io↘ 8↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fcdepends onused bytracing-subscriber
0.3.23crates.io↘ 10↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319depends ontype-map
0.5.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90depends onused bytypenum
1.20.1crates.io↘ 0↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20uds_windows
1.2.1crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6eused byunarray
0.1.4crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumeaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94used byunic-langid
0.9.6crates.io↘ 1↖ 8sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05depends onunic-langid-impl
0.9.6crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658depends onused byunicase
2.9.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142used byunicode_categories
0.1.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14eused byunicode-ident
1.0.24crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75unicode-width
0.2.2crates.io↘ 0↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254unicode-xid
0.2.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853used byunit-prefix
0.5.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3used byuniversal-hash
0.5.1crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07eadepends onused byuniversal-hash
0.6.1crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96depends onuntrusted
0.9.0crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1url
2.5.8crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eedutf8_iter
1.0.4crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6beutf8parse
0.2.2crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821uuid
1.23.3crates.io↘ 4↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7valuable
0.1.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65used byversion_check
0.9.5crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105aused byvt100
0.16.2crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum054ff75fb8fa83e609e685106df4faeffdf3a735d3c74ebce97ec557d5d36fd9depends onused byvte
0.15.0crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbdused bywalkdir
2.5.0crates.io↘ 2↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4bdepends onwant
0.3.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0edepends onused bywasi
0.11.1+wasi-snapshot-preview1crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44bused bywasip2
1.0.4+wasi-0.2.12crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487depends onused bywasip3
0.4.0+wasi-0.3.0-rc-2026-01-06crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5depends onused bywasite
0.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855bused bywasm-bindgen
0.2.125crates.io↘ 5↖ 12sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1adepends onwasm-bindgen-futures
0.4.75crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280depends onwasm-bindgen-macro
0.2.125crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3dused bywasm-bindgen-macro-support
0.2.125crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebdused bywasm-encoder
0.244.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319depends onwasm-metadata
0.244.0crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909wasmparser
0.244.0crates.io↘ 4↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028feweb-sys
0.3.102crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061ddepends onused byweb-time
1.1.0crates.io↘ 2↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bbdepends onwhich
4.4.2crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7used bywhoami
1.6.1crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97ddepends onused bywinapi-util
0.1.11crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22depends onwindows
0.62.2crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580used bywindows_aarch64_gnullvm
0.52.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3used bywindows_aarch64_gnullvm
0.53.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53used bywindows_aarch64_msvc
0.52.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469used bywindows_aarch64_msvc
0.53.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006used bywindows_i686_gnu
0.52.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0bused bywindows_i686_gnu
0.53.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3used bywindows_i686_gnullvm
0.52.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66used bywindows_i686_gnullvm
0.53.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180cused bywindows_i686_msvc
0.52.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66used bywindows_i686_msvc
0.53.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2used bywindows_x86_64_gnu
0.52.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78used bywindows_x86_64_gnu
0.53.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499used bywindows_x86_64_gnullvm
0.52.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0dused bywindows_x86_64_gnullvm
0.53.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1used bywindows_x86_64_msvc
0.52.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ecused bywindows_x86_64_msvc
0.53.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650used bywindows-collections
0.3.2crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610depends onused bywindows-core
0.62.2crates.io↘ 5↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9debdepends onwindows-future
0.3.2crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cbused bywindows-implement
0.60.2crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddfdepends onused bywindows-interface
0.59.3crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358depends onused bywindows-link
0.2.1crates.io↘ 0↖ 12sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5windows-numerics
0.3.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26depends onused bywindows-result
0.4.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5depends onused bywindows-strings
0.5.1crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091depends onwindows-sys
0.52.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33ddepends onused bywindows-sys
0.59.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853bdepends onused bywindows-sys
0.60.2crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcbdepends onused bywindows-sys
0.61.2crates.io↘ 1↖ 20sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fcdepends onwindows-targets
0.52.6crates.io↘ 8↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973depends onwindows-targets
0.53.5crates.io↘ 9↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3depends onused bywindows-threading
0.2.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37depends onused bywinnow
1.0.3crates.io↘ 1↖ 6sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1depends onwit-bindgen
0.51.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5depends onwit-bindgen
0.57.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536eused bywit-bindgen-core
0.51.0crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dcdepends onwit-bindgen-rust
0.51.0crates.io↘ 8↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21depends onused bywit-bindgen-rust-macro
0.51.0crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17adepends onused bywit-component
0.244.0crates.io↘ 11↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2depends onused bywit-parser
0.244.0crates.io↘ 10↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736depends onwriteable
0.6.3crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4x25519-dalek
2.0.1crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277yoke
0.8.3crates.io↘ 3↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5yoke-derive
0.8.2crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumde844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858eused byzbus
5.16.0crates.io↘ 27↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumeee682d202a77e4a9f3b2c2bdf48a7b28af5c08c34ddf66f98c93e5e39464285depends on- async-broadcast
0.7.2 - async-executor
1.14.0 - async-io
2.6.0 - async-lock
3.4.2 - async-process
2.5.0 - async-recursion
1.1.1 - async-task
4.7.1 - async-trait
0.1.89 - blocking
1.6.2 - enumflags2
0.7.12 - event-listener
5.4.1 - futures-core
0.3.32 - futures-lite
2.6.1 - hex
0.4.3 - libc
0.2.186 - ordered-stream
0.2.0 - rustix
1.1.4 - serde
1.0.228 - serde_repr
0.1.20 - tracing
0.1.44 - uds_windows
1.2.1 - uuid
1.23.3 - windows-sys
0.61.2 - winnow
1.0.3 - zbus_macros
5.16.0 - zbus_names
4.3.2 - zvariant
5.12.0
- async-broadcast
zbus_macros
5.16.0crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumadf1bd45a81a103745b1757754762a26e8cd01e4532e4d6c8ec431624b80d1d6depends onused byzbus_names
4.3.2crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52ddepends onused byzerocopy
0.8.52crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653fdepends onused byzerocopy-derive
0.8.52crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930depends onused byzerofrom
0.1.8crates.io↘ 1↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272depends onzerofrom-derive
0.1.7crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1used byzeroize
1.9.0crates.io↘ 1↖ 32sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64edepends onused by- aes
0.9.1 - aes-gcm
0.11.0-rc.4 - age
0.11.3 - block-buffer
0.12.1 - chacha20
0.10.0 - chacha20poly1305
0.10.1 - cipher
0.4.4 - cipher
0.5.2 - crypto-bigint
0.7.3 - curve25519-dalek
4.1.3 - curve25519-dalek
5.0.0-rc.0 - der
0.7.10 - der
0.8.0 - ecdsa
0.17.0-rc.18 - ed25519-dalek
2.2.0 - ed25519-dalek
3.0.0-rc.0 - elliptic-curve
0.14.0-rc.33 - hybrid-array
0.4.12 - num-bigint-dig
0.8.6 - poly1305
0.9.0 - primefield
0.14.0-rc.11 - rsa
0.9.10 - rsa
0.10.0-rc.18 - russh
0.61.2 - rustls
0.23.40 - rustls-pki-types
1.14.1 - sec1
0.8.1 - secrecy
0.10.3 - ssh-cipher
0.3.0-rc.9 - ssh-encoding
0.3.0-rc.9 - ssh-key
0.7.0-rc.10 - x25519-dalek
2.0.1
- aes
zeroize_derive
1.5.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328depends onused byzerotrie
0.2.4crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bfdepends onzerovec
0.11.6crates.io↘ 4↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239zerovec-derive
0.11.3crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555depends onused byzmij
1.0.21crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaaused byzvariant
5.12.0crates.io↘ 6↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma192a0bde63360d77a7523c833d4b4ce6070a927e2c53246e4c540b1a3e27be0zvariant_derive
5.12.0crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum90bc6cde9c01c511074be97f7ccb6c19d0da89e3f8662e812e999dcfd4638737used byzvariant_utils
3.4.0crates.io↘ 5↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1e8535915cfa75547e559d8c68e8139909a4aeee076831e4ef7fc59d8172c4d6
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,22 +6,28 @@
package.rust-version = "1.89.0"
[workspace.dependencies]
-better-command = { path = "./crates/better-command" }
fleet-base = { path = "./crates/fleet-base" }
fleet-shared = { path = "./crates/fleet-shared" }
nix-eval = { path = "./crates/nix-eval" }
nixlike = { path = "./crates/nixlike" }
opentelemetry-exporter-env = { path = "./crates/opentelemetry-exporter-env" }
+remowt-fleet = { path = "./crates/remowt-fleet" }
-abort-on-drop = "0.2"
+remowt-client = "0.1.3"
+remowt-endpoints = "0.1.3"
+remowt-link-shared = "0.1.3"
+remowt-plugin = "0.1.3"
+remowt-ui-prompt = "0.1.3"
+
+bifrostlink = "0.2.3"
+
+uuid = { version = "1", features = ["v4"] }
+
age = { version = "0.11", features = ["plugin", "ssh"] }
-age-core = "0.11"
anyhow = "1.0"
-async-trait = "0.1.88"
-axum = { version = "0.8.7", features = ["http2", "macros", "ws"] }
-axum-extra = { version = "0.12.2", features = ["typed-header"] }
base64 = "0.22.1"
bindgen = "0.72.0"
+camino = "1.2.2"
chrono = { version = "0.4.41", features = ["serde"] }
clap = { version = "4.5", features = ["derive", "env", "unicode", "wrap_help"] }
clap_complete = "4.5"
@@ -29,19 +35,16 @@
cxx-build = "1.0.168"
ed25519-dalek = "2.1"
futures = "0.3.31"
-futures-util = { version = "0.3.31", features = ["sink"] }
hex = "0.4.3"
hmac = "0.12"
hostname = "0.4.1"
human-repr = "1.1"
-hyper = "1.8.1"
indicatif = "0.18"
indoc = "2.0.6"
itertools = "0.14.0"
linked-hash-map = "0.5.6"
nix = { version = "0.31.2", features = ["fs", "user"] }
nom = "8.0.0"
-openssh = "0.11.5"
opentelemetry = "0.31.0"
opentelemetry-appender-tracing = "0.31.1"
opentelemetry-otlp = { version = "0.31.0", features = ["grpc-tonic", "gzip-tonic", "http-json", "reqwest-rustls"] }
@@ -50,21 +53,16 @@
peg = "0.8.5"
pkg-config = "0.3.30"
rand = "0.10.0"
-regex = "1.11"
serde = { version = "1.0", features = ["derive"] }
-serde-transcode = "1.1.1"
serde_json = "1.0"
sha2 = "0.10"
shlex = "1.3"
tabled = "0.20.0"
tempfile = "3.20"
test-log = { version = "0.2.19", features = ["trace"] }
-tf-provider = "0.2.2"
thiserror = "2.0.12"
time = "0.3.41"
tokio = { version = "1.45.1", features = ["fs", "macros", "rt", "rt-multi-thread", "sync", "time"] }
-tokio-util = "0.7.17"
-toml_edit = "0.23.10"
tracing = "0.1"
tracing-indicatif = "0.3.13"
tracing-opentelemetry = "0.32.1"
cmds/fleet/Cargo.tomldiffbeforeafterboth--- a/cmds/fleet/Cargo.toml
+++ b/cmds/fleet/Cargo.toml
@@ -8,15 +8,13 @@
default-run = "fleet"
[dependencies]
-age = { workspace = true, features = ["armor"] }
anyhow.workspace = true
-better-command.workspace = true
+camino.workspace = true
clap.workspace = true
clap_complete.workspace = true
fleet-base.workspace = true
-fleet-shared.workspace = true
nix-eval.workspace = true
-nixlike.workspace = true
+remowt-fleet.workspace = true
serde.workspace = true
serde_json.workspace = true
tempfile.workspace = true
@@ -24,30 +22,17 @@
tracing.workspace = true
tracing-subscriber.workspace = true
-abort-on-drop.workspace = true
-age-core.workspace = true
-async-trait.workspace = true
-base64.workspace = true
-chrono.workspace = true
futures.workspace = true
-hostname.workspace = true
itertools.workspace = true
-openssh.workspace = true
-peg.workspace = true
-regex.workspace = true
shlex.workspace = true
tabled.workspace = true
-time = { workspace = true, features = ["serde"] }
-tokio-util = { workspace = true, features = ["codec"] }
human-repr = { workspace = true, optional = true }
indicatif = { workspace = true, optional = true }
-nom.workspace = true
opentelemetry.workspace = true
opentelemetry-appender-tracing.workspace = true
opentelemetry-exporter-env.workspace = true
opentelemetry_sdk.workspace = true
-thiserror.workspace = true
tracing-indicatif = { workspace = true, optional = true }
tracing-opentelemetry.workspace = true
@@ -58,6 +43,5 @@
"dep:tracing-indicatif",
"dep:indicatif",
"dep:human-repr",
- "better-command/indicatif",
"nix-eval/indicatif",
]
cmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/build_systems.rs
+++ b/cmds/fleet/src/cmds/build_systems.rs
@@ -1,6 +1,7 @@
use std::{env::current_dir, os::unix::fs::symlink, path::PathBuf};
use anyhow::Result;
+use camino::Utf8PathBuf;
use clap::Parser;
use fleet_base::{
deploy::{DeployAction, deploy_task, upload_task},
@@ -29,7 +30,7 @@
build_attr: String,
}
-async fn build_task(config: Config, hostname: String, build_attr: &str) -> Result<PathBuf> {
+async fn build_task(config: Config, hostname: String, build_attr: &str) -> Result<Utf8PathBuf> {
info!("building");
let host = config.host(&hostname)?;
// let action = Action::from(self.subcommand.clone());
@@ -42,17 +43,20 @@
// We already have system profiles for backups.
if !host.local {
info!("adding gc root");
- let mut cmd = config.local_host().cmd("nix").await?;
- cmd.arg("build")
- .comparg(
- "--profile",
- format!(
- "/nix/var/nix/profiles/{}-{hostname}",
- config.data.gc_root_prefix
- ),
- )
- .arg(&out_output);
- cmd.sudo().run_nix().await?;
+ let local = config.local_host();
+ let plugin_id = local.ensure_nix_plugin().await?;
+ let nix = local
+ .remowt()
+ .await?
+ .plugin_endpoints::<remowt_fleet::NixClient<_>>(plugin_id);
+ let profile = format!(
+ "/nix/var/nix/profiles/{}-{hostname}",
+ config.data.gc_root_prefix
+ );
+ nix.switch_profile(profile, out_output.clone())
+ .await
+ .map_err(|e| anyhow::anyhow!("{e:?}"))?
+ .map_err(|e| anyhow::anyhow!("{e}"))?;
}
Ok(out_output)
cmds/fleet/src/cmds/tf.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/tf.rs
+++ b/cmds/fleet/src/cmds/tf.rs
@@ -1,6 +1,7 @@
-use std::{collections::BTreeMap, ffi::OsString, path::PathBuf};
+use std::{collections::BTreeMap, ffi::OsString};
use anyhow::{Context, Result};
+use camino::Utf8PathBuf;
use clap::Parser;
use fleet_base::host::Config;
use nix_eval::nix_go;
@@ -40,7 +41,7 @@
let system = &config.local_system;
let config = &config.flake_outputs;
let data = nix_go!(config.tf({ system }));
- let data: PathBuf = spawn_blocking(move || data.build("out"))
+ let data: Utf8PathBuf = spawn_blocking(move || data.build("out"))
.await
.expect("tf.json derivation should not fail")?;
let data = fs::read(&data).await?;
cmds/fleet/src/main.rsdiffbeforeafterboth--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -4,9 +4,10 @@
// pub(crate) mod command;
pub(crate) mod extra_args;
-use std::{env, ffi::OsString, process::ExitCode, sync::Arc};
+use std::{process::ExitCode, sync::Arc};
-use anyhow::{Result, bail};
+use anyhow::{Context as _, Result, bail};
+use camino::Utf8PathBuf;
use clap::{CommandFactory, Parser};
use cmds::{
build_systems::{BuildSystems, Deploy},
@@ -23,7 +24,8 @@
#[cfg(feature = "indicatif")]
use indicatif::{ProgressState, ProgressStyle};
use nix_eval::{
- gc_register_my_thread, gc_unregister_my_thread, init_libraries, init_tokio_for_nix,
+ add_file_to_store, gc_register_my_thread, gc_unregister_my_thread, init_libraries,
+ init_tokio_for_nix,
};
use opentelemetry::trace::TracerProvider;
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
@@ -48,24 +50,21 @@
}
let tasks = FuturesUnordered::new();
for entry in std::fs::read_dir(&prefetch_dir)? {
- tasks.push(async {
- let entry = entry?;
- if !entry.metadata()?.is_file() {
- bail!("only files should exist in prefetch directory");
- }
- let span = info_span!(
- "prefetching",
- name = entry.file_name().to_string_lossy().as_ref()
- );
- let mut path = OsString::new();
- path.push("file://");
- path.push(entry.path());
-
- let mut status = config.local_host().cmd("nix").await?;
- status.args(&config.nix_args);
- status.arg("store").arg("prefetch-file").arg(path);
- status.run_nix_string().instrument(span).await?;
- Ok(())
+ let entry = entry?;
+ if !entry.metadata()?.is_file() {
+ bail!("only files should exist in prefetch directory");
+ }
+ let name = entry.file_name().to_string_lossy().into_owned();
+ let path =
+ Utf8PathBuf::try_from(entry.path()).context("prefetch path should be utf8")?;
+ let span = info_span!("prefetching", name = %name);
+ tasks.push(async move {
+ let added = tokio::task::spawn_blocking(move || add_file_to_store(&name, &path))
+ .instrument(span.clone())
+ .await??;
+ let _g = span.enter();
+ info!("{} -> {}", added.hash, added.store_path);
+ anyhow::Ok(())
});
}
tasks.try_collect::<Vec<()>>().await?;
@@ -179,9 +178,7 @@
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
let reg = tracing_subscriber::registry().with({
- let sub = tracing_subscriber::fmt::layer()
- .without_time()
- .with_target(false);
+ let sub = tracing_subscriber::fmt::layer().without_time();
#[cfg(feature = "indicatif")]
let sub = sub.with_writer(indicatif_layer.get_stderr_writer());
sub.with_filter(filter) // .without,
@@ -262,14 +259,10 @@
}
async fn main_real(opts: RootOpts) -> Result<()> {
- let nix_args = std::env::var_os("NIX_ARGS")
- .map(|a| extra_args::parse_os(&a))
- .transpose()?
- .unwrap_or_default();
- let config = opts.fleet_opts.build(
- nix_args,
- matches!(opts.command, Opts::Deploy(_) | Opts::BuildSystems(_)),
- )?;
+ let config = opts.fleet_opts.build(matches!(
+ opts.command,
+ Opts::Deploy(_) | Opts::BuildSystems(_)
+ ))?;
match run_command(&config, opts.fleet_opts, opts.command).await {
Ok(()) => {
cmds/install-secrets/src/main.rsdiffbeforeafterboth--- a/cmds/install-secrets/src/main.rs
+++ b/cmds/install-secrets/src/main.rs
@@ -227,7 +227,6 @@
.from_env_lossy(),
)
.without_time()
- .with_target(false)
.init();
let opts = Opts::parse();
cmds/nix-plugin-fleet/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/cmds/nix-plugin-fleet/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "nix-plugin-fleet"
+version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+fleet-base.workspace = true
cmds/nix-plugin-fleet/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/cmds/nix-plugin-fleet/src/lib.rs
@@ -0,0 +1,7 @@
+use fleet_base::primops::init_primops;
+
+/// SAFETY: expected plugin dynamic library entry point
+#[unsafe(no_mangle)]
+fn nix_plugin_entry() {
+ init_primops();
+}
cmds/remowt-plugin-fleet/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/cmds/remowt-plugin-fleet/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "remowt-plugin-fleet"
+description = "Remowt plugin exposing fleet's Nix endpoint to a running agent"
+version.workspace = true
+edition = "2021"
+
+[dependencies]
+remowt-fleet.workspace = true
+remowt-plugin.workspace = true
+
+anyhow.workspace = true
cmds/remowt-plugin-fleet/src/main.rsdiffbeforeafterboth--- /dev/null
+++ b/cmds/remowt-plugin-fleet/src/main.rs
@@ -0,0 +1,8 @@
+use remowt_fleet::{Nix, init_libraries};
+
+fn main() -> anyhow::Result<()> {
+ remowt_plugin::run(|rpc| {
+ init_libraries();
+ Nix.register_endpoints(rpc);
+ })
+}
cmds/repl-plugin-unstable/Cargo.tomldiffbeforeafterboth--- a/cmds/repl-plugin-unstable/Cargo.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "repl-plugin-unstable"
-version.workspace = true
-edition.workspace = true
-rust-version.workspace = true
-
-[lib]
-crate-type = ["cdylib"]
-
-[dependencies]
-fleet-base.workspace = true
cmds/repl-plugin-unstable/src/lib.rsdiffbeforeafterboth--- a/cmds/repl-plugin-unstable/src/lib.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-use fleet_base::primops::init_primops;
-
-/// SAFETY: expected plugin dynamic library entry point
-#[unsafe(no_mangle)]
-fn nix_plugin_entry() {
- init_primops();
-}
cmds/terraform-provider-fleet/Cargo.tomldiffbeforeafterboth--- a/cmds/terraform-provider-fleet/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-name = "terraform-provider-fleet"
-version.workspace = true
-edition.workspace = true
-rust-version.workspace = true
-
-[dependencies]
-anyhow.workspace = true
-serde = { workspace = true, features = ["derive"] }
-tokio.workspace = true
-
-async-trait.workspace = true
-tf-provider.workspace = true
cmds/terraform-provider-fleet/src/main.rsdiffbeforeafterboth--- a/cmds/terraform-provider-fleet/src/main.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
- panic!(
- "this is a stub, real provider is in development, I just don't want to keep it in different branch."
- )
-}
crates/better-command/Cargo.tomldiffbeforeafterboth--- a/crates/better-command/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-name = "better-command"
-version.workspace = true
-edition.workspace = true
-rust-version.workspace = true
-
-[dependencies]
-regex.workspace = true
-serde.workspace = true
-serde_json.workspace = true
-tracing.workspace = true
-
-tracing-indicatif = { workspace = true, optional = true }
-
-[features]
-indicatif = ["tracing-indicatif"]
crates/better-command/src/handler.rsdiffbeforeafterboth--- a/crates/better-command/src/handler.rs
+++ /dev/null
@@ -1,335 +0,0 @@
-//! Collection of handlers, which transform program-specific stdout format to tracing
-
-use std::{
- collections::HashMap,
- sync::{Arc, LazyLock, Mutex},
-};
-
-use regex::Regex;
-use serde::Deserialize;
-use tracing::{Span, info, info_span, warn};
-#[cfg(feature = "indicatif")]
-use tracing_indicatif::span_ext::IndicatifSpanExt as _;
-
-pub trait Handler: Send {
- fn handle_line(&mut self, e: &str);
-}
-
-/// Handler wrapper, which can be cloned.
-pub struct ClonableHandler<H>(Arc<Mutex<H>>);
-impl<H> Clone for ClonableHandler<H> {
- fn clone(&self) -> Self {
- Self(self.0.clone())
- }
-}
-impl<H> ClonableHandler<H> {
- pub fn new(inner: H) -> Self {
- Self(Arc::new(Mutex::new(inner)))
- }
-}
-impl<H: Handler> Handler for ClonableHandler<H> {
- fn handle_line(&mut self, e: &str) {
- self.0.lock().unwrap().handle_line(e)
- }
-}
-
-/// Converts command output to tracing lines
-pub struct PlainHandler;
-impl Handler for PlainHandler {
- fn handle_line(&mut self, e: &str) {
- info!(target: "log", "{e}");
- }
-}
-
-/// Ignores output
-pub struct NoopHandler;
-impl Handler for NoopHandler {
- fn handle_line(&mut self, _e: &str) {}
-}
-
-/// Transform nix internal-json logs to tracing spans.
-#[derive(Default)]
-pub struct NixHandler {
- spans: HashMap<u64, Span>,
-}
-#[derive(Deserialize, Debug)]
-#[serde(untagged)]
-enum LogField {
- String(String),
- Num(u64),
-}
-
-/// Nix internal-json log line type
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase", tag = "action")]
-#[allow(dead_code)]
-enum NixLog {
- Msg {
- level: u32,
- msg: String,
- raw_msg: Option<String>,
- },
- Start {
- id: u64,
- level: u32,
- #[serde(default)]
- fields: Vec<LogField>,
- text: String,
- #[serde(rename = "type")]
- typ: u32,
- },
- Stop {
- id: u64,
- },
- Result {
- id: u64,
- #[serde(rename = "type")]
- typ: u32,
- #[serde(default)]
- fields: Vec<LogField>,
- },
-}
-fn process_message(m: &str) -> String {
- // Supposed to remove formatting characters except colors, as some programs try to reset cursor position etc.
- static OSC_CLEANER: LazyLock<Regex> =
- LazyLock::new(|| Regex::new(r"\x1B\]([^\x07\x1C]*[\x07\x1C])?|\r").unwrap());
- static DETABBER: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\t").unwrap());
- let m = OSC_CLEANER.replace_all(m, "");
- // Indicatif can't format tabs. This is not the correct tab formatting, as correct one should be aligned,
- // and not just be replaced with the constant number of spaces, but it's ok for now, as statuses are single-line.
- DETABBER.replace_all(m.as_ref(), " ").to_string()
-}
-impl Handler for NixHandler {
- fn handle_line(&mut self, e: &str) {
- if let Some(e) = e.strip_prefix("@nix ") {
- let log: NixLog = match serde_json::from_str(e) {
- Ok(l) => l,
- Err(err) => {
- warn!("failed to parse nix log line {:?}: {}", e, err);
- return;
- }
- };
- match log {
- NixLog::Msg { msg, raw_msg, .. } => {
- #[allow(clippy::nonminimal_bool)]
- if !(msg.starts_with("\u{1b}[35;1mwarning:\u{1b}[0m Git tree '")
- && msg.ends_with("' is dirty"))
- && !msg.starts_with(
- "\u{1b}[35;1mwarning:\u{1b}[0m not writing modified lock file of flake",
- ) && msg
- != "\u{1b}[35;1mwarning:\u{1b}[0m \u{1b}[31;1merror:\u{1b}[0m SQLite database '\u{1b}[35;1m/nix/var/nix/db/db.sqlite\u{1b}[0m' is busy"
- {
- if let Some(raw_msg) = raw_msg {
- if !msg.is_empty() {
- info!(target: "nix", "{}\n{}", raw_msg.trim_end(), msg.trim_end())
- } else {
- info!(target: "nix", "{}", raw_msg.trim_end())
- }
- } else {
- info!(target: "nix", "{}", msg.trim_end())
- }
- }
- }
- NixLog::Start {
- ref fields,
- typ,
- id,
- ..
- } if typ == 105 && !fields.is_empty() => {
- if let [LogField::String(drv), ..] = &fields[..] {
- let mut drv = drv.as_str();
- if let Some(pkg) = drv.strip_prefix("/nix/store/") {
- let mut it = pkg.splitn(2, '-');
- it.next();
- if let Some(pkg) = it.next() {
- drv = pkg;
- }
- }
- info!(target: "nix","building {}", drv);
- let span = info_span!("build", drv);
- #[cfg(feature = "indicatif")]
- span.pb_start();
- self.spans.insert(id, span);
- } else {
- warn!("bad build log: {:?}", log)
- }
- }
- NixLog::Start {
- ref fields,
- typ,
- id,
- ..
- } if typ == 100 && fields.len() >= 3 => {
- if let [
- LogField::String(drv),
- LogField::String(from),
- LogField::String(to),
- ..,
- ] = &fields[..]
- {
- let mut drv = drv.as_str();
-
- if let Some(pkg) = drv.strip_prefix("/nix/store/") {
- let mut it = pkg.splitn(2, '-');
- it.next();
- if let Some(pkg) = it.next() {
- drv = pkg;
- }
- }
- info!(target: "nix","copying {} {} -> {}", drv, from, to);
- let span = info_span!("copy", from, to, drv);
- #[cfg(feature = "indicatif")]
- span.pb_start();
- self.spans.insert(id, span);
- } else {
- warn!("bad copy log: {:?}", log)
- }
- }
- NixLog::Start { text, typ, id, .. }
- if typ == 0 || typ == 102 || typ == 103 || typ == 104 =>
- {
- if !text.is_empty()
- && text != "querying info about missing paths"
- && text != "copying 0 paths"
- // Too much spam on lazy-trees branch
- && !(text.starts_with("copying '") && text.ends_with("' to the store"))
- {
- let span = info_span!("job");
- #[cfg(feature = "indicatif")]
- {
- span.pb_start();
- span.pb_set_message(&process_message(text.trim()));
- }
- self.spans.insert(id, span);
- info!(target: "nix", "{}", text);
- }
- }
- NixLog::Start {
- text,
- level: 0,
- typ: 108,
- ..
- } if text.is_empty() => {
- // Cache lookup? Coupled with copy log
- }
- NixLog::Start {
- text,
- level: 4,
- typ: 109,
- ..
- } if text.starts_with("querying info about ") => {
- // Cache lookup
- }
- NixLog::Start {
- text,
- level: 4,
- typ: 101,
- ..
- } if text.starts_with("downloading ") => {
- // NAR downloading, coupled with copy log
- }
- NixLog::Start {
- text,
- level: 1,
- typ: 111,
- ..
- } if text.starts_with("waiting for a machine to build ") => {
- // Useless repeating notification about build
- }
- NixLog::Start {
- text,
- level: 3,
- typ: 111,
- ..
- } if text.starts_with("resolved derivation: ") => {
- // CA resolved
- }
- NixLog::Start {
- text,
- level: 1,
- typ: 111,
- id,
- ..
- } if text.starts_with("waiting for lock on ") => {
- let mut drv = text.strip_prefix("waiting for lock on ").unwrap();
- if let Some(txt) = drv.strip_prefix("\u{1b}[35;1m'") {
- drv = txt;
- }
- if let Some(txt) = drv.strip_suffix("'\u{1b}[0m") {
- drv = txt;
- }
- if let Some(txt) = drv.split("', '").next() {
- drv = txt;
- }
- if let Some(pkg) = drv.strip_prefix("/nix/store/") {
- let mut it = pkg.splitn(2, '-');
- it.next();
- if let Some(pkg) = it.next() {
- drv = pkg;
- }
- }
- let span = info_span!("waiting on drv", drv);
- #[cfg(feature = "indicatif")]
- span.pb_start();
- self.spans.insert(id, span);
- // Concurrent build of the same message
- }
- NixLog::Stop { id, .. } => {
- self.spans.remove(&id);
- }
- NixLog::Result { fields, id, typ } if typ == 101 && !fields.is_empty() => {
- if let Some(span) = self.spans.get(&id) {
- if let LogField::String(s) = &fields[0] {
- #[cfg(feature = "indicatif")]
- span.pb_set_message(&process_message(s.trim()));
- #[cfg(not(feature = "indicatif"))]
- {
- let _span = span.enter();
- info!("{}", process_message(s));
- }
- } else {
- warn!("bad fields: {fields:?}");
- }
- } else {
- warn!("unknown result id: {id} {typ} {fields:?}");
- }
- // dbg!(fields, id, typ);
- }
- NixLog::Result { fields, id, typ } if typ == 105 && fields.len() >= 4 => {
- if let Some(span) = self.spans.get(&id) {
- if let [
- LogField::Num(done),
- LogField::Num(expected),
- LogField::Num(_running),
- LogField::Num(_failed),
- ] = &fields[..4]
- {
- #[cfg(feature = "indicatif")]
- {
- span.pb_set_length(*expected);
- span.pb_set_position(*done);
- }
- let _ = (span, done, expected);
- } else {
- warn!("bad fields: {fields:?}");
- }
- } else {
- // warn!("unknown result id: {id} {typ} {fields:?}");
- // Unaccounted progress.
- }
- // dbg!(fields, id, typ);
- }
- NixLog::Result { typ, .. } if typ == 104 || typ == 106 => {
- // Set phase, expected
- }
- _ => warn!("unknown log: {:?}", log),
- };
- } else {
- let e = e.trim();
- if e.starts_with("Failed tcsetattr(TCSADRAIN): ") {
- return;
- }
- info!("{e}")
- }
- }
-}
crates/better-command/src/lib.rsdiffbeforeafterboth--- a/crates/better-command/src/lib.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-mod handler;
-pub use handler::{ClonableHandler, Handler, NixHandler, NoopHandler, PlainHandler};
crates/fleet-base/Cargo.tomldiffbeforeafterboth--- a/crates/fleet-base/Cargo.toml
+++ b/crates/fleet-base/Cargo.toml
@@ -5,9 +5,15 @@
rust-version.workspace = true
[dependencies]
+remowt-client.workspace = true
+remowt-endpoints.workspace = true
+remowt-fleet.workspace = true
+remowt-link-shared.workspace = true
+remowt-ui-prompt.workspace = true
+
age.workspace = true
anyhow.workspace = true
-better-command.workspace = true
+camino.workspace = true
chrono.workspace = true
clap = { workspace = true, features = ["derive"] }
fleet-shared.workspace = true
@@ -18,15 +24,11 @@
nix-eval.workspace = true
nixlike.workspace = true
nom.workspace = true
-openssh.workspace = true
rand.workspace = true
serde.workspace = true
serde_json.workspace = true
tabled.workspace = true
tempfile.workspace = true
-thiserror.workspace = true
time = { workspace = true, features = ["parsing"] }
tokio.workspace = true
-tokio-util = { workspace = true, features = ["codec"] }
-toml_edit.workspace = true
tracing.workspace = true
crates/fleet-base/src/command.rsdiffbeforeafterboth--- a/crates/fleet-base/src/command.rs
+++ /dev/null
@@ -1,442 +0,0 @@
-use std::{ffi::OsStr, pin, process::Stdio, sync::Arc, task::Poll};
-
-use anyhow::{Result, anyhow};
-use better_command::{Handler, NixHandler, PlainHandler};
-use futures::StreamExt;
-use itertools::Either;
-use openssh::{OverSsh, OwningCommand, Session};
-use serde::de::DeserializeOwned;
-use tokio::{io::AsyncRead, process::Command, select};
-use tokio_util::codec::{BytesCodec, FramedRead, LinesCodec};
-use tracing::debug;
-
-use crate::host::EscalationStrategy;
-
-fn escape_bash(input: &str, out: &mut String) {
- const TO_ESCAPE: &str = "$ !\"#&'()*,;<>?[\\]^`{|}";
- if input.chars().all(|c| !TO_ESCAPE.contains(c)) {
- out.push_str(input);
- return;
- }
- out.push('\'');
- for (i, v) in input.split('\'').enumerate() {
- if i != 0 {
- out.push_str("'\"'\"'");
- }
- out.push_str(v);
- }
- out.push('\'');
-}
-fn ostoutf8(os: impl AsRef<OsStr>) -> String {
- os.as_ref().to_str().expect("non-utf8 data").to_owned()
-}
-
-#[derive(Clone, Debug)]
-pub struct MyCommand {
- command: String,
- args: Vec<String>,
- env: Vec<(String, String)>,
- ssh_session: Option<Arc<Session>>,
- escalation: EscalationStrategy,
- escalate: bool,
-}
-impl MyCommand {
- pub fn new_on(
- escalation: EscalationStrategy,
- cmd: impl AsRef<OsStr>,
- session: Arc<Session>,
- ) -> Self {
- assert!(!cmd.as_ref().is_empty());
- Self {
- command: ostoutf8(cmd),
- args: vec![],
- env: vec![],
- ssh_session: Some(session),
- escalation,
- escalate: false,
- }
- }
- pub fn new(escalation: EscalationStrategy, cmd: impl AsRef<OsStr>) -> Self {
- assert!(!cmd.as_ref().is_empty());
- Self {
- command: ostoutf8(cmd),
- args: vec![],
- env: vec![],
- ssh_session: None,
- escalation,
- escalate: false,
- }
- }
- fn new_here(&self, cmd: impl AsRef<OsStr>) -> Self {
- match self.ssh_session.clone() {
- Some(ssh_session) => Self::new_on(self.escalation, cmd, ssh_session),
- _ => Self::new(self.escalation, cmd),
- }
- }
-
- fn into_args(self) -> Vec<String> {
- let mut out = Vec::new();
- if !self.env.is_empty() {
- out.push("env".to_owned());
- for (k, v) in self.env {
- assert!(!k.contains('='));
- out.push(format!("{k}={v}"));
- }
- }
- out.push(self.command);
- out.extend(self.args);
- out
- }
-
- /// Translates environment variables into env command execution.
- /// Required for ssh, as ssh don't allow to send environment variables (at least by default).
- ///
- /// FIXME: Insecure, as arguments might be seen by other users on the same machine.
- /// Figure out some way to transfer environment using stdio?
- fn translate_env_into_env(self) -> Self {
- if self.env.is_empty() {
- return self;
- }
- let mut out = self.new_here("env");
- for (k, v) in self.env {
- assert!(!k.contains('='));
- out.arg(format!("{k}={v}"));
- }
- out.arg(self.command);
- out.args(self.args);
-
- out
- }
- fn into_string(self) -> String {
- let mut out = String::new();
- if !self.env.is_empty() {
- out.push_str("env");
- for (k, v) in self.env {
- out.push(' ');
- assert!(!k.contains('='));
- escape_bash(&k, &mut out);
- out.push('=');
- escape_bash(&v, &mut out);
- }
- }
- if !out.is_empty() {
- out.push(' ');
- }
- escape_bash(&self.command, &mut out);
- for arg in self.args {
- out.push(' ');
- escape_bash(&arg, &mut out);
- }
- out
- }
- fn into_command_unchecked_local(self) -> Command {
- let mut out = Command::new(self.command);
- out.args(self.args);
- for (k, v) in self.env {
- out.env(k, v);
- }
- out
- }
- fn into_command(self) -> Result<Either<Command, openssh::OwningCommand<Arc<Session>>>> {
- Ok(match self.ssh_session.clone() {
- Some(session) => {
- let cmd = self.translate_env_into_env().into_command_unchecked_local();
- Either::Right(
- cmd.over_ssh(session)
- .map_err(|e| anyhow!("ssh error: {e}"))?,
- )
- }
- _ => {
- let cmd = self.into_command_unchecked_local();
- Either::Left(cmd)
- }
- })
- }
- pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
- let arg = arg.as_ref();
- self.args.push(ostoutf8(arg));
- self
- }
- pub fn eqarg(&mut self, arg: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Self {
- let arg = arg.as_ref();
- let value = value.as_ref();
- let arg = ostoutf8(arg);
- let value = ostoutf8(value);
- self.arg(format!("{arg}={value}"));
- self
- }
- pub fn comparg(&mut self, arg: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Self {
- self.arg(arg);
- self.arg(value);
- self
- }
- pub fn env(&mut self, name: impl AsRef<str>, value: impl AsRef<str>) -> &mut Self {
- self.env
- .push((name.as_ref().to_owned(), value.as_ref().to_owned()));
- self
- }
- pub fn args<V: AsRef<OsStr>>(&mut self, args: impl IntoIterator<Item = V>) -> &mut Self {
- for arg in args.into_iter() {
- let arg = arg.as_ref();
- self.args.push(ostoutf8(arg));
- }
- self
- }
- pub fn sudo(mut self) -> Self {
- self.escalate = true;
- self
- }
- fn wrap_sudo_if_needed(self) -> Self {
- if !self.escalate {
- return self;
- }
- match self.escalation {
- EscalationStrategy::Su => {
- let mut out = self.new_here("su");
- out.arg("-c").arg(self.into_string());
- out
- }
- EscalationStrategy::Sudo => {
- let mut out = self.new_here("sudo");
- out.args(self.into_args());
- out
- }
- EscalationStrategy::Run0 => {
- // run0 wants interactive authentication by default.
- let mut run0 = self.new_here("run0");
- let mut out = self.new_here("script");
-
- // Red backgrounds messes with fleet formatting
- run0.arg("--background=");
- run0.args(self.into_args());
-
- out.arg("-q");
- out.arg("/dev/null");
- out.arg("-c");
- out.arg(run0.into_string());
- dbg!(&out);
- out
- }
- }
- }
-
- pub async fn run(self) -> Result<()> {
- let str = self.clone().into_string();
- let cmd = self.wrap_sudo_if_needed().into_command()?;
- match cmd {
- Either::Left(cmd) => run_nix_inner(str, cmd, &mut PlainHandler).await?,
- Either::Right(cmd) => run_nix_inner_ssh(str, cmd, &mut PlainHandler).await?,
- };
- Ok(())
- }
- pub async fn run_string(self) -> Result<String> {
- let bytes = self.run_bytes().await?;
- Ok(String::from_utf8(bytes)?)
- }
- pub async fn run_value<T: DeserializeOwned>(self) -> Result<T> {
- let v = self.run_string().await?;
- Ok(serde_json::from_str(&v)?)
- }
- pub async fn run_bytes(self) -> Result<Vec<u8>> {
- let str = self.clone().into_string();
- let cmd = self.wrap_sudo_if_needed().into_command()?;
- let v = match cmd {
- Either::Left(cmd) => run_nix_inner_stdout(str, cmd, &mut PlainHandler).await?,
- Either::Right(cmd) => run_nix_inner_stdout_ssh(str, cmd, &mut PlainHandler).await?,
- };
- Ok(v)
- }
-
- pub async fn run_nix_string(mut self) -> Result<String> {
- let str = self.clone().into_string();
- self.arg("--log-format").arg("internal-json");
- let cmd = self.wrap_sudo_if_needed().into_command()?;
- let bytes = match cmd {
- Either::Left(cmd) => run_nix_inner_stdout(str, cmd, &mut NixHandler::default()).await?,
- Either::Right(cmd) => {
- run_nix_inner_stdout_ssh(str, cmd, &mut NixHandler::default()).await?
- }
- };
- Ok(String::from_utf8(bytes)?)
- }
- pub async fn run_nix(mut self) -> Result<()> {
- let str = self.clone().into_string();
- self.arg("--log-format").arg("internal-json");
- let cmd = self.wrap_sudo_if_needed().into_command()?;
- match cmd {
- Either::Left(mut cmd) => {
- cmd.stdout(Stdio::inherit());
- run_nix_inner(str, cmd, &mut NixHandler::default()).await
- }
- Either::Right(mut cmd) => {
- cmd.stdout(openssh::Stdio::inherit());
- run_nix_inner_ssh(str, cmd, &mut NixHandler::default()).await
- }
- }
- }
-}
-
-struct EmptyAsyncRead;
-impl AsyncRead for EmptyAsyncRead {
- fn poll_read(
- self: std::pin::Pin<&mut Self>,
- _cx: &mut std::task::Context<'_>,
- _buf: &mut tokio::io::ReadBuf<'_>,
- ) -> Poll<std::io::Result<()>> {
- Poll::Pending
- }
-}
-
-async fn run_nix_inner_stdout(
- str: String,
- cmd: Command,
- handler: &mut dyn Handler,
-) -> Result<Vec<u8>> {
- Ok(run_nix_inner_raw(str, cmd, true, handler, None)
- .await?
- .expect("has out"))
-}
-async fn run_nix_inner(str: String, cmd: Command, handler: &mut dyn Handler) -> Result<()> {
- let v = run_nix_inner_raw(str, cmd, false, handler, None).await?;
- assert!(v.is_none());
- Ok(())
-}
-async fn run_nix_inner_stdout_ssh(
- str: String,
- cmd: OwningCommand<Arc<Session>>,
- handler: &mut dyn Handler,
-) -> Result<Vec<u8>> {
- Ok(run_nix_inner_raw_ssh(str, cmd, true, handler, None)
- .await?
- .expect("has out"))
-}
-async fn run_nix_inner_ssh(
- str: String,
- cmd: OwningCommand<Arc<Session>>,
- handler: &mut dyn Handler,
-) -> Result<()> {
- let v = run_nix_inner_raw_ssh(str, cmd, false, handler, None).await?;
- assert!(v.is_none());
- Ok(())
-}
-
-async fn run_nix_inner_raw(
- str: String,
- mut cmd: Command,
- want_stdout: bool,
- err_handler: &mut dyn Handler,
- mut out_handler: Option<&mut dyn Handler>,
-) -> Result<Option<Vec<u8>>> {
- cmd.stderr(Stdio::piped());
- cmd.stdout(Stdio::piped());
- debug!("running command {str:?} on local");
- let mut child = cmd.spawn()?;
- let mut stderr = child.stderr.take().unwrap();
- let stdout = child.stdout.take().unwrap();
- let mut err = FramedRead::new(&mut stderr, LinesCodec::new());
- let mut out: Option<Box<dyn AsyncRead + Unpin + Send>> = Some(Box::new(stdout));
- let mut ob = want_stdout
- .then(|| out.take().unwrap())
- .unwrap_or_else(|| Box::new(EmptyAsyncRead));
- let mut ol = (!want_stdout)
- .then(|| out.take().unwrap())
- .unwrap_or_else(|| Box::new(EmptyAsyncRead));
- let mut ob = FramedRead::new(&mut ob, BytesCodec::new());
- let mut ol = FramedRead::new(&mut ol, LinesCodec::new());
-
- // while let Some(line) = read.next().await? {}
-
- let mut out_buf = if want_stdout { Some(vec![]) } else { None };
- loop {
- select! {
- biased;
-
- Some(e) = err.next() => {
- let e = e?;
- err_handler.handle_line(&e);
- },
- Some(o) = ob.next() => {
- out_buf.as_mut().expect("stdout == wants_stdout").extend_from_slice(&o?);
- },
- Some(o) = ol.next() => {
- let o = o?;
- if let Some(out) = out_handler.as_mut() {
- out.handle_line(&o)
- } else {
- err_handler.handle_line(&o)
- }
- // out_handler.handle_info(&o);
- },
- code = child.wait() => {
- let code = code?;
- if !code.success() {
- anyhow::bail!("command '{str}' failed with status {}", code);
- }
- break;
- }
- }
- }
-
- Ok(out_buf)
-}
-async fn run_nix_inner_raw_ssh(
- str: String,
- mut cmd: OwningCommand<Arc<Session>>,
- want_stdout: bool,
- err_handler: &mut dyn Handler,
- mut out_handler: Option<&mut dyn Handler>,
-) -> Result<Option<Vec<u8>>> {
- debug!("running command {str:?} over ssh");
- cmd.stderr(openssh::Stdio::piped());
- cmd.stdout(openssh::Stdio::piped());
- let mut child = cmd.spawn().await?;
- let mut stderr = child.stderr().take().unwrap();
- let stdout = child.stdout().take().unwrap();
- let mut err = FramedRead::new(&mut stderr, LinesCodec::new());
- let mut out: Option<Box<dyn AsyncRead + Unpin + Send>> = Some(Box::new(stdout));
- let mut ob = want_stdout
- .then(|| out.take().unwrap())
- .unwrap_or_else(|| Box::new(EmptyAsyncRead));
- let mut ol = (!want_stdout)
- .then(|| out.take().unwrap())
- .unwrap_or_else(|| Box::new(EmptyAsyncRead));
- let mut ob = FramedRead::new(&mut ob, BytesCodec::new());
- let mut ol = FramedRead::new(&mut ol, LinesCodec::new());
-
- // while let Some(line) = read.next().await? {}
-
- let mut out_buf = if want_stdout { Some(vec![]) } else { None };
-
- let mut wait_future = pin::pin!(child.wait());
- loop {
- select! {
- biased;
-
- Some(e) = err.next() => {
- let e = e?;
- err_handler.handle_line(&e);
- },
- Some(o) = ob.next() => {
- out_buf.as_mut().expect("stdout == wants_stdout").extend_from_slice(&o?);
- },
- Some(o) = ol.next() => {
- let o = o?;
- if let Some(out) = out_handler.as_mut() {
- out.handle_line(&o)
- } else {
- err_handler.handle_line(&o)
- }
- // out_handler.handle_info(&o);
- },
- code = &mut wait_future => {
- let code = code?;
- if !code.success() {
- anyhow::bail!("command '{str}' failed with status {}", code);
- }
- break;
- }
- }
- }
-
- Ok(out_buf)
-}
crates/fleet-base/src/deploy.rsdiffbeforeafterboth--- a/crates/fleet-base/src/deploy.rs
+++ b/crates/fleet-base/src/deploy.rs
@@ -1,8 +1,13 @@
-use std::{path::PathBuf, time::Duration};
+use std::time::Duration;
use anyhow::{Context as _, Result, anyhow, bail};
+use camino::Utf8PathBuf;
use clap::ValueEnum;
use itertools::Itertools;
+use remowt_endpoints::fs::FsClient;
+use remowt_endpoints::systemd::SystemdClient;
+use remowt_fleet::NixClient;
+use remowt_link_shared::BifConfig;
use tokio::time::sleep;
use tracing::{Instrument as _, error, info, info_span, warn};
@@ -59,10 +64,11 @@
pub async fn deploy_task(
action: DeployAction,
host: &ConfigHost,
- built: PathBuf,
+ built: Utf8PathBuf,
specialisation: Option<String>,
disable_rollback: bool,
) -> Result<()> {
+ let remowt = host.remowt().await?;
let deploy_kind = host.deploy_kind().await?;
if (deploy_kind == DeployKind::NixosInstall || deploy_kind == DeployKind::NixosLustrate)
&& !matches!(action, DeployAction::Boot | DeployAction::Upload)
@@ -86,7 +92,7 @@
generation.id, generation.datetime
);
{
- let mut cmd = host.cmd("sh").await?;
+ let mut cmd = remowt.cmd("sh");
cmd.arg("-c").arg(format!("mark=$(mktemp -p /etc -t fleet_rollback_marker.XXXXX) && echo -n {} > $mark && mv --no-clobber $mark /etc/fleet_rollback_marker", generation.id));
if let Err(e) = cmd.sudo().run().await {
error!("failed to set rollback marker: {e}");
@@ -104,7 +110,7 @@
// if we fail to perform generation switch in time, then we will still call the activation script, and this may break something.
// Anyway, reboot will still help in this case.
if action.should_schedule_rollback_run() {
- let mut cmd = host.cmd("systemd-run").await?;
+ let mut cmd = remowt.cmd("systemd-run");
cmd.comparg("--on-active", "3min")
.comparg("--unit", "rollback-watchdog-run")
.arg("systemctl")
@@ -116,14 +122,20 @@
}
}
}
+
+ let remowt = host.remowt().await?;
+ let fs = remowt.endpoints::<FsClient<_>>();
if deploy_kind == DeployKind::NixosLustrate {
// Fleet could also create this file, but as this operation is potentially disruptive,
// make user do it themself.
- if !host.file_exists("/etc/NIXOS_LUSTRATE").await? {
+ if !fs
+ .file_exists(Utf8PathBuf::from("/etc/NIXOS_LUSTRATE"))
+ .await?
+ {
bail!("/etc/NIXOS_LUSTRATE should be created on remote host");
}
// Wanted by NixOS to recognize the system as NixOS.
- let mut cmd = host.cmd("touch").await?;
+ let mut cmd = remowt.cmd("touch");
cmd.arg("/etc/NIXOS");
cmd.sudo().run().await.context("creating /etc/NIXOS")?;
}
@@ -131,7 +143,7 @@
info!(
"running nixos-install to switch profile, install bootloader, and perform activation"
);
- let mut cmd = host.cmd("nixos-install").await?;
+ let mut cmd = remowt.cmd("nixos-install");
cmd.arg("--system").arg(&built).args([
// Channels here aren't fleet host system channels, but channels embedded in installation cd, which might be old.
// It is possible to copy host channels, but I would prefer non-flake nix just to be unsupported.
@@ -147,32 +159,38 @@
if action.should_switch_profile() && !failed {
info!("switching system profile generation");
- // To avoid even more problems, using nixos-install for now.
- // // nix build is unable to work with --store argument for some reason, and nix until 2.26 didn't support copy with --profile argument,
- // // falling back to using nix-env command
- // // After stable NixOS starts using 2.26 - use `nix --store /mnt copy --from /mnt --profile ...` here, and instead of nix build below.
- // let mut cmd = host.cmd("nix-env").await?;
- // cmd.args([
- // "--store",
- // "/mnt",
- // "--profile",
- // "/mnt/nix/var/nix/profiles/system",
- // "--set",
- // ])
- // .arg(&built);
- // if let Err(e) = cmd.sudo().run_nix().await {
- // error!("failed to switch system profile generation: {e}");
- // failed = true;
- // }
- // It would also be possible to update profile atomically during copy:
- // https://github.com/NixOS/nix/pull/11657
- let mut cmd = host.nix_cmd().await?;
- cmd.arg("build");
- cmd.comparg("--profile", "/nix/var/nix/profiles/system");
- cmd.arg(&built);
- if let Err(e) = cmd.sudo().run_nix().await {
- error!("failed to switch system profile generation: {e}");
- failed = true;
+ match host.ensure_nix_plugin().await {
+ Ok(plugin_id) => {
+ let nix_elevated = remowt.plugin_endpoints::<NixClient<_>>(plugin_id);
+ // To avoid even more problems, using nixos-install for now.
+ // // nix build is unable to work with --store argument for some reason, and nix until 2.26 didn't support copy with --profile argument,
+ // // falling back to using nix-env command
+ // // After stable NixOS starts using 2.26 - use `nix --store /mnt copy --from /mnt --profile ...` here, and instead of nix build below.
+ // let mut cmd = host.cmd("nix-env").await?;
+ // cmd.args([
+ // "--store",
+ // "/mnt",
+ // "--profile",
+ // "/mnt/nix/var/nix/profiles/system",
+ // "--set",
+ // ])
+ // .arg(&built);
+ // if let Err(e) = cmd.sudo().run_nix().await {
+ // error!("failed to switch system profile generation: {e}");
+ // failed = true;
+ // }
+ if let Err(e) = nix_elevated
+ .switch_profile("/nix/var/nix/profiles/system".to_owned(), built.clone())
+ .await
+ {
+ error!("failed to switch system profile generation: {e}");
+ failed = true;
+ }
+ }
+ Err(e) => {
+ failed = true;
+ error!("failed to enable nix plugin: {e:?}");
+ }
}
}
@@ -189,7 +207,7 @@
built.clone()
};
let switch_script = specialised.join("bin/switch-to-configuration");
- let mut cmd = host.cmd("systemd-run").in_current_span().await?;
+ let mut cmd = remowt.cmd("systemd-run");
if deploy_kind == DeployKind::NixosLustrate {
cmd.arg("--setenv=NIXOS_INSTALL_BOOTLOADER=1");
}
@@ -209,12 +227,14 @@
}
}
if action.should_create_rollback_marker() {
+ let elevated_systemd = remowt.run0_endpoints::<SystemdClient<BifConfig>>().await?;
+ let elevated_fs = remowt.run0_endpoints::<FsClient<BifConfig>>().await?;
if !disable_rollback {
if failed {
if action.should_schedule_rollback_run() {
info!("executing rollback");
- if let Err(e) = host
- .systemctl_start("rollback-watchdog.service")
+ if let Err(e) = elevated_systemd
+ .start("rollback-watchdog.service".to_owned())
.instrument(info_span!("rollback"))
.await
{
@@ -223,8 +243,8 @@
}
} else {
info!("trying to mark upgrade as successful");
- if let Err(e) = host
- .rm_file("/etc/fleet_rollback_marker", true)
+ if let Err(e) = elevated_fs
+ .rm_file(Utf8PathBuf::from("/etc/fleet_rollback_marker"))
.in_current_span()
.await
{
@@ -234,16 +254,22 @@
}
}
info!("disarming watchdog, just in case");
- if let Err(_e) = host.systemctl_stop("rollback-watchdog.timer").await {
+ if let Err(_e) = elevated_systemd
+ .stop("rollback-watchdog.timer".to_owned())
+ .await
+ {
// It is ok, if there was no reboot - then timer might not be running.
}
if action.should_schedule_rollback_run() {
- if let Err(e) = host.systemctl_stop("rollback-watchdog-run.timer").await {
+ if let Err(e) = elevated_systemd
+ .stop("rollback-watchdog-run.timer".to_owned())
+ .await
+ {
error!("failed to disarm rollback run: {e}");
}
}
- } else if let Err(_e) = host
- .rm_file("/etc/fleet_rollback_marker", true)
+ } else if let Err(_e) = elevated_fs
+ .rm_file(Utf8PathBuf::from("/etc/fleet_rollback_marker"))
.in_current_span()
.await
{
@@ -257,8 +283,8 @@
config: &Config,
host: &ConfigHost,
location: GenerationStorage,
- generation: PathBuf,
-) -> Result<PathBuf> {
+ generation: Utf8PathBuf,
+) -> Result<Utf8PathBuf> {
if matches!(location, GenerationStorage::Pusher) {
bail!("pusher is not enabled in this version of fleet");
}
@@ -273,11 +299,11 @@
}
Err(e) if tries < 3 => {
tries += 1;
- warn!("copy failure ({}/3): {}", tries, e);
+ warn!("copy failure ({}/3): {:#}", tries, e);
sleep(Duration::from_millis(5000)).await;
}
Err(e) => {
- bail!("upload failed: {e}");
+ bail!("upload failed: {e:#}");
}
}
}
crates/fleet-base/src/fleetdata.rsdiffbeforeafterboth--- a/crates/fleet-base/src/fleetdata.rs
+++ b/crates/fleet-base/src/fleetdata.rs
@@ -144,10 +144,6 @@
pub generation_data: Value,
}
-fn is_false(b: &bool) -> bool {
- *b == false
-}
-
#[derive(Serialize, Deserialize, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
#[repr(transparent)]
pub struct SecretOwner(String);
@@ -291,7 +287,7 @@
}
// Which one is easier to access
- return a.owners.len().cmp(&b.owners.len());
+ a.owners.len().cmp(&b.owners.len())
}
impl FleetSecretDistributions {
crates/fleet-base/src/host.rsdiffbeforeafterboth--- a/crates/fleet-base/src/host.rs
+++ b/crates/fleet-base/src/host.rs
@@ -1,30 +1,33 @@
use std::{
collections::{BTreeMap, BTreeSet, HashSet},
- ffi::{OsStr, OsString},
- fmt::Display,
+ future::Future,
io::Write,
ops::Deref,
path::PathBuf,
+ pin::Pin,
str::FromStr,
- sync::{Arc, Mutex, MutexGuard, OnceLock},
+ sync::{Arc, OnceLock},
};
use anyhow::{Context, Result, anyhow, bail, ensure};
+use camino::{Utf8Path, Utf8PathBuf};
use chrono::{DateTime, Utc};
use fleet_shared::SecretData;
-use nix_eval::{Value, nix_go, nix_go_json, util::assert_warn};
-use openssh::{ControlPersist, SessionBuilder};
-use serde::de::DeserializeOwned;
+use nix_eval::{Store, Value, nix_go, nix_go_json, util::assert_warn};
+use remowt_client::{AgentBundle, Remowt};
+use remowt_endpoints::fs::FsClient;
+use remowt_link_shared::Address;
+use remowt_ui_prompt::auto::AutoPrompter;
+use remowt_ui_prompt::bifrost::PromptEndpoints;
+use remowt_ui_prompt::{PrependSourcePrompter, Source};
use tabled::Tabled;
use tempfile::NamedTempFile;
-use time::{UtcDateTime, format_description};
-use tracing::warn;
+use time::UtcDateTime;
+use tokio::task::spawn_blocking;
+use tracing::{info, warn};
-use crate::{
- command::MyCommand,
- fleetdata::{
- FleetData, FleetSecretData, FleetSecretDistribution, FleetSecretPart, SecretOwner,
- },
+use crate::fleetdata::{
+ FleetData, FleetSecretData, FleetSecretDistribution, FleetSecretPart, SecretOwner,
};
pub struct FleetConfigInternals {
@@ -36,7 +39,6 @@
/// builtins.currentSystem
pub local_system: String,
pub data: Arc<FleetData>,
- pub nix_args: Vec<OsString>,
/// fleet_config.config
pub config_field: Value,
/// flake.output
@@ -48,6 +50,8 @@
pub default_pkgs: Value,
/// inputs.nixpkgs
pub nixpkgs: Value,
+
+ pub local_host: OnceLock<Arc<ConfigHost>>,
}
// TODO: Make field not pub
@@ -62,13 +66,6 @@
}
}
-#[derive(Clone, Copy, Debug)]
-pub enum EscalationStrategy {
- Sudo,
- Run0,
- Su,
-}
-
#[derive(Clone, PartialEq, Copy, Debug)]
pub enum DeployKind {
/// NixOS => NixOS managed by fleet
@@ -115,9 +112,26 @@
// TODO: Move command helpers away with connectivity refactor
pub local: bool,
- pub session: OnceLock<Arc<openssh::Session>>,
+ pub remowt: OnceLock<Remowt>,
+ nix_store: OnceLock<Arc<Store>>,
+ nix_plugin: tokio::sync::OnceCell<()>,
}
+const NIX_PLUGIN_ID: u16 = 2;
+
+fn agents_dir() -> Result<PathBuf> {
+ std::env::var_os("REMOWT_AGENTS_DIR")
+ .map(PathBuf::from)
+ .or_else(|| option_env!("REMOWT_AGENTS_DIR").map(PathBuf::from))
+ .ok_or_else(|| {
+ anyhow!("no remowt-agents bundle; set REMOWT_AGENTS_DIR to a remowt-agents output")
+ })
+}
+
+fn agent_bundle() -> Result<AgentBundle> {
+ AgentBundle::from_dir(agents_dir()?)
+}
+
#[derive(Debug, Clone, Copy)]
pub enum GenerationStorage {
Deployer,
@@ -143,7 +157,7 @@
#[tabled(rename = "Created at")]
pub datetime: UtcDateTime,
#[tabled(format = "{:?}")]
- pub store_path: PathBuf,
+ pub store_path: Utf8PathBuf,
#[tabled(skip)]
pub location: GenerationStorage,
}
@@ -153,68 +167,36 @@
}
}
-fn parse_generation_line(g: &str) -> Option<Generation> {
- let mut parts = g.split_whitespace();
- let id = parts.next()?;
- let id: u32 = id.parse().ok()?;
- let date = parts.next()?;
- let time = parts.next()?;
- let current = if let Some(current) = parts.next() {
- if current == "(current)" {
- Some(true)
- } else {
- None
- }
- } else {
- Some(false)
- };
- let current = current?;
- if parts.next().is_some() {
- warn!("unexpected text after generation: {g}");
- }
-
- let format = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")
- .expect("valid format");
- let datetime = UtcDateTime::parse(&format!("{date} {time}"), &format).ok()?;
-
- Some(Generation {
- id,
- current,
- datetime,
- store_path: PathBuf::new(),
- location: GenerationStorage::Machine,
- })
-}
-// TODO: Move command helpers away with connectivity refactor
impl ConfigHost {
pub async fn list_generations(&self, profile: &str) -> Result<Vec<Generation>> {
- let mut cmd = self.cmd("nix-env").await?;
- cmd.comparg("--profile", format!("/nix/var/nix/profiles/{profile}"))
- .arg("--list-generations")
- .env("TZ", "UTC");
- // Sudo is required because --list-generations tries to acquire profile lock
- let data = cmd.sudo().run_string().await?;
- let mut generations = data
- .split('\n')
- .map(|e| e.trim())
- .filter(|&l| !l.is_empty())
- .filter_map(|g| {
- let generation = parse_generation_line(g);
- if generation.is_none() {
- warn!("bad generation: {g}");
- };
- generation
+ let plugin_id = self.ensure_nix_plugin().await?;
+ let nix = self
+ .remowt()
+ .await?
+ .plugin_endpoints::<remowt_fleet::NixClient<_>>(plugin_id);
+ let raw = nix
+ .list_generations(profile.to_owned())
+ .await
+ .map_err(|e| anyhow!("{e:?}"))?
+ .map_err(|e| anyhow!("{e}"))?;
+ raw.into_iter()
+ .map(|g| {
+ let id: u32 =
+ g.id.try_into()
+ .with_context(|| format!("generation id {} doesn't fit in u32", g.id))?;
+ let datetime = UtcDateTime::from_unix_timestamp(g.creation_time_unix)
+ .with_context(|| {
+ format!("invalid generation timestamp {}", g.creation_time_unix)
+ })?;
+ Ok(Generation {
+ id,
+ current: g.current,
+ datetime,
+ store_path: g.store_path,
+ location: GenerationStorage::Machine,
+ })
})
- .collect::<Vec<_>>();
- for ele in generations.iter_mut() {
- let mut cmd = self.cmd("readlink").await?;
- cmd.arg("--")
- .arg(format!("/nix/var/nix/profiles/{profile}-{}-link", ele.id));
- let path = cmd.run_string().await?;
- ele.store_path = PathBuf::from(path.trim_end_matches("\n"));
- }
-
- Ok(generations)
+ .collect()
}
pub fn set_session_destination(&self, dest: String) {
@@ -236,7 +218,9 @@
if let Some(kind) = self.deploy_kind.get() {
return Ok(*kind);
}
- let is_fleet_managed = match self.file_exists("/etc/FLEET_HOST").await {
+ let remowt = self.remowt().await?;
+ let fs = remowt.endpoints::<FsClient<_>>();
+ let is_fleet_managed = match fs.file_exists(Utf8PathBuf::from("/etc/FLEET_HOST")).await {
Ok(v) => v,
Err(e) => {
bail!("failed to query remote system kind: {e}");
@@ -252,6 +236,7 @@
1. manually create /etc/FLEET_HOST file on the target host,
2. use ?deploy_kind=fleet host argument if you're upgrading from older version of fleet
3. use ?deploy_kind=upgrade_to_fleet if you're upgrading from plain nixos to fleet-managed nixos
+ for installation use ?deploy_kind=nixos_install / ?deploy_kind=nixos_lustrate
"}
);
}
@@ -259,139 +244,101 @@
let _ = self.deploy_kind.set(DeployKind::Fleet);
Ok(*self.deploy_kind.get().expect("deploy kind is just set"))
}
- pub async fn escalation_strategy(&self) -> Result<EscalationStrategy> {
- // Prefer sudo, as run0 has some gotchas with polkit
- // and too many repeating prompts.
- if (self.find_in_path("sudo").await).is_ok() {
- return Ok(EscalationStrategy::Sudo);
- }
- if (self.find_in_path("run0").await).is_ok() {
- return Ok(EscalationStrategy::Run0);
+ async fn connection(&self) -> Result<Remowt> {
+ if let Some(conn) = self.remowt.get() {
+ return Ok(conn.clone());
}
- Ok(EscalationStrategy::Su)
- }
- async fn open_session(&self) -> Result<Arc<openssh::Session>> {
- assert!(!self.local, "do not open ssh connection to local session");
- // FIXME: TOCTOU
- if let Some(session) = &self.session.get() {
- return Ok((*session).clone());
+ let bundle = agent_bundle()?;
+ let conn = if self.local {
+ Remowt::connect_local(&bundle)
+ .await
+ .context("starting local remowt agent")?
+ } else {
+ let dest = self
+ .session_destination
+ .get()
+ .cloned()
+ .unwrap_or_else(|| self.name.clone());
+ Remowt::connect(&dest, &bundle)
+ .await
+ .map_err(|e| anyhow!("remowt error while connecting to {}: {e:#?}", self.name))?
};
- let mut session = SessionBuilder::default();
- session.control_persist(ControlPersist::ClosedAfterInitialConnection);
-
- let dest = self.session_destination.get().unwrap_or(&self.name);
- let session = session
- .connect(&dest)
- .await
- .map_err(|e| anyhow!("ssh error while connecting to {}: {e:#?}", self.name))?;
- let session = Arc::new(session);
- self.session.set(session.clone()).expect("TOCTOU happened");
- Ok(session)
- }
- pub async fn mktemp_dir(&self) -> Result<String> {
- let mut cmd = self.cmd("mktemp").await?;
- cmd.arg("-d");
- let path = cmd.run_string().await?;
- Ok(path.trim_end().to_owned())
- }
- pub async fn file_exists(&self, path: impl AsRef<OsStr>) -> Result<bool> {
- let mut cmd = self.cmd("sh").await?;
- cmd.arg("-c")
- .arg("test -e \"$1\" && echo true || echo false")
- .arg("_")
- .arg(path);
- cmd.run_value().await
- }
- pub async fn read_file_bin(&self, path: impl AsRef<OsStr>) -> Result<Vec<u8>> {
- let mut cmd = self.cmd("cat").await?;
- cmd.arg(path);
- cmd.run_bytes().await
- }
- pub async fn read_file_text(&self, path: impl AsRef<OsStr>) -> Result<String> {
- let mut cmd = self.cmd("cat").await?;
- cmd.arg(path);
- cmd.run_string().await
- }
- pub async fn read_dir(&self, path: impl AsRef<OsStr>) -> Result<Vec<String>> {
- let mut cmd = self.cmd("ls").await?;
- cmd.arg(path);
- let out = cmd.run_string().await?;
- let mut lines = out.split('\n');
- if let Some(last) = lines.next_back() {
- ensure!(last.is_empty(), "output of ls should end with newline");
- }
- Ok(lines.map(ToOwned::to_owned).collect())
- }
- #[allow(dead_code)]
- pub async fn read_file_json<D: DeserializeOwned>(&self, path: impl AsRef<OsStr>) -> Result<D> {
- let text = self.read_file_text(path).await?;
- Ok(serde_json::from_str(&text)?)
- }
- pub async fn read_env(&self, env: &str) -> Result<String> {
- let mut cmd = self.cmd("printenv").await?;
- cmd.arg(env);
- cmd.run_string().await
- }
- pub async fn find_in_path(&self, command: &str) -> Result<String> {
- // // `which` is not a part of coreutils, and it might not exist on machine.
- // let path = self.read_env("PATH").await?;
- // // Assuming delimiter is :, we don't work with windows host, this check will be much
- // // more sophisticated in remowt backend (and quicker, since actual PATH search will be done on remote machine)
- // for ele in path.split(':') {
- // let test_path = format!("{ele}/{cmd}");
- // test -x etc
- // }
- // let mut cmd = self.cmd("printenv").await?;
- // cmd.arg(env);
- // Ok(cmd.run_string().await?)
- // Assuming this is an environment issue if which doesn't exist, will be fixed with remowt.
- let mut cmd = self
- .cmd_escalation(
- // Not used
- EscalationStrategy::Su,
- "which",
- )
- .await?;
- cmd.arg(command);
- cmd.run_string().await
+ PromptEndpoints(PrependSourcePrompter {
+ prompter: AutoPrompter::new().await,
+ source: if self.local {
+ vec![]
+ } else {
+ vec![Source(std::borrow::Cow::Owned(format!(
+ "ssh host: {}",
+ self.name
+ )))]
+ },
+ description: "".to_owned(),
+ })
+ .register_endpoints(&mut conn.rpc());
+ let _ = self.remowt.set(conn);
+ Ok(self.remowt.get().expect("just set").clone())
}
- pub async fn read_file_value<D: FromStr>(&self, path: impl AsRef<OsStr>) -> Result<D>
- where
- <D as FromStr>::Err: Display,
- {
- let text = self.read_file_text(path).await?;
- D::from_str(&text).map_err(|e| anyhow!("failed to parse value: {e}"))
+
+ /// Client for this host's unprivileged agent.
+ pub async fn remowt(&self) -> Result<Remowt> {
+ Ok(self.connection().await?)
}
- pub async fn cmd(&self, cmd: impl AsRef<OsStr>) -> Result<MyCommand> {
- self.cmd_escalation(self.escalation_strategy().await?, cmd)
- .await
+
+ pub fn ensure_nix_plugin(&self) -> Pin<Box<dyn Future<Output = Result<u16>> + Send + '_>> {
+ Box::pin(async {
+ self.nix_plugin
+ .get_or_try_init(|| async {
+ let pkgs = self.pkgs()?;
+ let name = "remowt-plugin-fleet";
+ let plugin = nix_go!(pkgs[{ name }]);
+ let built = plugin
+ .build("out")
+ .context("failed to build the fleet nix plugin")?;
+ let copied = self
+ .remote_derivation(&built)
+ .await
+ .context("failed to copy the fleet nix plugin to the host store")?;
+ let bin = copied.join("bin/remowt-plugin-fleet");
+ self.remowt()
+ .await?
+ .run0_load_plugin_path(NIX_PLUGIN_ID, bin.as_str())
+ .await
+ .context("failed to load the fleet nix plugin")?;
+ self.remowt()
+ .await?
+ .rpc()
+ .wait_for_connection_to(Address::Plugin(NIX_PLUGIN_ID))
+ .await
+ .map_err(|e| anyhow!("failed to wait for plugin"))?;
+ anyhow::Ok(())
+ })
+ .await?;
+ Ok(NIX_PLUGIN_ID)
+ })
}
- pub async fn cmd_escalation(
- &self,
- escalation: EscalationStrategy,
- cmd: impl AsRef<OsStr>,
- ) -> Result<MyCommand> {
- if self.local {
- Ok(MyCommand::new(escalation, cmd))
- } else {
- let session = self.open_session().await?;
- Ok(MyCommand::new_on(escalation, cmd, session))
+
+ async fn nix_store(&self) -> Result<Arc<Store>> {
+ if let Some(store) = self.nix_store.get() {
+ return Ok(store.clone());
}
- }
- pub async fn nix_cmd(&self) -> Result<MyCommand> {
- let mut nix = self.cmd("nix").await?;
- nix.args([
- "--extra-experimental-features",
- "nix-command",
- "--extra-experimental-features",
- "flakes",
- ]);
- Ok(nix)
+ let conn = self.connection().await?;
+ let socket = match self.deploy_kind().await? {
+ DeployKind::NixosInstall => {
+ remowt_fleet::nix_store_socket(conn, "/mnt?require-sigs=false").await?
+ }
+ _ => remowt_fleet::nix_store_socket(conn, "auto").await?,
+ };
+ let uri = format!("unix://{}", socket.display());
+ let store = Arc::new(Store::open(&uri)?);
+ let _ = self.nix_store.set(store);
+ Ok(self.nix_store.get().expect("just set").clone())
}
pub async fn decrypt(&self, data: SecretData) -> Result<Vec<u8>> {
ensure!(data.encrypted, "secret is not encrypted");
- let mut cmd = self.cmd("fleet-install-secrets").await?;
+ let remowt = self.remowt().await?;
+ let mut cmd = remowt.cmd("fleet-install-secrets");
cmd.arg("decrypt").eqarg("--secret", data.to_string());
let encoded = cmd
.sudo()
@@ -434,8 +381,9 @@
data: SecretData,
targets: BTreeSet<SecretOwner>,
) -> Result<SecretData> {
+ let remowt = self.remowt().await?;
ensure!(data.encrypted, "secret is not encrypted");
- let mut cmd = self.cmd("fleet-install-secrets").await?;
+ let mut cmd = remowt.cmd("fleet-install-secrets");
cmd.arg("reencrypt").eqarg("--secret", data.to_string());
for target in targets {
let key = self.config.key(&target).await?;
@@ -451,74 +399,39 @@
Ok(data)
}
/// Returns path for futureproofing, as path might change i.e on conversion to CA
- pub async fn remote_derivation(&self, path: &PathBuf) -> Result<PathBuf> {
+ pub async fn remote_derivation(&self, path: impl AsRef<Utf8Path>) -> Result<Utf8PathBuf> {
+ let path = path.as_ref().to_owned();
if self.local {
// Path is located locally, thus already trusted.
- return Ok(path.to_owned());
- }
- let mut sign = MyCommand::new(
- // TODO: Look at the current escalation strategy.
- // ... or switch to run0 right after polkit update
- EscalationStrategy::Sudo,
- "nix",
- );
- sign.arg("store")
- .arg("sign")
- .comparg("--key-file", "/etc/nix/private-key")
- .arg("-r")
- .arg(&path);
- if let Err(e) = sign.sudo().run_nix().await {
- warn!("failed to sign store paths: {e}");
+ return Ok(path);
}
- let mut nix = MyCommand::new(
- // Not used
- EscalationStrategy::Su,
- "nix",
- );
- nix.arg("copy").arg("--substitute-on-destination");
-
- let proto = if self.legacy_ssh_store.get().cloned().unwrap_or(false) {
- "ssh"
- } else {
- "ssh-ng"
+ let sign: Pin<Box<dyn Future<Output = Result<()>> + Send>> = {
+ let path = path.clone();
+ Box::pin(async move {
+ let local = self.config.local_host();
+ let plugin_id = local.ensure_nix_plugin().await?;
+ let nix = local
+ .remowt()
+ .await?
+ .plugin_endpoints::<remowt_fleet::NixClient<_>>(plugin_id);
+ nix.sign_closure(path, Utf8PathBuf::from("/etc/nix/private-key"))
+ .await
+ .map_err(|e| anyhow!("{e:?}"))?
+ .map_err(|e| anyhow!("{e}"))?;
+ Ok(())
+ })
};
-
- match self.deploy_kind().await? {
- DeployKind::Fleet | DeployKind::UpgradeToFleet | DeployKind::NixosLustrate => {
- nix.comparg("--to", format!("{proto}://{}", self.name));
- }
- DeployKind::NixosInstall => {
- nix
- // Signature checking makes no sense with remote-store store argument set, as we're not even interacting with remote nix daemon
- .arg("--no-check-sigs")
- .comparg(
- "--to",
- format!("{proto}://root@{}?remote-store=/mnt", self.name),
- );
- }
+ if let Err(e) = sign.await {
+ warn!("failed to sign store paths: {e}");
}
- nix.arg(path);
- nix.run_nix().await.context("nix copy")?;
- Ok(path.to_owned())
- }
- pub async fn systemctl_stop(&self, name: &str) -> Result<()> {
- let mut cmd = self.cmd("systemctl").await?;
- cmd.arg("stop").arg(name);
- cmd.sudo().run().await
- }
- pub async fn systemctl_start(&self, name: &str) -> Result<()> {
- let mut cmd = self.cmd("systemctl").await?;
- cmd.arg("start").arg(name);
- cmd.sudo().run().await
- }
-
- pub async fn rm_file(&self, path: impl AsRef<OsStr>, sudo: bool) -> Result<()> {
- let mut cmd = self.cmd("rm").await?;
- cmd.arg("-f").arg(path);
- if sudo {
- cmd = cmd.sudo()
+ let store = self.nix_store().await?;
+ {
+ let path = path.clone();
+ spawn_blocking(move || nix_eval::copy_closure_to(&store, path.as_ref()))
+ .await?
+ .context("copying closure to remote store")?;
}
- cmd.run().await
+ Ok(path)
}
}
@@ -630,26 +543,32 @@
}
Ok(out)
}
- pub fn local_host(&self) -> ConfigHost {
- ConfigHost {
- config: self.clone(),
- name: "<virtual localhost>".to_owned(),
- host_config: None,
- nixos_config: OnceLock::new(),
- nixos_unchecked_config: OnceLock::new(),
- groups: {
- let cell = OnceLock::new();
- let _ = cell.set(vec![]);
- cell
- },
- pkgs_override: Some(self.default_pkgs.clone()),
+ pub fn local_host(&self) -> Arc<ConfigHost> {
+ self.local_host
+ .get_or_init(|| {
+ Arc::new(ConfigHost {
+ config: self.clone(),
+ name: "<virtual localhost>".to_owned(),
+ host_config: None,
+ nixos_config: OnceLock::new(),
+ nixos_unchecked_config: OnceLock::new(),
+ groups: {
+ let cell = OnceLock::new();
+ let _ = cell.set(vec![]);
+ cell
+ },
+ pkgs_override: Some(self.default_pkgs.clone()),
- local: true,
- session: OnceLock::new(),
- deploy_kind: OnceLock::new(),
- session_destination: OnceLock::new(),
- legacy_ssh_store: OnceLock::new(),
- }
+ local: true,
+ remowt: OnceLock::new(),
+ nix_store: OnceLock::new(),
+ nix_plugin: tokio::sync::OnceCell::new(),
+ deploy_kind: OnceLock::new(),
+ session_destination: OnceLock::new(),
+ legacy_ssh_store: OnceLock::new(),
+ })
+ })
+ .clone()
}
pub fn preferred_hosts(
@@ -684,7 +603,9 @@
// TODO: Remove with connectivit refactor
local: self.localhost == name,
- session: OnceLock::new(),
+ remowt: OnceLock::new(),
+ nix_store: OnceLock::new(),
+ nix_plugin: tokio::sync::OnceCell::new(),
deploy_kind: OnceLock::new(),
session_destination: OnceLock::new(),
legacy_ssh_store: OnceLock::new(),
crates/fleet-base/src/keys.rsdiffbeforeafterboth--- a/crates/fleet-base/src/keys.rs
+++ b/crates/fleet-base/src/keys.rs
@@ -31,7 +31,8 @@
} else {
warn!("Loading key for {}", host);
let host = self.host(host)?;
- let mut cmd = host.cmd("cat").await?;
+ let remowt = host.remowt().await?;
+ let mut cmd = remowt.cmd("cat");
cmd.arg("/etc/ssh/ssh_host_ed25519_key.pub");
let key = cmd.run_string().await?;
self.update_key(&host.name, key.clone());
crates/fleet-base/src/lib.rsdiffbeforeafterboth--- a/crates/fleet-base/src/lib.rs
+++ b/crates/fleet-base/src/lib.rs
@@ -1,8 +1,6 @@
-pub mod command;
pub mod deploy;
pub mod fleetdata;
pub mod host;
mod keys;
pub mod opts;
pub mod primops;
-pub mod secret_storage;
crates/fleet-base/src/opts.rsdiffbeforeafterboth--- a/crates/fleet-base/src/opts.rs
+++ b/crates/fleet-base/src/opts.rs
@@ -1,9 +1,8 @@
use std::{
collections::{BTreeMap, BTreeSet},
env::current_dir,
- ffi::OsString,
str::FromStr,
- sync::{Arc, Mutex},
+ sync::{Arc, OnceLock},
};
use anyhow::{Context, Result, bail};
@@ -196,7 +195,7 @@
}
// TODO: Config should be detached from opts.
- pub fn build(&self, nix_args: Vec<OsString>, assert: bool) -> Result<Config> {
+ pub fn build(&self, assert: bool) -> Result<Config> {
let cwd = current_dir()?;
let mut directory = cwd.clone();
let mut fleet_data_path = directory.join("fleet.nix");
@@ -274,11 +273,11 @@
data,
flake_outputs: flake,
local_system: self.local_system.clone(),
- nix_args,
config_field,
default_pkgs,
nixpkgs,
localhost: self.localhost.to_owned(),
+ local_host: OnceLock::new(),
}));
PRIMOPS_DATA
crates/fleet-base/src/primops.rsdiffbeforeafterboth--- a/crates/fleet-base/src/primops.rs
+++ b/crates/fleet-base/src/primops.rs
@@ -1,10 +1,12 @@
use std::collections::{BTreeMap, BTreeSet, HashMap};
-use std::sync::OnceLock;
+use std::sync::{Arc, OnceLock};
use anyhow::{Context, bail, ensure};
use fleet_shared::SecretData;
use itertools::Itertools;
use nix_eval::{NativeFn, Value, await_in_nix, nix_go, nix_go_json};
+use remowt_endpoints::fs::FsClient;
+use remowt_link_shared::BifConfig;
use serde::Deserialize;
use tracing::{info, warn};
@@ -28,7 +30,7 @@
let pkgs = host_on.pkgs()?;
let default_mk_secret_generators = nix_go!(pkgs.mkSecretGenerators);
let generators = nix_go!(default_mk_secret_generators(Obj { recipients }));
- Ok(pkgs.clone().attrs_update(generators)?)
+ pkgs.clone().attrs_update(generators)
}
pub fn get_default_pkgs_and_generators(config: &Config) -> Result<Value> {
let host_on = config.local_host();
@@ -91,12 +93,18 @@
let impure_on: Option<String> = nix_go_json!(default_generator_drv.impureOn);
let host_on = if let Some(on) = &impure_on {
- config
- .host(on)
- .context("failed to get secret generation target host")?
+ Arc::new(
+ config
+ .host(on)
+ .context("failed to get secret generation target host")?,
+ )
} else {
config.local_host()
};
+
+ let remowt = host_on.remowt().await?;
+ let fs = remowt.endpoints::<FsClient<BifConfig>>();
+
let mut recipients = Vec::new();
for owner in &expectations.owners {
recipients.push(config.key(owner).await?);
@@ -116,12 +124,13 @@
.context("failed to copy generator to target host")?;
// TODO: Remove destdir after everything is done
- let out_parent = host_on
+ let out_parent = fs
.mktemp_dir()
.await
+ .map_err(|e| anyhow!("{e:?}"))
.context("failed to prepare generator output dir on target host")?;
- let out = format!("{out_parent}/out");
- let mut generator_cmd = host_on.cmd(generator).await?;
+ let out = out_parent.join("out");
+ let mut generator_cmd = remowt.cmd(generator);
generator_cmd.env("out", &out);
if impure_on.is_none() {
let project_path: String = config
@@ -138,7 +147,7 @@
.context("failed to run impure generator")?;
{
- let marker = host_on.read_file_text(format!("{out}/marker")).await?;
+ let marker = fs.read_file_text(out.join("marker")).await?;
ensure!(
marker == "SUCCESS",
"impure generator ended prematurely, secret generation failed"
@@ -147,15 +156,16 @@
let mut missing_parts = expectations.parts.clone();
let mut parts = BTreeMap::new();
- for part in host_on.read_dir(&out).await? {
+ for part in fs.read_dir(&out).await? {
+ let part = part.into_string();
if part == "created_at" || part == "expires_at" || part == "marker" {
continue;
}
let Some(part_def) = missing_parts.remove(&part) else {
bail!("secret generator has produced an unexpected part: {part}");
};
- let contents: SecretData = host_on
- .read_file_text(format!("{out}/{part}"))
+ let contents: SecretData = fs
+ .read_file_text(out.join("part"))
.await?
.parse()
.map_err(|e| anyhow!("failed to decode secret {out:?} part {part:?}: {e}"))?;
@@ -178,11 +188,12 @@
);
}
- let created_at = host_on.read_file_value(format!("{out}/created_at")).await?;
- let expires_at = host_on
- .read_file_value(format!("{out}/expires_at"))
- .await
- .ok();
+ let created_at = fs.read_file_value(out.join("created_at")).await??;
+ let expires_at = match fs.read_file_value(out.join("expires_at")).await {
+ Ok(v) => Some(v?),
+ Err(remowt_endpoints::fs::Error::NotFound) => None,
+ Err(e) => return Err(e.into()),
+ };
let new_data = FleetSecretData {
created_at,
crates/fleet-base/src/secret_storage.rsdiffbeforeafterboth--- a/crates/fleet-base/src/secret_storage.rs
+++ /dev/null
@@ -1,278 +0,0 @@
-use anyhow::{Result, bail, ensure};
-use itertools::Itertools;
-use std::fs::{File, metadata};
-use std::io::{self, ErrorKind, Read, Write};
-use std::path::PathBuf;
-use std::str::FromStr;
-use std::{env, fs};
-
-use tempfile::{TempPath, tempfile_in};
-use toml_edit::{Document, DocumentMut, Formatted, Item, Value};
-
-struct Name(String);
-
-fn encode_name(name: &str) -> Name {
- assert!(
- !name.starts_with(['_', '.']),
- "groups should not start with _ or ."
- );
- assert!(
- !name.chars().any(|c| c == '/'),
- "group name should not contain internal slash"
- );
- Name(name.to_owned())
-}
-
-enum RewriteError {
- ConcurrentCreate,
- ConcurrentDelete,
- ConcurrentModify,
- ConcurrentWrite,
- Io(io::Error),
- Persist(tempfile::PersistError),
-}
-
-fn safe_rewrite(
- path: &PathBuf,
- old_content: Option<Vec<u8>>,
- new_content: Option<Vec<u8>>,
-) -> Result<(), RewriteError> {
- let mut f = match (old_content.is_some(), new_content.is_some()) {
- (false, true) => match File::create_new(path) {
- Ok(v) => v,
- Err(e) if e.kind() == ErrorKind::AlreadyExists => {
- return Err(RewriteError::ConcurrentCreate);
- }
- Err(e) => return Err(RewriteError::Io(e)),
- },
- (true, _) => match File::open(&path) {
- Ok(v) => v,
- Err(_e) => return Err(RewriteError::ConcurrentDelete),
- },
- (false, false) => match metadata(&path) {
- Err(e) if e.kind() == ErrorKind::NotFound => {
- return Ok(());
- }
- Ok(_) => return Err(RewriteError::ConcurrentCreate),
- Err(e) => return Err(RewriteError::Io(e)),
- },
- };
- f.lock().map_err(RewriteError::Io)?;
- let mut check_content = vec![];
- f.read_to_end(&mut check_content)
- .map_err(RewriteError::Io)?;
- match &old_content {
- Some(old) => {
- if old != &check_content {
- return Err(RewriteError::ConcurrentModify);
- }
- }
- None => {
- if !check_content.is_empty() {
- return Err(RewriteError::ConcurrentDelete);
- }
- }
- }
- if let Some(new_content) = new_content {
- if Some(&new_content) == old_content.as_ref() {
- return Ok(());
- }
- let dir = path.parent().expect("file is in directory, thus not root");
- let mut tempfile = tempfile::Builder::new()
- .prefix(".rewrite-")
- .tempfile_in(dir)
- .map_err(RewriteError::Io)?;
- tempfile.write_all(&new_content).map_err(RewriteError::Io)?;
- tempfile.flush().map_err(RewriteError::Io)?;
- tempfile.persist(path).map_err(RewriteError::Persist)?;
- } else {
- fs::remove_file(path).map_err(RewriteError::Io)?;
- }
- let _ = f.unlock();
- Ok(())
-}
-fn update_string(path: PathBuf, modify: impl Fn(&mut Option<String>) -> Result<()>) -> Result<()> {
- loop {
- let orig = match fs::read_to_string(&path) {
- Ok(v) => Some(v),
- Err(e) if e.kind() == ErrorKind::NotFound => None,
- Err(e) => return Err(e.into()),
- };
- let mut edit = orig.clone();
- modify(&mut edit);
-
- match safe_rewrite(&path, orig.map(String::into), edit.map(String::into)) {
- Ok(()) => return Ok(()),
- Err(
- RewriteError::ConcurrentCreate
- | RewriteError::ConcurrentModify
- | RewriteError::ConcurrentWrite
- | RewriteError::ConcurrentDelete,
- ) => {
- continue;
- }
- Err(RewriteError::Io(io)) => return Err(io.into()),
- Err(RewriteError::Persist(io)) => return Err(io.into()),
- }
- }
-}
-fn update_toml(path: PathBuf, modify: impl Fn(&mut DocumentMut) -> Result<()>) -> Result<()> {
- update_string(path, |str| {
- let mut doc = match str {
- None => DocumentMut::new(),
- Some(v) => DocumentMut::from_str(v)?,
- };
- modify(&mut doc)?;
- if doc.is_empty() {
- *str = None
- } else {
- *str = Some(doc.to_string())
- }
- Ok(())
- })
-}
-fn update_lines(path: PathBuf, modify: impl Fn(&mut Vec<String>) -> Result<()>) -> Result<()> {
- update_string(path, |str| {
- let mut list = if let Some(str) = str {
- str.split('\n').map(|s| s.to_owned()).collect_vec()
- } else {
- vec![]
- };
- let had_end_newline = if list.last().map(|v| v.as_str()) == Some("") {
- list.pop();
- true
- } else {
- false
- };
- modify(&mut list)?;
- if list.is_empty() {
- *str = None
- } else {
- if had_end_newline {
- list.push("".to_owned())
- }
- *str = Some(list.join("\n"));
- }
- Ok(())
- })
-}
-fn update_section(
- data: &mut Vec<String>,
- start: &str,
- end: &str,
- modify: impl Fn(&mut Vec<String>) -> Result<()>,
-) -> Result<()> {
- let first = data
- .iter()
- .enumerate()
- .filter(|(_, v)| *v == start)
- .at_most_one()
- .map_err(|_| anyhow::anyhow!("there should be at most one section start"))?
- .map(|(v, _)| v);
- let last = data
- .iter()
- .enumerate()
- .filter(|(_, v)| *v == end)
- .at_most_one()
- .map_err(|_| anyhow::anyhow!("there should be at most one section end"))?
- .map(|(v, _)| v);
-
- match (first, last) {
- (None, None) => {
- let mut out = Vec::new();
- modify(&mut out)?;
- if out.is_empty() {
- return Ok(());
- }
- data.push(start.to_owned());
- data.extend(out);
- data.push(end.to_owned());
- Ok(())
- }
- (None, Some(_)) | (Some(_), None) => {
- bail!("mismatched section start/end")
- }
- (Some(first), Some(last)) => {
- ensure!(first < last, "section end should come after start");
- let mut out = data[first + 1..last]
- .iter()
- .map(|v| v.to_owned())
- .collect_vec();
- modify(&mut out)?;
- if out.is_empty() {
- data.drain(first..=last);
- } else {
- data.splice(first + 1..last, out);
- }
- Ok(())
- }
- }
-}
-
-struct Group {
- path: PathBuf,
-}
-impl Group {
- fn new(path: PathBuf) -> Self {
- Self { path }
- }
- fn manage(&self, manager: &str) {}
- fn ensure_managing(&self, manager: &str) {
- if !self.has_stored() {
- return;
- }
- let managed = match fs::read_to_string(self.path.join(".managed_by")) {
- Ok(found_manager) => found_manager.lines().any(|line| line == manager),
- Err(e) if e.kind() == ErrorKind::NotFound => true,
- Err(e) => panic!("{e}"),
- };
- assert!(managed);
- }
- fn has_stored(&self) -> bool {
- match fs::metadata(&self.path) {
- Ok(d) => d.is_dir(),
- Err(e) if e.kind() == ErrorKind::NotFound => false,
- Err(e) => panic!("{e}"),
- }
- }
-}
-
-struct Root {
- path: PathBuf,
-}
-impl Root {
- fn new(path: PathBuf) -> Self {
- Self { path }
- }
- fn subgroup(&self, name: &str) -> Group {
- Group::new(self.path.join(name))
- }
-}
-
-#[test]
-fn test() {
- let mut data = vec![
- "a".to_owned(),
- "b".to_owned(),
- "start".to_owned(),
- "c".to_owned(),
- "d".to_owned(),
- "end".to_owned(),
- "e".to_owned(),
- "f".to_owned(),
- ];
- update_section(&mut data, "start", "end", |a| {
- a.push("vv".to_owned());
- Ok(())
- })
- .unwrap();
- dbg!(&data);
- // for v in 0..1000 {
- // update_toml(PathBuf::from("./test.toml"), |e| {
- // e.as_table_mut()
- // .insert("hello", Item::Value(Value::Integer(Formatted::new(v))));
- // })
- // .expect("update")
- // }
- // v.subgroup(name)
-}
crates/nix-eval/Cargo.tomldiffbeforeafterboth--- a/crates/nix-eval/Cargo.toml
+++ b/crates/nix-eval/Cargo.toml
@@ -10,10 +10,11 @@
nixlike.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
-thiserror.workspace = true
tracing.workspace = true
+camino = { workspace = true, features = ["serde1"] }
cxx.workspace = true
+futures.workspace = true
itertools.workspace = true
test-log.workspace = true
tokio.workspace = true
crates/nix-eval/src/drv.rsdiffbeforeafterboth--- a/crates/nix-eval/src/drv.rs
+++ b/crates/nix-eval/src/drv.rs
@@ -66,7 +66,13 @@
#[derive(Debug, Deserialize)]
pub struct DrvParsed {
pub inputs: DrvInputs,
- pub outputs: HashMap<String, serde_json::Value>,
+ pub outputs: HashMap<String, DrvParsedOutput>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct DrvParsedOutput {
+ #[serde(default)]
+ pub path: Option<String>,
}
#[derive(Debug, Deserialize)]
@@ -82,18 +88,19 @@
pub outputs: Vec<String>,
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct DrvGraph {
pub root: String,
pub nodes: HashMap<String, DrvNode>,
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct DrvNode {
pub name: String,
pub input_drvs: HashMap<String, Vec<String>>,
pub input_srcs: Vec<String>,
- pub outputs: Vec<String>,
+ // TODO: CA outputs without a known paths are skipped
+ pub outputs: HashMap<String, String>,
}
impl DrvGraph {
@@ -124,19 +131,59 @@
}
}
+ let outputs: HashMap<String, String> = parsed
+ .outputs
+ .into_iter()
+ .filter_map(|(name, out)| out.path.map(|p| (name, to_absolute_store_path(&sd, &p))))
+ .collect();
+
nodes.insert(
path.clone(),
DrvNode {
name: extract_drv_name(&path),
input_drvs,
input_srcs: parsed.inputs.srcs,
- outputs: parsed.outputs.into_keys().collect(),
+ outputs,
},
);
}
Ok(Self { root, nodes })
}
+
+ pub fn wanted_outputs(&self, root_outputs: &[String]) -> HashMap<String, Vec<String>> {
+ let mut wanted: HashMap<String, HashSet<String>> = HashMap::new();
+ wanted.insert(self.root.clone(), root_outputs.iter().cloned().collect());
+
+ let mut queue: VecDeque<String> = VecDeque::new();
+ queue.push_back(self.root.clone());
+ while let Some(path) = queue.pop_front() {
+ let Some(node) = self.nodes.get(&path) else {
+ continue;
+ };
+ for (dep_path, dep_outputs) in &node.input_drvs {
+ let entry = wanted.entry(dep_path.clone()).or_default();
+ let mut changed = false;
+ for o in dep_outputs {
+ if entry.insert(o.clone()) {
+ changed = true;
+ }
+ }
+ if changed {
+ queue.push_back(dep_path.clone());
+ }
+ }
+ }
+
+ wanted
+ .into_iter()
+ .map(|(k, v)| {
+ let mut v: Vec<_> = v.into_iter().collect();
+ v.sort();
+ (k, v)
+ })
+ .collect()
+ }
}
fn extract_drv_name(drv_path: &str) -> String {
crates/nix-eval/src/lib.ccdiffbeforeafterboth--- a/crates/nix-eval/src/lib.cc
+++ b/crates/nix-eval/src/lib.cc
@@ -1,8 +1,25 @@
#include "nix-eval/src/lib.rs"
#include "lib.hh"
#include <nix/fetchers/fetch-settings.hh>
+#include <nix/store/build-result.hh>
+#include <nix/store/content-address.hh>
+#include <nix/store/derived-path.hh>
+#include <nix/store/local-fs-store.hh>
+#include <nix/store/outputs-spec.hh>
+#include <nix/store/path-info.hh>
+#include <nix/store/profiles.hh>
+#include <nix/store/realisation.hh>
+#include <nix/store/store-api.hh>
+#include <nix/util/file-system.hh>
+#include <nix/util/hash.hh>
+#include <nix/util/posix-source-accessor.hh>
#include <nix/util/ref.hh>
+#include <nix/util/signature/local-keys.hh>
+#include <nix/util/signature/signer.hh>
+#include <nix/util/source-path.hh>
#include <nix_api_fetchers.h>
+#include <nix_api_store_internal.h>
+#include <sstream>
struct nix_fetchers_settings {
nix::ref<nix::fetchers::Settings> settings;
@@ -15,3 +32,175 @@
bool result = settings_ref->set(setting, value);
}
}
+
+rust::String switch_profile(Store *store, rust::Str profile,
+ rust::Str store_path) {
+ try {
+ auto nixStore = store->ptr;
+ auto *lfs = dynamic_cast<nix::LocalFSStore *>(&*nixStore);
+ if (!lfs)
+ return rust::String("destination is not a local-fs store");
+ auto path = nixStore->parseStorePath(std::string(store_path));
+ std::filesystem::path prof = std::string(profile);
+ auto gen = nix::createGeneration(*lfs, prof, path);
+ nix::switchLink(prof, gen);
+ return rust::String();
+ } catch (const std::exception &e) {
+ return rust::String(e.what());
+ }
+}
+
+rust::String sign_closure(Store *store, rust::Str store_path,
+ rust::Str key_file) {
+ try {
+ auto nixStore = store->ptr;
+ nix::LocalSigner signer(
+ nix::SecretKey::parse(nix::readFile(std::string(key_file))));
+ auto root = nixStore->parseStorePath(std::string(store_path));
+ nix::StorePathSet closure;
+ nixStore->computeFSClosure(root, closure);
+ for (auto &p : closure) {
+ auto info = nixStore->queryPathInfo(p);
+ nix::ValidPathInfo info2(*info);
+ info2.sign(*nixStore, signer);
+ nixStore->addSignatures(p, info2.sigs);
+ }
+ return rust::String();
+ } catch (const std::exception &e) {
+ return rust::String(e.what());
+ }
+}
+
+CxxListGenerationsResult list_generations(rust::Str profile_path) {
+ CxxListGenerationsResult out{rust::String(), {}};
+ try {
+ auto [gens, current] =
+ nix::findGenerations(std::filesystem::path(std::string(profile_path)));
+ for (auto &g : gens) {
+ CxxProfileGeneration cg{};
+ cg.id = g.number;
+ cg.store_path = rust::String(g.path.string());
+ cg.creation_time_unix = static_cast<int64_t>(g.creationTime);
+ cg.current = current.has_value() && *current == g.number;
+ out.generations.push_back(cg);
+ }
+ } catch (const std::exception &e) {
+ out.error = rust::String(e.what());
+ }
+ return out;
+}
+
+static std::vector<std::string> split_lines(rust::Str joined) {
+ std::vector<std::string> out;
+ std::string buf;
+ std::istringstream iss((std::string(joined)));
+ while (std::getline(iss, buf)) {
+ if (!buf.empty())
+ out.push_back(buf);
+ }
+ return out;
+}
+
+CxxBuildResult build_drv_outputs(Store *store, rust::Str drv_path,
+ // TODO: Vec<str>
+ rust::Str output_names_joined) {
+ CxxBuildResult res{rust::String(), {}};
+ try {
+ auto nixStore = store->ptr;
+ auto sp = nixStore->parseStorePath(std::string(drv_path));
+
+ nix::DerivedPath::Built built{
+ .drvPath = nix::makeConstantStorePathRef(sp),
+ .outputs = nix::OutputsSpec{nix::OutputsSpec::All{}},
+ };
+ auto names = split_lines(output_names_joined);
+ if (!names.empty()) {
+ std::set<nix::OutputName, std::less<>> nameSet;
+ for (auto &n : names)
+ nameSet.insert(n);
+ built.outputs =
+ nix::OutputsSpec{nix::OutputsSpec::Names{std::move(nameSet)}};
+ }
+
+ std::vector<nix::DerivedPath> reqs;
+ reqs.push_back(built);
+
+ auto results = nixStore->buildPathsWithResults(reqs);
+ for (auto &r : results) {
+ if (auto *failure = r.tryGetFailure()) {
+ res.error = rust::String(failure->what());
+ return res;
+ }
+ }
+ for (auto &r : results) {
+ if (auto *success = r.tryGetSuccess()) {
+ for (auto &[name, real] : success->builtOutputs) {
+ res.outputs.push_back(
+ rust::String(nixStore->printStorePath(real.outPath)));
+ }
+ }
+ }
+ } catch (const std::exception &e) {
+ res.error = rust::String(e.what());
+ }
+ return res;
+}
+
+CxxBuildResult substitute_paths(Store *store, rust::Str paths_joined) {
+ CxxBuildResult res{rust::String(), {}};
+ try {
+ auto nixStore = store->ptr;
+ auto paths = split_lines(paths_joined);
+
+ std::vector<nix::DerivedPath> reqs;
+ reqs.reserve(paths.size());
+ for (auto &p : paths) {
+ reqs.push_back(nix::DerivedPath::Opaque{nixStore->parseStorePath(p)});
+ }
+
+ // Substituter miss will cause scheduler to trigger build
+ auto results = nixStore->buildPathsWithResults(reqs);
+ for (auto &r : results) {
+ if (r.tryGetSuccess() == nullptr)
+ continue;
+ if (auto *opaque = std::get_if<nix::DerivedPath::Opaque>(&r.path.raw())) {
+ res.outputs.push_back(
+ rust::String(nixStore->printStorePath(opaque->path)));
+ }
+ }
+ } catch (const std::exception &e) {
+ res.error = rust::String(e.what());
+ }
+ return res;
+}
+
+bool is_valid_path(Store *store, rust::Str path) {
+ try {
+ auto nixStore = store->ptr;
+ auto sp = nixStore->parseStorePath(std::string(path));
+ return nixStore->isValidPath(sp);
+ } catch (const std::exception &) {
+ return false;
+ }
+}
+
+AddFileToStoreResult add_file_to_store(Store *store, rust::Str name,
+ rust::Str path) {
+ AddFileToStoreResult out{rust::String(), rust::String(), rust::String()};
+ try {
+ auto nixStore = store->ptr;
+ auto src = nix::PosixSourceAccessor::createAtRoot(
+ std::filesystem::path(std::string(path)));
+ auto info = nixStore->addToStoreSlow(std::string(name), src,
+ nix::ContentAddressMethod::Raw::Flat,
+ nix::HashAlgorithm::SHA256);
+ out.store_path = rust::String(nixStore->printStorePath(info.path));
+ if (info.ca.has_value()) {
+ out.hash =
+ rust::String(info.ca->hash.to_string(nix::HashFormat::SRI, true));
+ }
+ } catch (const std::exception &e) {
+ out.error = rust::String(e.what());
+ }
+ return out;
+}
crates/nix-eval/src/lib.hhdiffbeforeafterboth--- a/crates/nix-eval/src/lib.hh
+++ b/crates/nix-eval/src/lib.hh
@@ -1,7 +1,32 @@
#pragma once
+#include "rust/cxx.h"
#include <nix_api_fetchers.h>
+struct Store;
+
+struct AddFileToStoreResult;
+struct CxxBuildResult;
+
extern "C" {
void set_fetcher_setting(nix_fetchers_settings *settings, const char *setting,
const char *value);
}
+
+rust::String switch_profile(Store *store, rust::Str profile,
+ rust::Str store_path);
+
+rust::String sign_closure(Store *store, rust::Str store_path,
+ rust::Str key_file);
+
+struct CxxListGenerationsResult;
+CxxListGenerationsResult list_generations(rust::Str profile_path);
+
+AddFileToStoreResult add_file_to_store(Store *store, rust::Str name,
+ rust::Str path);
+
+CxxBuildResult build_drv_outputs(Store *store, rust::Str drv_path,
+ rust::Str output_names_joined);
+
+CxxBuildResult substitute_paths(Store *store, rust::Str paths_joined);
+
+bool is_valid_path(Store *store, rust::Str path);
crates/nix-eval/src/lib.rsdiffbeforeafterboth--- a/crates/nix-eval/src/lib.rs
+++ b/crates/nix-eval/src/lib.rs
@@ -1,12 +1,13 @@
use std::borrow::Cow;
use std::cell::RefCell;
+use std::collections::HashMap;
use std::ffi::{CStr, CString, c_char, c_int, c_uint, c_void};
use std::ptr::{null, null_mut};
use std::sync::{Arc, LazyLock, OnceLock};
use std::{array, fmt, slice};
-use std::{collections::HashMap, path::PathBuf};
use anyhow::{Context, anyhow, bail};
+use camino::{Utf8Path, Utf8PathBuf};
use itertools::Itertools;
use serde::Serialize;
use serde::de::DeserializeOwned;
@@ -38,8 +39,9 @@
make_attrs, make_bindings_builder, make_list, make_list_builder, realised_string,
realised_string_free, realised_string_get_buffer_size, realised_string_get_buffer_start,
realised_string_get_store_path, realised_string_get_store_path_count, register_primop,
- set_err_msg, setting_set, state_free, store_open, store_parse_path, store_path_free,
- store_path_name, string_realise, value, value_call, value_decref, value_force, value_incref,
+ set_err_msg, setting_set, state_free, store_copy_closure, store_free, store_open,
+ store_parse_path, store_path_free, store_path_name, string_realise, value, value_call,
+ value_decref, value_force, value_incref,
};
// Contains macros helpers
@@ -47,6 +49,7 @@
pub mod logging;
#[doc(hidden)]
pub mod macros;
+pub mod scheduler;
#[doc(hidden)]
pub mod __macro_support {
@@ -68,8 +71,28 @@
}
#[cxx::bridge]
pub mod nix_cxx {
+ struct AddFileToStoreResult {
+ error: String,
+ store_path: String,
+ hash: String,
+ }
+ struct CxxProfileGeneration {
+ id: u64,
+ store_path: String,
+ creation_time_unix: i64,
+ current: bool,
+ }
+ struct CxxListGenerationsResult {
+ error: String,
+ generations: Vec<CxxProfileGeneration>,
+ }
+ struct CxxBuildResult {
+ error: String,
+ outputs: Vec<String>,
+ }
unsafe extern "C++" {
type nix_fetchers_settings;
+ type Store;
include!("nix-eval/src/lib.hh");
#[allow(clippy::missing_safety_doc)]
@@ -78,6 +101,34 @@
setting: *const c_char,
value: *const c_char,
);
+
+ #[allow(clippy::missing_safety_doc)]
+ unsafe fn switch_profile(store: *mut Store, profile: &str, store_path: &str) -> String;
+
+ #[allow(clippy::missing_safety_doc)]
+ unsafe fn sign_closure(store: *mut Store, store_path: &str, key_file: &str) -> String;
+
+ #[allow(clippy::missing_safety_doc)]
+ unsafe fn add_file_to_store(
+ store: *mut Store,
+ name: &str,
+ path: &str,
+ ) -> AddFileToStoreResult;
+
+ fn list_generations(profile_path: &str) -> CxxListGenerationsResult;
+
+ #[allow(clippy::missing_safety_doc)]
+ unsafe fn build_drv_outputs(
+ store: *mut Store,
+ drv_path: &str,
+ output_names_joined: &str,
+ ) -> CxxBuildResult;
+
+ #[allow(clippy::missing_safety_doc)]
+ unsafe fn substitute_paths(store: *mut Store, paths_joined: &str) -> CxxBuildResult;
+
+ #[allow(clippy::missing_safety_doc)]
+ unsafe fn is_valid_path(store: *mut Store, path: &str) -> bool;
}
}
@@ -186,7 +237,7 @@
unsafe { set_err_msg(self.0, err as c_int, msg.as_ptr()) };
}
pub fn set_err(&mut self, err: anyhow::Error) {
- let mut fmt = format!("{err:?}").replace("\0", "\\0");
+ let fmt = format!("{err:?}").replace("\0", "\\0");
self.set_err_raw(
NixErrorKind::Generic,
&CString::new(fmt).expect("NUL bytes were just replaced"),
@@ -352,6 +403,125 @@
with_default_context(|c, _| unsafe { setting_set(c, s.as_ptr(), v.as_ptr()) }).map(|_| ())
}
+#[instrument(skip(dst))]
+pub fn copy_closure_to(dst: &Store, path: &Utf8Path) -> Result<()> {
+ let path_c = CString::new(path.as_str())?;
+ with_store_context(|c, src_store, _state| -> Result<()> {
+ let sp = unsafe { store_parse_path(c, src_store, path_c.as_ptr()) };
+ if sp.is_null() {
+ bail!("failed to parse store path {path}");
+ }
+ let rc = unsafe { store_copy_closure(c, src_store, dst.0, sp) };
+ unsafe { store_path_free(sp) };
+ if rc != nix_raw::err_NIX_OK {
+ bail!("store_copy_closure failed (code {rc})");
+ }
+ Ok(())
+ })?
+}
+
+#[instrument]
+pub fn switch_profile(profile: &str, store_path: &Utf8Path) -> Result<()> {
+ let msg = with_store_context(|_c, store, _state| unsafe {
+ nix_cxx::switch_profile(store.cast(), profile, store_path.as_str())
+ })?
+ .to_string();
+ if msg.is_empty() {
+ Ok(())
+ } else {
+ bail!("failed to switch profile {profile}: {msg}");
+ }
+}
+
+// TODO: fleet operator-managed key file
+#[instrument]
+pub fn sign_closure(store_path: &str, key_file: &str) -> Result<()> {
+ let msg = with_store_context(|_c, store, _state| unsafe {
+ nix_cxx::sign_closure(store.cast(), store_path, key_file)
+ })?
+ .to_string();
+ if msg.is_empty() {
+ Ok(())
+ } else {
+ bail!("failed to sign {store_path}: {msg}");
+ }
+}
+
+#[derive(Debug)]
+pub struct AddedFile {
+ pub store_path: Utf8PathBuf,
+ pub hash: String,
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+pub struct ProfileGeneration {
+ pub id: u64,
+ pub store_path: Utf8PathBuf,
+ pub creation_time_unix: i64,
+ pub current: bool,
+}
+
+#[instrument]
+pub fn list_generations(profile_path: &str) -> Result<Vec<ProfileGeneration>> {
+ let res = nix_cxx::list_generations(profile_path);
+ if !res.error.is_empty() {
+ bail!(
+ "failed to list generations at {profile_path}: {}",
+ res.error
+ );
+ }
+ Ok(res
+ .generations
+ .into_iter()
+ .map(|g| ProfileGeneration {
+ id: g.id,
+ store_path: Utf8PathBuf::from(g.store_path),
+ creation_time_unix: g.creation_time_unix,
+ current: g.current,
+ })
+ .collect())
+}
+
+#[instrument]
+pub fn add_file_to_store(name: &str, path: &Utf8Path) -> Result<AddedFile> {
+ let res = with_store_context(|_c, store, _state| unsafe {
+ nix_cxx::add_file_to_store(store.cast(), name, path.as_str())
+ })?;
+ if !res.error.is_empty() {
+ bail!("failed to add {path} to store: {}", res.error);
+ }
+ Ok(AddedFile {
+ store_path: Utf8PathBuf::from(res.store_path),
+ hash: res.hash,
+ })
+}
+
+pub fn build_drv_outputs(drv_path: &str, output_names: &[String]) -> Result<Vec<String>> {
+ let joined = output_names.join("\n");
+ let res = with_store_context(|_c, store, _state| unsafe {
+ nix_cxx::build_drv_outputs(store.cast(), drv_path, &joined)
+ })?;
+ if !res.error.is_empty() {
+ bail!("build of {drv_path} failed: {}", res.error);
+ }
+ Ok(res.outputs)
+}
+
+pub fn substitute_paths(paths: &[String]) -> Result<Vec<String>> {
+ let joined = paths.join("\n");
+ let res = with_store_context(|_c, store, _state| unsafe {
+ nix_cxx::substitute_paths(store.cast(), &joined)
+ })?;
+ if !res.error.is_empty() {
+ warn!("substitute_paths reported: {}", res.error);
+ }
+ Ok(res.outputs)
+}
+
+pub fn is_valid_path(path: &str) -> Result<bool> {
+ with_store_context(|_c, store, _state| unsafe { nix_cxx::is_valid_path(store.cast(), path) })
+}
+
pub struct FetchSettings(*mut fetchers_settings);
impl FetchSettings {
pub fn new() -> Self {
@@ -450,17 +620,31 @@
unsafe { *user_data.cast::<String>() = s.to_owned() };
}
-struct Store(*mut c_store);
+pub struct Store(*mut c_store);
unsafe impl Send for Store {}
unsafe impl Sync for Store {}
impl Store {
+ pub fn open(uri: &str) -> Result<Self> {
+ let uri = CString::new(uri)?;
+ let ptr = with_default_context(|c, _| unsafe { store_open(c, uri.as_ptr(), null_mut()) })?;
+ if ptr.is_null() {
+ bail!("failed to open store");
+ }
+ Ok(Store(ptr))
+ }
+
fn parse_path(&self, path: &CStr) -> Result<StorePath> {
with_default_context(|c, _| {
StorePath(unsafe { store_parse_path(c, self.0, path.as_ptr()) })
})
}
}
+impl Drop for Store {
+ fn drop(&mut self) {
+ unsafe { store_free(self.0) }
+ }
+}
#[repr(transparent)]
pub struct EvalState(*mut c_eval_state);
@@ -858,7 +1042,7 @@
Ok(out)
}
#[instrument(name = "build", skip(self), fields(output))]
- pub fn build(&self, output: &str) -> Result<PathBuf> {
+ pub fn build(&self, output: &str) -> Result<Utf8PathBuf> {
if !self.is_derivation() {
bail!("expected derivation to build")
}
@@ -880,14 +1064,15 @@
.get_field("drvPath")
.context("getting drvPath")?
.to_string()?;
- let graph = drv::DrvGraph::resolve(&drv_path)?;
+ let graph = Arc::new(drv::DrvGraph::resolve(&drv_path)?);
let _guard = logging::register_build_graph(&Span::current(), &graph);
- // to_string here blocks until the path is built
+ scheduler::build_graph_sync(graph.clone(), vec![output.to_owned()])?;
+
let s = v.builtin_to_string()?;
let rs = s.to_realised_string()?;
let out_path = rs.as_str().to_owned();
- Ok(PathBuf::from(out_path))
+ Ok(Utf8PathBuf::from(out_path))
}
pub fn as_json<T: DeserializeOwned>(&self) -> Result<T> {
let to_json = Self::eval("builtins.toJSON")?;
crates/nix-eval/src/logging.ccdiffbeforeafterboth--- a/crates/nix-eval/src/logging.cc
+++ b/crates/nix-eval/src/logging.cc
@@ -96,7 +96,9 @@
extern "C" {
void apply_tracing_logger() {
- logger = std::make_unique<TracingLogger>();
+ auto old = logger;
+ logger = new TracingLogger();
+ delete old;
// verbosity = lvlVomit;
}
rust::Box<ErrorInfoBuilder>
crates/nix-eval/src/logging.rsdiffbeforeafterboth--- a/crates/nix-eval/src/logging.rs
+++ b/crates/nix-eval/src/logging.rs
@@ -499,7 +499,9 @@
} else if level == Level::INFO {
info!(target: "nix", "{}", s)
} else if level == Level::DEBUG {
- debug!(target: "nix", "{}", s)
+ if s != "querying info about missing paths" {
+ debug!(target: "nix", "{}", s)
+ }
} else {
trace!(target: "nix", "{}", s)
}
@@ -583,7 +585,9 @@
} else if level == Level::INFO {
info!(target: "nix", "{v}")
} else if level == Level::DEBUG {
- debug!(target: "nix", "{v}")
+ if v != "querying info about missing paths" {
+ debug!(target: "nix", "{v}")
+ }
} else {
trace!(target: "nix", "{v}")
}
crates/nix-eval/src/scheduler.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/nix-eval/src/scheduler.rs
@@ -0,0 +1,372 @@
+use std::collections::{HashMap, HashSet};
+use std::sync::Arc;
+
+use anyhow::{Context, Result, bail};
+use futures::stream::{FuturesUnordered, StreamExt};
+use tokio::sync::{Semaphore, broadcast};
+use tracing::{debug, info, instrument, warn};
+
+use crate::drv::DrvGraph;
+
+#[derive(Clone, Debug)]
+pub enum BuildEvent {
+ SubstitutePrepassStarted {
+ paths: usize,
+ },
+ SubstitutePrepassFinished {
+ satisfied: usize,
+ },
+ DrvStarted {
+ drv_path: String,
+ name: String,
+ wanted: Vec<String>,
+ },
+ DrvSkipped {
+ drv_path: String,
+ name: String,
+ },
+ DrvFinished {
+ drv_path: String,
+ name: String,
+ },
+ DrvFailed {
+ drv_path: String,
+ name: String,
+ error: String,
+ },
+ DrvCancelled {
+ drv_path: String,
+ name: String,
+ failed_dep: String,
+ },
+}
+
+pub struct Scheduler {
+ parallelism: usize,
+ events: broadcast::Sender<BuildEvent>,
+}
+
+impl Scheduler {
+ pub fn new(parallelism: usize) -> Self {
+ let parallelism = parallelism.max(1);
+ let (events, _) = broadcast::channel(1024);
+ Self {
+ parallelism,
+ events,
+ }
+ }
+
+ pub fn subscribe(&self) -> broadcast::Receiver<BuildEvent> {
+ self.events.subscribe()
+ }
+
+ #[instrument(name = "scheduler", skip(self, graph), fields(root = %graph.root, nodes = graph.nodes.len()))]
+ pub async fn run(&self, graph: Arc<DrvGraph>, root_outputs: Vec<String>) -> Result<()> {
+ let wanted = graph.wanted_outputs(&root_outputs);
+
+ self.substitute_prepass(&graph, &wanted).await?;
+ self.build_topo(&graph, wanted).await
+ }
+
+ async fn substitute_prepass(
+ &self,
+ graph: &DrvGraph,
+ wanted: &HashMap<String, Vec<String>>,
+ ) -> Result<()> {
+ let paths = collect_substitute_paths(graph, wanted);
+ if paths.is_empty() {
+ return Ok(());
+ }
+ let _ = self
+ .events
+ .send(BuildEvent::SubstitutePrepassStarted { paths: paths.len() });
+ debug!("substitute pre-pass: {} paths", paths.len());
+
+ let satisfied = tokio::task::spawn_blocking(move || crate::substitute_paths(&paths))
+ .await
+ .expect("substitute pre-pass task should not panic")?;
+
+ let _ = self.events.send(BuildEvent::SubstitutePrepassFinished {
+ satisfied: satisfied.len(),
+ });
+ Ok(())
+ }
+
+ async fn build_topo(
+ &self,
+ graph: &Arc<DrvGraph>,
+ wanted: HashMap<String, Vec<String>>,
+ ) -> Result<()> {
+ let mut indeg: HashMap<String, usize> = graph
+ .nodes
+ .iter()
+ .map(|(k, n)| (k.clone(), n.input_drvs.len()))
+ .collect();
+ let mut dependents: HashMap<String, Vec<String>> = HashMap::new();
+ for (path, node) in &graph.nodes {
+ for dep in node.input_drvs.keys() {
+ dependents
+ .entry(dep.clone())
+ .or_default()
+ .push(path.clone());
+ }
+ }
+
+ let sem = Arc::new(Semaphore::new(self.parallelism));
+ let mut ready: Vec<String> = indeg
+ .iter()
+ .filter(|(_, d)| **d == 0)
+ .map(|(k, _)| k.clone())
+ .collect();
+ let mut in_flight = FuturesUnordered::new();
+ let mut failed: HashMap<String, String> = HashMap::new();
+ // Tainted = transitively depends on a failed drv
+ let mut tainted: HashMap<String, String> = HashMap::new();
+
+ loop {
+ let batch: Vec<String> = std::mem::take(&mut ready);
+ for path in batch {
+ if let Some(failed_dep) = tainted.get(&path) {
+ let name = graph
+ .nodes
+ .get(&path)
+ .map(|n| n.name.clone())
+ .unwrap_or_default();
+ let _ = self.events.send(BuildEvent::DrvCancelled {
+ drv_path: path.clone(),
+ name,
+ failed_dep: failed_dep.clone(),
+ });
+ propagate_done(&dependents, &mut indeg, &mut ready, &path);
+ continue;
+ }
+
+ let sem = sem.clone();
+ let events = self.events.clone();
+ let graph = graph.clone();
+ let wanted_here = wanted.get(&path).cloned().unwrap_or_default();
+ in_flight.push(tokio::spawn(async move {
+ let _permit = sem.acquire_owned().await.expect("semaphore not closed");
+ let node = graph
+ .nodes
+ .get(&path)
+ .expect("ready node must be in graph")
+ .clone();
+ let name = node.name.clone();
+
+ let all_valid = !wanted_here.is_empty()
+ && wanted_here.iter().all(|o| {
+ node.outputs
+ .get(o)
+ .map(|p| crate::is_valid_path(p).unwrap_or(false))
+ .unwrap_or(false)
+ });
+ if all_valid {
+ let _ = events.send(BuildEvent::DrvSkipped {
+ drv_path: path.clone(),
+ name: name.clone(),
+ });
+ return (path, name, Ok::<(), anyhow::Error>(()));
+ }
+
+ let _ = events.send(BuildEvent::DrvStarted {
+ drv_path: path.clone(),
+ name: name.clone(),
+ wanted: wanted_here.clone(),
+ });
+
+ let path_for_build = path.clone();
+ let res = tokio::task::spawn_blocking(move || {
+ crate::build_drv_outputs(&path_for_build, &wanted_here)
+ })
+ .await
+ .expect("build task should not panic");
+
+ match res {
+ Ok(_) => {
+ let _ = events.send(BuildEvent::DrvFinished {
+ drv_path: path.clone(),
+ name: name.clone(),
+ });
+ (path, name, Ok(()))
+ }
+ Err(e) => {
+ let msg = format!("{e:#}");
+ let _ = events.send(BuildEvent::DrvFailed {
+ drv_path: path.clone(),
+ name: name.clone(),
+ error: msg,
+ });
+ (path, name, Err(e))
+ }
+ }
+ }));
+ }
+
+ let Some(joined) = in_flight.next().await else {
+ break;
+ };
+ let (finished, _name, res) = match joined {
+ Ok(t) => t,
+ Err(e) => bail!("scheduler task panicked: {e}"),
+ };
+ match res {
+ Ok(()) => {
+ propagate_done(&dependents, &mut indeg, &mut ready, &finished);
+ }
+ Err(e) => {
+ failed.insert(finished.clone(), format!("{e:#}"));
+ mark_tainted(&dependents, &finished, &mut tainted);
+ propagate_done(&dependents, &mut indeg, &mut ready, &finished);
+ }
+ }
+ }
+
+ let stuck: Vec<_> = indeg
+ .iter()
+ .filter(|(_, d)| **d != 0)
+ .map(|(k, _)| k.as_str())
+ .collect();
+ if !stuck.is_empty() {
+ warn!(
+ "scheduler finished with {} nodes still pending (loop?)",
+ stuck.len()
+ );
+ }
+
+ if failed.is_empty() {
+ info!("scheduler completed");
+ Ok(())
+ } else {
+ let mut report = format!("{} drv(s) failed to build:", failed.len());
+ let mut sorted: Vec<_> = failed.iter().collect();
+ sorted.sort_by(|a, b| a.0.cmp(b.0));
+ for (path, err) in sorted {
+ let name = graph
+ .nodes
+ .get(path)
+ .map(|n| n.name.as_str())
+ .unwrap_or("?");
+ let chain = path_to_root(graph, path);
+ report.push_str(&format!(
+ "\n\n {name} ({path}):\n {err}\n needed by: {}",
+ chain.join(" => "),
+ ));
+ }
+ Err(anyhow::anyhow!(report))
+ }
+ }
+}
+
+fn propagate_done(
+ dependents: &HashMap<String, Vec<String>>,
+ indeg: &mut HashMap<String, usize>,
+ ready: &mut Vec<String>,
+ finished: &str,
+) {
+ if let Some(deps) = dependents.get(finished) {
+ for d in deps {
+ let entry = indeg.get_mut(d).expect("dependent must have indeg");
+ *entry = entry.saturating_sub(1);
+ if *entry == 0 {
+ ready.push(d.clone());
+ }
+ }
+ }
+}
+
+fn mark_tainted(
+ dependents: &HashMap<String, Vec<String>>,
+ failed: &str,
+ tainted: &mut HashMap<String, String>,
+) {
+ let mut queue: Vec<String> = dependents.get(failed).cloned().unwrap_or_default();
+ while let Some(node) = queue.pop() {
+ if tainted
+ .entry(node.clone())
+ .or_insert_with(|| failed.to_owned())
+ == failed
+ {
+ if let Some(deps) = dependents.get(&node) {
+ for d in deps {
+ if !tainted.contains_key(d) {
+ queue.push(d.clone());
+ }
+ }
+ }
+ }
+ }
+}
+
+fn path_to_root(graph: &DrvGraph, from: &str) -> Vec<String> {
+ let mut dependents: HashMap<&str, Vec<&str>> = HashMap::new();
+ for (path, node) in &graph.nodes {
+ for dep in node.input_drvs.keys() {
+ dependents
+ .entry(dep.as_str())
+ .or_default()
+ .push(path.as_str());
+ }
+ }
+
+ let mut chain: Vec<String> = vec![node_name(graph, from)];
+ let mut cur = from;
+ let mut seen: HashSet<&str> = HashSet::new();
+ seen.insert(cur);
+ while cur != graph.root.as_str() {
+ let Some(next) = dependents.get(cur).and_then(|v| v.first().copied()) else {
+ break;
+ };
+ if !seen.insert(next) {
+ break;
+ }
+ chain.push(node_name(graph, next));
+ cur = next;
+ }
+ chain
+}
+
+fn node_name(graph: &DrvGraph, path: &str) -> String {
+ graph
+ .nodes
+ .get(path)
+ .map(|n| n.name.clone())
+ .unwrap_or_else(|| path.to_owned())
+}
+
+fn collect_substitute_paths(
+ graph: &DrvGraph,
+ wanted: &HashMap<String, Vec<String>>,
+) -> Vec<String> {
+ let mut paths: HashSet<String> = HashSet::new();
+ for node in graph.nodes.values() {
+ for src in &node.input_srcs {
+ paths.insert(src.clone());
+ }
+ }
+ for (path, outs) in wanted {
+ let Some(node) = graph.nodes.get(path) else {
+ continue;
+ };
+ for o in outs {
+ if let Some(p) = node.outputs.get(o) {
+ paths.insert(p.clone());
+ }
+ }
+ }
+ let mut v: Vec<_> = paths.into_iter().collect();
+ v.sort();
+ v
+}
+
+// TODO: Parallelism as a metric works poorly with multiple machines, but I haven't thought about bringing
+// hercy here yet. In case of remote machines - they will handle parallelism on their own, and this one
+// will work as a hard cap.
+pub fn build_graph_sync(graph: Arc<DrvGraph>, root_outputs: Vec<String>) -> Result<()> {
+ let parallelism = std::thread::available_parallelism()
+ .map(|p| p.get())
+ .unwrap_or(4);
+ let scheduler = Scheduler::new(parallelism);
+ crate::await_in_nix(async move { scheduler.run(graph, root_outputs).await })
+ .context("scheduler run")
+}
crates/nixlike/Cargo.tomldiffbeforeafterboth--- a/crates/nixlike/Cargo.toml
+++ b/crates/nixlike/Cargo.toml
@@ -11,5 +11,3 @@
linked-hash-map.workspace = true
peg.workspace = true
serde.workspace = true
-serde-transcode.workspace = true
-serde_json.workspace = true
crates/remowt-fleet/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/crates/remowt-fleet/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "remowt-fleet"
+description = "Remowt endpoints for fleet"
+version.workspace = true
+edition = "2021"
+
+[dependencies]
+bifrostlink.workspace = true
+
+remowt-client.workspace = true
+remowt-endpoints.workspace = true
+
+anyhow.workspace = true
+camino.workspace = true
+nix-eval.workspace = true
+serde = { workspace = true }
+thiserror.workspace = true
+tokio = { workspace = true, features = ["io-util", "net", "process", "rt"] }
+tracing.workspace = true
+uuid.workspace = true
crates/remowt-fleet/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/remowt-fleet/src/lib.rs
@@ -0,0 +1,120 @@
+use std::path::PathBuf;
+
+use anyhow::{Context as _, Result};
+use bifrostlink::Config;
+use bifrostlink::declarative::endpoints;
+use camino::Utf8PathBuf;
+use remowt_client::Remowt;
+use remowt_endpoints::nix_daemon::NixDaemonClient;
+use serde::{Deserialize, Serialize};
+use tokio::net::UnixListener;
+use tracing::error;
+
+pub struct Nix;
+pub use nix_eval::{init_libraries, init_tokio_for_nix};
+
+#[derive(Serialize, Deserialize, Debug, thiserror::Error)]
+pub enum NixError {
+ #[error("nix daemon unavailable: {0}")]
+ DaemonUnavailable(String),
+ #[error("tunnel socket unavailable: {0}")]
+ Tunnel(String),
+ #[error("profile switch failed: {0}")]
+ Profile(String),
+ #[error("signing failed: {0}")]
+ Sign(String),
+ #[error("listing generations failed: {0}")]
+ ListGenerations(String),
+}
+
+#[endpoints(ns = 91)]
+impl Nix {
+ #[endpoints(id = 3)]
+ async fn switch_profile(
+ &self,
+ profile: String,
+ store_path: Utf8PathBuf,
+ ) -> Result<(), NixError> {
+ tokio::task::spawn_blocking(move || nix_eval::switch_profile(&profile, &store_path))
+ .await
+ .map_err(|e| NixError::Profile(e.to_string()))?
+ .map_err(|e| NixError::Profile(e.to_string()))
+ }
+
+ #[endpoints(id = 4)]
+ async fn sign_closure(
+ &self,
+ store_path: Utf8PathBuf,
+ key_file: Utf8PathBuf,
+ ) -> Result<(), NixError> {
+ tokio::task::spawn_blocking(move || {
+ nix_eval::sign_closure(store_path.as_str(), key_file.as_str())
+ })
+ .await
+ .map_err(|e| NixError::Sign(e.to_string()))?
+ .map_err(|e| NixError::Sign(e.to_string()))
+ }
+
+ #[endpoints(id = 5)]
+ async fn list_generations(
+ &self,
+ profile: String,
+ ) -> Result<Vec<nix_eval::ProfileGeneration>, NixError> {
+ tokio::task::spawn_blocking(move || {
+ nix_eval::list_generations(&format!("/nix/var/nix/profiles/{profile}"))
+ })
+ .await
+ .map_err(|e| NixError::ListGenerations(e.to_string()))?
+ .map_err(|e| NixError::ListGenerations(e.to_string()))
+ }
+}
+
+pub async fn nix_store_socket(conn: Remowt, store: &str) -> Result<PathBuf> {
+ let store = store.to_owned();
+ let path = std::env::temp_dir().join(format!("fleet-nix-{}.sock", uuid::Uuid::new_v4()));
+ let _ = std::fs::remove_file(&path);
+ let listener = UnixListener::bind(&path)?;
+ tokio::spawn(async move {
+ if let Err(e) = serve(conn, listener, store).await {
+ error!("nix daemon proxy failed: {e}");
+ }
+ });
+ Ok(path)
+}
+
+async fn serve(conn: Remowt, listener: UnixListener, store: String) -> Result<()> {
+ let nix = conn.endpoints::<NixDaemonClient<_>>();
+ loop {
+ let (mut local, _) = listener.accept().await?;
+
+ let (rx, remote_sock) = match conn.bind_runtime_unix("nix-daemon").await {
+ Ok(rx) => rx,
+ Err(e) => {
+ error!("streamlocal_forward failed: {e}");
+ continue;
+ }
+ };
+ let sock_str = remote_sock.as_str().to_owned();
+ match nix.serve_store(store.clone(), sock_str).await {
+ Ok(Ok(())) => {}
+ Ok(Err(e)) => {
+ error!("nix bridge: {e}");
+ continue;
+ }
+ Err(e) => {
+ error!("nix bridge rpc failed: {e}");
+ continue;
+ }
+ }
+
+ let mut channel = rx
+ .accept()
+ .await
+ .context("failed to accept remote nix connection")?;
+ tokio::spawn(async move {
+ if let Err(e) = tokio::io::copy_bidirectional(&mut local, &mut channel).await {
+ tracing::debug!("nix tunnel ended: {e}");
+ }
+ });
+ }
+}
flake.lockdiffbeforeafterboth--- a/flake.lock
+++ b/flake.lock
@@ -2,10 +2,10 @@
"nodes": {
"crane": {
"locked": {
- "lastModified": 1773189535,
+ "lastModified": 1780532242,
"owner": "ipetkov",
"repo": "crane",
- "rev": "6fa2fb4cf4a89ba49fc9dd5a3eb6cde99d388269",
+ "rev": "59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37",
"type": "github"
},
"original": {
@@ -37,10 +37,10 @@
]
},
"locked": {
- "lastModified": 1772408722,
+ "lastModified": 1778716662,
"owner": "hercules-ci",
"repo": "flake-parts",
- "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
+ "rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb",
"type": "github"
},
"original": {
@@ -62,10 +62,10 @@
]
},
"locked": {
- "lastModified": 1759080490,
+ "lastModified": 1780160585,
"owner": "CertainLach",
"repo": "fleet-tf",
- "rev": "878bd8c23933d628bf750378bbe527b841901c3d",
+ "rev": "aa2200a3f8f93a8c0d3b87bb29f11d9d9b0a23e6",
"type": "github"
},
"original": {
@@ -111,10 +111,10 @@
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
- "lastModified": 1768702010,
+ "lastModified": 1781448983,
"owner": "deltarocks",
"repo": "nix",
- "rev": "b05b52670b9c7affff5b9be3edb539a1603c39e6",
+ "rev": "bb8784f285658e77642437409824619f5c34a854",
"type": "github"
},
"original": {
@@ -126,10 +126,10 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1773268153,
+ "lastModified": 1781402740,
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "63ca4f465b79edbaa9ff113ea7ff48fb49ea0db0",
+ "rev": "49145c5aba740948d6da1265f584826bd27619ad",
"type": "github"
},
"original": {
@@ -171,6 +171,34 @@
"type": "github"
}
},
+ "remowt-agents": {
+ "inputs": {
+ "crane": [
+ "crane"
+ ],
+ "flake-parts": [
+ "flake-parts"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "rust-overlay": "rust-overlay",
+ "shelly": [
+ "shelly"
+ ]
+ },
+ "locked": {
+ "lastModified": 1781471358,
+ "rev": "c69dddc33f8e2081ef685ae20a7278f92cfcd32e",
+ "revCount": 37,
+ "type": "git",
+ "url": "file:/home/lach/build/remowt-agents"
+ },
+ "original": {
+ "type": "git",
+ "url": "file:/home/lach/build/remowt-agents"
+ }
+ },
"root": {
"inputs": {
"crane": "crane",
@@ -178,7 +206,8 @@
"fleet-tf": "fleet-tf",
"nix": "nix",
"nixpkgs": "nixpkgs",
- "rust-overlay": "rust-overlay",
+ "remowt-agents": "remowt-agents",
+ "rust-overlay": "rust-overlay_2",
"shelly": "shelly",
"treefmt-nix": "treefmt-nix"
}
@@ -186,14 +215,15 @@
"rust-overlay": {
"inputs": {
"nixpkgs": [
+ "remowt-agents",
"nixpkgs"
]
},
"locked": {
- "lastModified": 1773216618,
+ "lastModified": 1769309768,
"owner": "oxalica",
"repo": "rust-overlay",
- "rev": "07d7dc6fcc5eae76b4fb0e19d4afd939437bec97",
+ "rev": "140c9dc582cb73ada2d63a2180524fcaa744fad5",
"type": "github"
},
"original": {
@@ -202,6 +232,25 @@
"type": "github"
}
},
+ "rust-overlay_2": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1781320681,
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "5b929d8c854149d926d05ea0cd6469bf4e54db27",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ },
"shelly": {
"locked": {
"lastModified": 1756323923,
@@ -223,10 +272,10 @@
]
},
"locked": {
- "lastModified": 1772660329,
+ "lastModified": 1780220602,
"owner": "numtide",
"repo": "treefmt-nix",
- "rev": "3710e0e1218041bbad640352a0440114b1e10428",
+ "rev": "db947814a175b7ca6ded66e21383d938df01c227",
"type": "github"
},
"original": {
flake.nixdiffbeforeafterboth--- a/flake.nix
+++ b/flake.nix
@@ -23,6 +23,13 @@
url = "github:numtide/treefmt-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
+ remowt-agents = {
+ url = "git+file:/home/lach/build/remowt-agents";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.flake-parts.follows = "flake-parts";
+ inputs.crane.follows = "crane";
+ inputs.shelly.follows = "shelly";
+ };
# DeterminateSystem's nix fork is controversial, but I don't mind it,
# and it has lazy-trees support which is useful for fleet.
nix = {
@@ -147,7 +154,7 @@
packages = lib.mkIf deployerSystem (
let
packages = pkgs.callPackages ./pkgs {
- inherit craneLib inputs';
+ inherit craneLib inputs;
};
in
packages // { default = packages.fleet; }
lib/flakePart.nixdiffbeforeafterboth--- a/lib/flakePart.nix
+++ b/lib/flakePart.nix
@@ -57,7 +57,7 @@
modules = (import ../modules/module-list.nix) ++ [
module
(
- { inputs', ... }:
+ { inputs, ... }:
{
config = {
data = if isPath data then import data else data;
@@ -66,12 +66,13 @@
(final: prev: {
inherit
(import ../pkgs {
- inherit (prev) callPackage;
- inherit inputs';
+ inherit (final) callPackage;
+ inherit inputs;
craneLib = crane.mkLib prev;
})
fleet-install-secrets
fleet-generator-helper
+ remowt-plugin-fleet
;
})
];
modules/nixpkgs.nixdiffbeforeafterboth--- a/modules/nixpkgs.nix
+++ b/modules/nixpkgs.nix
@@ -42,10 +42,12 @@
default = config.nixpkgs.buildUsing;
defaultText = literalExpression "config.nixpkgs.buildUsing";
};
- config.nixos = {
- inherit _file;
- nixpkgs.overlays = config.nixpkgs.overlays;
- };
+ config.nixos =
+ { inputs', ... }:
+ {
+ inherit _file;
+ nixpkgs.overlays = config.nixpkgs.overlays;
+ };
};
};
}
pkgs/default.nixdiffbeforeafterboth--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -1,10 +1,11 @@
{
callPackage,
craneLib,
- inputs',
+ inputs,
}:
{
- fleet = callPackage ./fleet.nix { inherit craneLib inputs'; };
+ fleet = callPackage ./fleet.nix { inherit craneLib inputs; };
+ remowt-plugin-fleet = callPackage ./remowt-plugin-fleet.nix { inherit craneLib inputs; };
fleet-install-secrets = callPackage ./fleet-install-secrets.nix { inherit craneLib; };
fleet-generator-helper = callPackage ./fleet-generator-helper.nix { inherit craneLib; };
}
pkgs/fleet.nixdiffbeforeafterboth--- a/pkgs/fleet.nix
+++ b/pkgs/fleet.nix
@@ -2,10 +2,16 @@
lib,
craneLib,
installShellFiles,
- inputs',
+ inputs,
+
+ stdenv,
pkg-config,
rustPlatform,
+ rofi,
}:
+let
+ system = stdenv.hostPlatform.system;
+in
craneLib.buildPackage rec {
pname = "fleet";
src = lib.cleanSourceWith {
@@ -20,10 +26,15 @@
cargoExtraArgs = "--locked -p ${pname}";
+ REMOWT_AGENTS_DIR = "${inputs.remowt-agents.packages.${system}.remowt-agents}";
+ # TODO: built-in fleet prompter should be a prodash widget, or it should require
+ # tty remowt prompter running on host machine idk.
+ ROFI = "${rofi}/bin/rofi";
+
buildInputs = [
- inputs'.nix.packages.nix-expr-c
- inputs'.nix.packages.nix-flake-c
- inputs'.nix.packages.nix-fetchers-c
+ inputs.nix.packages.${system}.nix-expr-c
+ inputs.nix.packages.${system}.nix-flake-c
+ inputs.nix.packages.${system}.nix-fetchers-c
];
nativeBuildInputs = [
installShellFiles
pkgs/remowt-plugin-fleet.nixdiffbeforeafterboth--- /dev/null
+++ b/pkgs/remowt-plugin-fleet.nix
@@ -0,0 +1,36 @@
+{
+ lib,
+ craneLib,
+ inputs,
+
+ stdenv,
+ pkg-config,
+ rustPlatform,
+}:
+let
+ system = stdenv.hostPlatform.system;
+in
+craneLib.buildPackage rec {
+ pname = "remowt-plugin-fleet";
+ src = lib.cleanSourceWith {
+ src = ../.;
+ filter =
+ path: type:
+ (lib.hasSuffix "\.cc" path)
+ || (lib.hasSuffix "\.hh" path)
+ || (craneLib.filterCargoSources path type);
+ };
+ strictDeps = true;
+
+ cargoExtraArgs = "--locked -p ${pname}";
+
+ buildInputs = [
+ inputs.nix.packages.${system}.nix-expr-c
+ inputs.nix.packages.${system}.nix-flake-c
+ inputs.nix.packages.${system}.nix-fetchers-c
+ ];
+ nativeBuildInputs = [
+ pkg-config
+ rustPlatform.bindgenHook
+ ];
+}