├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── build.yaml ├── .gitignore ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── Vagrantfile ├── apparmor ├── zeus └── zeus.d │ └── docker ├── assets ├── logo.256x256.png ├── logo.512x512.png ├── logo.inkscape.svg ├── logo.optimized.svg ├── social-image.png └── social-image.xcf.xz ├── completions ├── zeus.bash ├── zeus.fish └── zeus.zsh ├── runtimes └── zeus_rt_docker │ ├── .gitignore │ ├── Cargo.toml │ ├── data │ └── Dockerfile │ └── src │ ├── lib.rs │ └── models.rs ├── rustfmt.toml ├── scripts └── make_package.sh └── src ├── aur.rs ├── builder.rs ├── cli.rs ├── config.rs ├── error.rs ├── lib.rs ├── lock.rs ├── log.rs ├── machine ├── manager.rs └── mod.rs ├── message.rs ├── ops ├── build.rs ├── completions.rs ├── mod.rs ├── query.rs ├── remove.rs ├── runtime.rs └── sync.rs ├── term.rs ├── unix.rs └── zeus.rs /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Improve zeus with a bug report 4 | title: "[BUG] " 5 | labels: bug 6 | assignees: threadexio 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Expected behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Environment (please complete the following information):** 17 | - Zeus Version (`zeus -V`) 18 | - Runtime [e.g. name, version] 19 | - Installation method [e.g. official package or local build] 20 | 21 | **Zeus output:** 22 | A link to a service like [pastebin](https://pastebin.com) with the output of `zeus`. 23 | 24 | **Additional context** 25 | Add any other context about the problem here. 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: threadexio 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | if: "!startsWith(github.event.head_commit.message, '[no-ci]')" 9 | 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | 16 | - name: Setup toolchain 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | profile: minimal 20 | toolchain: stable 21 | default: true 22 | 23 | - name: Format 24 | run: | 25 | cargo fmt --check 26 | 27 | - name: Build 28 | run: | 29 | ./scripts/make_package.sh 30 | 31 | - name: Upload build artifacts 32 | uses: actions/upload-artifact@v3 33 | with: 34 | name: zeus 35 | path: | 36 | zeus.tar.gz 37 | 38 | - name: Create release 39 | uses: softprops/action-gh-release@v1 40 | if: startsWith(github.ref, 'refs/tags/v') 41 | with: 42 | files: zeus.tar.gz 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | /.vscode/* 4 | !/.vscode/settings.json 5 | 6 | *.tar.gz 7 | 8 | /.vagrant 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.server.extraEnv": { 3 | "DEFAULT_DATA_DIR": "", 4 | "DEFAULT_NAME": "", 5 | "DEFAULT_IMAGE": "", 6 | "DEFAULT_BUILDDIR": "", 7 | "DEFAULT_AUR_HOST": "", 8 | "DEFAULT_RUNTIME": "", 9 | "DEFAULT_RUNTIME_DIR": "", 10 | "VERSION": "" 11 | }, 12 | "rust-analyzer.runnables.extraArgs": ["--bin=zeus"] 13 | } 14 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "atty" 7 | version = "0.2.14" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 10 | dependencies = [ 11 | "hermit-abi", 12 | "libc", 13 | "winapi", 14 | ] 15 | 16 | [[package]] 17 | name = "autocfg" 18 | version = "1.1.0" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 21 | 22 | [[package]] 23 | name = "base64" 24 | version = "0.13.0" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 27 | 28 | [[package]] 29 | name = "bincode" 30 | version = "1.3.3" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 33 | dependencies = [ 34 | "serde", 35 | ] 36 | 37 | [[package]] 38 | name = "bitflags" 39 | version = "1.3.2" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 42 | 43 | [[package]] 44 | name = "bumpalo" 45 | version = "3.10.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" 48 | 49 | [[package]] 50 | name = "bytes" 51 | version = "1.2.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" 54 | 55 | [[package]] 56 | name = "cc" 57 | version = "1.0.73" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 60 | 61 | [[package]] 62 | name = "cfg-if" 63 | version = "1.0.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 66 | 67 | [[package]] 68 | name = "channels" 69 | version = "0.1.1" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "d5d255e8692b2800a72ce5d8d178a27745ffeba02df4face564a9b838dfc272f" 72 | dependencies = [ 73 | "bincode", 74 | "serde", 75 | ] 76 | 77 | [[package]] 78 | name = "clap" 79 | version = "3.2.14" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "54635806b078b7925d6e36810b1755f2a4b5b4d57560432c1ecf60bcbe10602b" 82 | dependencies = [ 83 | "atty", 84 | "bitflags", 85 | "clap_lex", 86 | "indexmap", 87 | "once_cell", 88 | "strsim", 89 | "termcolor", 90 | "textwrap", 91 | ] 92 | 93 | [[package]] 94 | name = "clap_complete" 95 | version = "3.2.3" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "ead064480dfc4880a10764488415a97fdd36a4cf1bb022d372f02e8faf8386e1" 98 | dependencies = [ 99 | "clap", 100 | ] 101 | 102 | [[package]] 103 | name = "clap_lex" 104 | version = "0.2.4" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 107 | dependencies = [ 108 | "os_str_bytes", 109 | ] 110 | 111 | [[package]] 112 | name = "colored" 113 | version = "2.0.0" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 116 | dependencies = [ 117 | "atty", 118 | "lazy_static", 119 | "winapi", 120 | ] 121 | 122 | [[package]] 123 | name = "const_format" 124 | version = "0.2.26" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "939dc9e2eb9077e0679d2ce32de1ded8531779360b003b4a972a7a39ec263495" 127 | dependencies = [ 128 | "const_format_proc_macros", 129 | ] 130 | 131 | [[package]] 132 | name = "const_format_proc_macros" 133 | version = "0.2.22" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "ef196d5d972878a48da7decb7686eded338b4858fbabeed513d63a7c98b2b82d" 136 | dependencies = [ 137 | "proc-macro2", 138 | "quote", 139 | "unicode-xid", 140 | ] 141 | 142 | [[package]] 143 | name = "core-foundation" 144 | version = "0.9.3" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 147 | dependencies = [ 148 | "core-foundation-sys", 149 | "libc", 150 | ] 151 | 152 | [[package]] 153 | name = "core-foundation-sys" 154 | version = "0.8.3" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 157 | 158 | [[package]] 159 | name = "encoding_rs" 160 | version = "0.8.31" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" 163 | dependencies = [ 164 | "cfg-if", 165 | ] 166 | 167 | [[package]] 168 | name = "fastrand" 169 | version = "1.8.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" 172 | dependencies = [ 173 | "instant", 174 | ] 175 | 176 | [[package]] 177 | name = "fnv" 178 | version = "1.0.7" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 181 | 182 | [[package]] 183 | name = "foreign-types" 184 | version = "0.3.2" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 187 | dependencies = [ 188 | "foreign-types-shared", 189 | ] 190 | 191 | [[package]] 192 | name = "foreign-types-shared" 193 | version = "0.1.1" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 196 | 197 | [[package]] 198 | name = "form_urlencoded" 199 | version = "1.0.1" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 202 | dependencies = [ 203 | "matches", 204 | "percent-encoding", 205 | ] 206 | 207 | [[package]] 208 | name = "fs4" 209 | version = "0.5.4" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "cef5c93884e5cef757f63446122c2f420713c3e03f85540d09485b9415983b4a" 212 | dependencies = [ 213 | "libc", 214 | "winapi", 215 | ] 216 | 217 | [[package]] 218 | name = "futures-channel" 219 | version = "0.3.21" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" 222 | dependencies = [ 223 | "futures-core", 224 | ] 225 | 226 | [[package]] 227 | name = "futures-core" 228 | version = "0.3.21" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" 231 | 232 | [[package]] 233 | name = "futures-io" 234 | version = "0.3.21" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" 237 | 238 | [[package]] 239 | name = "futures-sink" 240 | version = "0.3.21" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" 243 | 244 | [[package]] 245 | name = "futures-task" 246 | version = "0.3.21" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" 249 | 250 | [[package]] 251 | name = "futures-util" 252 | version = "0.3.21" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" 255 | dependencies = [ 256 | "futures-core", 257 | "futures-io", 258 | "futures-task", 259 | "memchr", 260 | "pin-project-lite", 261 | "pin-utils", 262 | "slab", 263 | ] 264 | 265 | [[package]] 266 | name = "h2" 267 | version = "0.3.13" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" 270 | dependencies = [ 271 | "bytes", 272 | "fnv", 273 | "futures-core", 274 | "futures-sink", 275 | "futures-util", 276 | "http", 277 | "indexmap", 278 | "slab", 279 | "tokio", 280 | "tokio-util", 281 | "tracing", 282 | ] 283 | 284 | [[package]] 285 | name = "hashbrown" 286 | version = "0.12.3" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 289 | 290 | [[package]] 291 | name = "hermit-abi" 292 | version = "0.1.19" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 295 | dependencies = [ 296 | "libc", 297 | ] 298 | 299 | [[package]] 300 | name = "http" 301 | version = "0.2.8" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" 304 | dependencies = [ 305 | "bytes", 306 | "fnv", 307 | "itoa", 308 | ] 309 | 310 | [[package]] 311 | name = "http-body" 312 | version = "0.4.5" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 315 | dependencies = [ 316 | "bytes", 317 | "http", 318 | "pin-project-lite", 319 | ] 320 | 321 | [[package]] 322 | name = "httparse" 323 | version = "1.7.1" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" 326 | 327 | [[package]] 328 | name = "httpdate" 329 | version = "1.0.2" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 332 | 333 | [[package]] 334 | name = "hyper" 335 | version = "0.14.20" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" 338 | dependencies = [ 339 | "bytes", 340 | "futures-channel", 341 | "futures-core", 342 | "futures-util", 343 | "h2", 344 | "http", 345 | "http-body", 346 | "httparse", 347 | "httpdate", 348 | "itoa", 349 | "pin-project-lite", 350 | "socket2", 351 | "tokio", 352 | "tower-service", 353 | "tracing", 354 | "want", 355 | ] 356 | 357 | [[package]] 358 | name = "hyper-tls" 359 | version = "0.5.0" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 362 | dependencies = [ 363 | "bytes", 364 | "hyper", 365 | "native-tls", 366 | "tokio", 367 | "tokio-native-tls", 368 | ] 369 | 370 | [[package]] 371 | name = "idna" 372 | version = "0.2.3" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 375 | dependencies = [ 376 | "matches", 377 | "unicode-bidi", 378 | "unicode-normalization", 379 | ] 380 | 381 | [[package]] 382 | name = "indexmap" 383 | version = "1.9.1" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 386 | dependencies = [ 387 | "autocfg", 388 | "hashbrown", 389 | ] 390 | 391 | [[package]] 392 | name = "instant" 393 | version = "0.1.12" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 396 | dependencies = [ 397 | "cfg-if", 398 | ] 399 | 400 | [[package]] 401 | name = "ipnet" 402 | version = "2.5.0" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" 405 | 406 | [[package]] 407 | name = "itoa" 408 | version = "1.0.1" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 411 | 412 | [[package]] 413 | name = "js-sys" 414 | version = "0.3.58" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" 417 | dependencies = [ 418 | "wasm-bindgen", 419 | ] 420 | 421 | [[package]] 422 | name = "lazy_static" 423 | version = "1.4.0" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 426 | 427 | [[package]] 428 | name = "libc" 429 | version = "0.2.123" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" 432 | 433 | [[package]] 434 | name = "libloading" 435 | version = "0.7.3" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" 438 | dependencies = [ 439 | "cfg-if", 440 | "winapi", 441 | ] 442 | 443 | [[package]] 444 | name = "log" 445 | version = "0.4.17" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 448 | dependencies = [ 449 | "cfg-if", 450 | ] 451 | 452 | [[package]] 453 | name = "matches" 454 | version = "0.1.9" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 457 | 458 | [[package]] 459 | name = "memchr" 460 | version = "2.5.0" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 463 | 464 | [[package]] 465 | name = "mime" 466 | version = "0.3.16" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 469 | 470 | [[package]] 471 | name = "mio" 472 | version = "0.8.4" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" 475 | dependencies = [ 476 | "libc", 477 | "log", 478 | "wasi", 479 | "windows-sys", 480 | ] 481 | 482 | [[package]] 483 | name = "native-tls" 484 | version = "0.2.10" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" 487 | dependencies = [ 488 | "lazy_static", 489 | "libc", 490 | "log", 491 | "openssl", 492 | "openssl-probe", 493 | "openssl-sys", 494 | "schannel", 495 | "security-framework", 496 | "security-framework-sys", 497 | "tempfile", 498 | ] 499 | 500 | [[package]] 501 | name = "num_cpus" 502 | version = "1.13.1" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 505 | dependencies = [ 506 | "hermit-abi", 507 | "libc", 508 | ] 509 | 510 | [[package]] 511 | name = "once_cell" 512 | version = "1.13.0" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" 515 | 516 | [[package]] 517 | name = "openssl" 518 | version = "0.10.41" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" 521 | dependencies = [ 522 | "bitflags", 523 | "cfg-if", 524 | "foreign-types", 525 | "libc", 526 | "once_cell", 527 | "openssl-macros", 528 | "openssl-sys", 529 | ] 530 | 531 | [[package]] 532 | name = "openssl-macros" 533 | version = "0.1.0" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" 536 | dependencies = [ 537 | "proc-macro2", 538 | "quote", 539 | "syn", 540 | ] 541 | 542 | [[package]] 543 | name = "openssl-probe" 544 | version = "0.1.5" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 547 | 548 | [[package]] 549 | name = "openssl-sys" 550 | version = "0.9.75" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" 553 | dependencies = [ 554 | "autocfg", 555 | "cc", 556 | "libc", 557 | "pkg-config", 558 | "vcpkg", 559 | ] 560 | 561 | [[package]] 562 | name = "os_str_bytes" 563 | version = "6.2.0" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4" 566 | 567 | [[package]] 568 | name = "percent-encoding" 569 | version = "2.1.0" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 572 | 573 | [[package]] 574 | name = "pin-project-lite" 575 | version = "0.2.9" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 578 | 579 | [[package]] 580 | name = "pin-utils" 581 | version = "0.1.0" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 584 | 585 | [[package]] 586 | name = "pkg-config" 587 | version = "0.3.25" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 590 | 591 | [[package]] 592 | name = "proc-macro2" 593 | version = "1.0.37" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" 596 | dependencies = [ 597 | "unicode-xid", 598 | ] 599 | 600 | [[package]] 601 | name = "quote" 602 | version = "1.0.18" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" 605 | dependencies = [ 606 | "proc-macro2", 607 | ] 608 | 609 | [[package]] 610 | name = "redox_syscall" 611 | version = "0.2.15" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" 614 | dependencies = [ 615 | "bitflags", 616 | ] 617 | 618 | [[package]] 619 | name = "remove_dir_all" 620 | version = "0.5.3" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 623 | dependencies = [ 624 | "winapi", 625 | ] 626 | 627 | [[package]] 628 | name = "reqwest" 629 | version = "0.11.11" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" 632 | dependencies = [ 633 | "base64", 634 | "bytes", 635 | "encoding_rs", 636 | "futures-core", 637 | "futures-util", 638 | "h2", 639 | "http", 640 | "http-body", 641 | "hyper", 642 | "hyper-tls", 643 | "ipnet", 644 | "js-sys", 645 | "lazy_static", 646 | "log", 647 | "mime", 648 | "native-tls", 649 | "percent-encoding", 650 | "pin-project-lite", 651 | "serde", 652 | "serde_json", 653 | "serde_urlencoded", 654 | "tokio", 655 | "tokio-native-tls", 656 | "tower-service", 657 | "url", 658 | "wasm-bindgen", 659 | "wasm-bindgen-futures", 660 | "web-sys", 661 | "winreg", 662 | ] 663 | 664 | [[package]] 665 | name = "ryu" 666 | version = "1.0.9" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 669 | 670 | [[package]] 671 | name = "schannel" 672 | version = "0.1.20" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" 675 | dependencies = [ 676 | "lazy_static", 677 | "windows-sys", 678 | ] 679 | 680 | [[package]] 681 | name = "security-framework" 682 | version = "2.6.1" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" 685 | dependencies = [ 686 | "bitflags", 687 | "core-foundation", 688 | "core-foundation-sys", 689 | "libc", 690 | "security-framework-sys", 691 | ] 692 | 693 | [[package]] 694 | name = "security-framework-sys" 695 | version = "2.6.1" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" 698 | dependencies = [ 699 | "core-foundation-sys", 700 | "libc", 701 | ] 702 | 703 | [[package]] 704 | name = "serde" 705 | version = "1.0.136" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" 708 | dependencies = [ 709 | "serde_derive", 710 | ] 711 | 712 | [[package]] 713 | name = "serde_derive" 714 | version = "1.0.136" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" 717 | dependencies = [ 718 | "proc-macro2", 719 | "quote", 720 | "syn", 721 | ] 722 | 723 | [[package]] 724 | name = "serde_json" 725 | version = "1.0.79" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" 728 | dependencies = [ 729 | "itoa", 730 | "ryu", 731 | "serde", 732 | ] 733 | 734 | [[package]] 735 | name = "serde_urlencoded" 736 | version = "0.7.1" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 739 | dependencies = [ 740 | "form_urlencoded", 741 | "itoa", 742 | "ryu", 743 | "serde", 744 | ] 745 | 746 | [[package]] 747 | name = "slab" 748 | version = "0.4.7" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" 751 | dependencies = [ 752 | "autocfg", 753 | ] 754 | 755 | [[package]] 756 | name = "socket2" 757 | version = "0.4.4" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" 760 | dependencies = [ 761 | "libc", 762 | "winapi", 763 | ] 764 | 765 | [[package]] 766 | name = "strsim" 767 | version = "0.10.0" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 770 | 771 | [[package]] 772 | name = "syn" 773 | version = "1.0.91" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" 776 | dependencies = [ 777 | "proc-macro2", 778 | "quote", 779 | "unicode-xid", 780 | ] 781 | 782 | [[package]] 783 | name = "tempfile" 784 | version = "3.3.0" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 787 | dependencies = [ 788 | "cfg-if", 789 | "fastrand", 790 | "libc", 791 | "redox_syscall", 792 | "remove_dir_all", 793 | "winapi", 794 | ] 795 | 796 | [[package]] 797 | name = "termcolor" 798 | version = "1.1.3" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 801 | dependencies = [ 802 | "winapi-util", 803 | ] 804 | 805 | [[package]] 806 | name = "textwrap" 807 | version = "0.15.0" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" 810 | 811 | [[package]] 812 | name = "tinyvec" 813 | version = "1.6.0" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 816 | dependencies = [ 817 | "tinyvec_macros", 818 | ] 819 | 820 | [[package]] 821 | name = "tinyvec_macros" 822 | version = "0.1.0" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 825 | 826 | [[package]] 827 | name = "tokio" 828 | version = "1.20.0" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e" 831 | dependencies = [ 832 | "autocfg", 833 | "bytes", 834 | "libc", 835 | "memchr", 836 | "mio", 837 | "num_cpus", 838 | "once_cell", 839 | "pin-project-lite", 840 | "socket2", 841 | "winapi", 842 | ] 843 | 844 | [[package]] 845 | name = "tokio-native-tls" 846 | version = "0.3.0" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 849 | dependencies = [ 850 | "native-tls", 851 | "tokio", 852 | ] 853 | 854 | [[package]] 855 | name = "tokio-util" 856 | version = "0.7.3" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" 859 | dependencies = [ 860 | "bytes", 861 | "futures-core", 862 | "futures-sink", 863 | "pin-project-lite", 864 | "tokio", 865 | "tracing", 866 | ] 867 | 868 | [[package]] 869 | name = "tower-service" 870 | version = "0.3.2" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 873 | 874 | [[package]] 875 | name = "tracing" 876 | version = "0.1.35" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" 879 | dependencies = [ 880 | "cfg-if", 881 | "pin-project-lite", 882 | "tracing-core", 883 | ] 884 | 885 | [[package]] 886 | name = "tracing-core" 887 | version = "0.1.28" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" 890 | dependencies = [ 891 | "once_cell", 892 | ] 893 | 894 | [[package]] 895 | name = "try-lock" 896 | version = "0.2.3" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 899 | 900 | [[package]] 901 | name = "unicode-bidi" 902 | version = "0.3.8" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" 905 | 906 | [[package]] 907 | name = "unicode-normalization" 908 | version = "0.1.21" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" 911 | dependencies = [ 912 | "tinyvec", 913 | ] 914 | 915 | [[package]] 916 | name = "unicode-xid" 917 | version = "0.2.2" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 920 | 921 | [[package]] 922 | name = "url" 923 | version = "2.2.2" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 926 | dependencies = [ 927 | "form_urlencoded", 928 | "idna", 929 | "matches", 930 | "percent-encoding", 931 | ] 932 | 933 | [[package]] 934 | name = "vcpkg" 935 | version = "0.2.15" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 938 | 939 | [[package]] 940 | name = "want" 941 | version = "0.3.0" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 944 | dependencies = [ 945 | "log", 946 | "try-lock", 947 | ] 948 | 949 | [[package]] 950 | name = "wasi" 951 | version = "0.11.0+wasi-snapshot-preview1" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 954 | 955 | [[package]] 956 | name = "wasm-bindgen" 957 | version = "0.2.81" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" 960 | dependencies = [ 961 | "cfg-if", 962 | "wasm-bindgen-macro", 963 | ] 964 | 965 | [[package]] 966 | name = "wasm-bindgen-backend" 967 | version = "0.2.81" 968 | source = "registry+https://github.com/rust-lang/crates.io-index" 969 | checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" 970 | dependencies = [ 971 | "bumpalo", 972 | "lazy_static", 973 | "log", 974 | "proc-macro2", 975 | "quote", 976 | "syn", 977 | "wasm-bindgen-shared", 978 | ] 979 | 980 | [[package]] 981 | name = "wasm-bindgen-futures" 982 | version = "0.4.31" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" 985 | dependencies = [ 986 | "cfg-if", 987 | "js-sys", 988 | "wasm-bindgen", 989 | "web-sys", 990 | ] 991 | 992 | [[package]] 993 | name = "wasm-bindgen-macro" 994 | version = "0.2.81" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" 997 | dependencies = [ 998 | "quote", 999 | "wasm-bindgen-macro-support", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "wasm-bindgen-macro-support" 1004 | version = "0.2.81" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" 1007 | dependencies = [ 1008 | "proc-macro2", 1009 | "quote", 1010 | "syn", 1011 | "wasm-bindgen-backend", 1012 | "wasm-bindgen-shared", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "wasm-bindgen-shared" 1017 | version = "0.2.81" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" 1020 | 1021 | [[package]] 1022 | name = "web-sys" 1023 | version = "0.3.58" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" 1026 | dependencies = [ 1027 | "js-sys", 1028 | "wasm-bindgen", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "winapi" 1033 | version = "0.3.9" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1036 | dependencies = [ 1037 | "winapi-i686-pc-windows-gnu", 1038 | "winapi-x86_64-pc-windows-gnu", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "winapi-i686-pc-windows-gnu" 1043 | version = "0.4.0" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1046 | 1047 | [[package]] 1048 | name = "winapi-util" 1049 | version = "0.1.5" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1052 | dependencies = [ 1053 | "winapi", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "winapi-x86_64-pc-windows-gnu" 1058 | version = "0.4.0" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1061 | 1062 | [[package]] 1063 | name = "windows-sys" 1064 | version = "0.36.1" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 1067 | dependencies = [ 1068 | "windows_aarch64_msvc", 1069 | "windows_i686_gnu", 1070 | "windows_i686_msvc", 1071 | "windows_x86_64_gnu", 1072 | "windows_x86_64_msvc", 1073 | ] 1074 | 1075 | [[package]] 1076 | name = "windows_aarch64_msvc" 1077 | version = "0.36.1" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 1080 | 1081 | [[package]] 1082 | name = "windows_i686_gnu" 1083 | version = "0.36.1" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 1086 | 1087 | [[package]] 1088 | name = "windows_i686_msvc" 1089 | version = "0.36.1" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 1092 | 1093 | [[package]] 1094 | name = "windows_x86_64_gnu" 1095 | version = "0.36.1" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 1098 | 1099 | [[package]] 1100 | name = "windows_x86_64_msvc" 1101 | version = "0.36.1" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 1104 | 1105 | [[package]] 1106 | name = "winreg" 1107 | version = "0.10.1" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" 1110 | dependencies = [ 1111 | "winapi", 1112 | ] 1113 | 1114 | [[package]] 1115 | name = "zeus" 1116 | version = "0.1.0" 1117 | dependencies = [ 1118 | "channels", 1119 | "clap", 1120 | "clap_complete", 1121 | "colored", 1122 | "const_format", 1123 | "fs4", 1124 | "libloading", 1125 | "reqwest", 1126 | "serde", 1127 | "serde_json", 1128 | ] 1129 | 1130 | [[package]] 1131 | name = "zeus_rt_docker" 1132 | version = "0.1.0" 1133 | dependencies = [ 1134 | "serde", 1135 | "serde_json", 1136 | "zeus", 1137 | ] 1138 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zeus" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["threadexio"] 6 | description = "Containerized AUR helper" 7 | readme = "README.md" 8 | homepage = "https://github.com/threadexio/zeus" 9 | repository = "https://github.com/threadexio/zeus" 10 | license = "GPL-3.0-or-later" 11 | 12 | [lib] 13 | name = "zeus" 14 | path = "src/lib.rs" 15 | 16 | [[bin]] 17 | name = "zeus" 18 | path = "src/zeus.rs" 19 | 20 | [[bin]] 21 | name = "builder" 22 | path = "src/builder.rs" 23 | 24 | [dependencies] 25 | clap = { version = "^3.1", features = ["cargo"] } 26 | clap_complete = "^3.1" 27 | serde = { version = "^1.0", features = ["derive"] } 28 | serde_json = "^1.0" 29 | channels = "0.1.1" 30 | fs4 = { version = "^0.5", features = ["sync"] } 31 | const_format = "^0.2" 32 | reqwest = { version = "^0.11", features = ["json", "blocking"] } 33 | colored = "^2.0" 34 | libloading = "^0.7" 35 | 36 | [workspace] 37 | members = ["runtimes/zeus_rt_docker"] 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_TYPE ?= debug 2 | CARGO_ARGS ?= 3 | 4 | VERSION ?= $(shell git describe --tags --always --dirty --broken) 5 | 6 | PREFIX ?= /usr/local 7 | DESTDIR ?= 8 | 9 | DEFAULT_NAME ?= zeus-builder 10 | DEFAULT_IMAGE ?= zeus-builder 11 | DEFAULT_BUILDDIR ?= /var/cache/aur 12 | DEFAULT_AUR_HOST ?= aur.archlinux.org 13 | DEFAULT_RUNTIME ?= docker 14 | DEFAULT_RUNTIME_DIR ?= $(PREFIX)/lib/zeus/runtimes 15 | DEFAULT_DATA_DIR ?= $(PREFIX)/share/zeus 16 | 17 | ifeq ($(BUILD_TYPE),debug) 18 | CARGO_ARGS += 19 | else ifeq ($(BUILD_TYPE),release) 20 | CARGO_ARGS += --release 21 | endif 22 | 23 | .PHONY: 24 | all: build 25 | 26 | .PHONY: 27 | FORCE: ; 28 | 29 | .PHONY: 30 | .ONESHELL: 31 | build: FORCE 32 | export DEFAULT_NAME="$(DEFAULT_NAME)" 33 | export DEFAULT_IMAGE="$(DEFAULT_IMAGE)" 34 | export DEFAULT_BUILDDIR="$(DEFAULT_BUILDDIR)" 35 | export DEFAULT_AUR_HOST="$(DEFAULT_AUR_HOST)" 36 | export DEFAULT_RUNTIME="$(DEFAULT_RUNTIME)" 37 | export DEFAULT_RUNTIME_DIR="$(DEFAULT_RUNTIME_DIR)" 38 | export DEFAULT_DATA_DIR="$(DEFAULT_DATA_DIR)" 39 | 40 | export VERSION="$(VERSION)" 41 | cargo build --workspace $(CARGO_ARGS) -- 42 | 43 | .PHONY: 44 | clean: FORCE 45 | -cargo clean $(CARGO_ARGS) -- 46 | 47 | .PHONY: 48 | completions: FORCE 49 | ./target/$(BUILD_TYPE)/zeus completions --shell bash > completions/zeus.bash 50 | ./target/$(BUILD_TYPE)/zeus completions --shell zsh > completions/zeus.zsh 51 | ./target/$(BUILD_TYPE)/zeus completions --shell fish > completions/zeus.fish 52 | 53 | .PHONY: 54 | install: 55 | install -Dm0755 -t "$(DESTDIR)/$(PREFIX)/bin" target/$(BUILD_TYPE)/zeus 56 | 57 | mkdir -p "$(DESTDIR)/var/cache/aur" 58 | chmod 0777 "$(DESTDIR)/var/cache/aur" 59 | 60 | install -Dm644 -t "$(DESTDIR)/etc/apparmor.d" apparmor/zeus 61 | 62 | mkdir -p "$(DESTDIR)/etc/apparmor.d/zeus.d" 63 | for i in apparmor/zeus.d/*; do 64 | install -Dm644 -t "$(DESTDIR)/etc/apparmor.d/zeus.d" "$$i" 65 | done 66 | 67 | install -Dm644 completions/zeus.bash "$(DESTDIR)/usr/share/bash-completion/completions/zeus" 68 | install -Dm644 completions/zeus.zsh "$(DESTDIR)/usr/share/zsh/site-functions/_zeus" 69 | install -Dm644 completions/zeus.fish "$(DESTDIR)/usr/share/fish/vendor_completions.d/zeus.fish" 70 | 71 | mkdir -p "$(DESTDIR)/$(PREFIX)/lib/zeus/runtimes" 72 | chmod 0755 "$(DESTDIR)/$(PREFIX)/lib/zeus/runtimes" 73 | 74 | install -Dm0755 -t "$(DESTDIR)/$(PREFIX)/share/zeus" target/$(BUILD_TYPE)/builder 75 | 76 | for rtlib in target/$(BUILD_TYPE)/librt_*.so; do 77 | install -Dm644 -t "$(DESTDIR)/$(PREFIX)/lib/zeus/runtimes" "$$rtlib" 78 | done 79 | 80 | for rtdata in runtimes/*/data/; do 81 | install -D -t "$(DESTDIR)/$(PREFIX)/share/zeus" "$$rtdata"/* 82 | done 83 | 84 | .PHONY: 85 | apparmor_test: 86 | -apparmor_parser -R /etc/apparmor.d/zeus 87 | -cp -r apparmor/* /etc/apparmor.d/ 88 | -aa-complain /etc/apparmor.d/zeus 89 | 90 | .PHONY: 91 | uninstall: 92 | -apparmor_parser -R /etc/apparmor.d/zeus 93 | 94 | -rm -f "$(DESTDIR)/$(PREFIX)/bin/zeus" 95 | -rm -rf "$(DESTDIR)/$(PREFIX)/share/zeus" 96 | -rm -rf "$(DESTDIR)/$(PREFIX)/lib/zeus" 97 | 98 | -rm -f "$(DESTDIR)/etc/apparmor.d/zeus" 99 | -rm -f "$(DESTDIR)/usr/share/bash-completion/completions/zeus" 100 | -rm -f "$(DESTDIR)/usr/share/zsh/site-functions/_zeus" 101 | -rm -f "$(DESTDIR)/usr/share/fish/vendor_completions.d/zeus.fish" 102 | 103 | .PHONY: 104 | assets: FORCE 105 | scour \ 106 | -i assets/logo.inkscape.svg \ 107 | -o assets/logo.optimized.svg \ 108 | --enable-id-stripping \ 109 | --strip-xml-space \ 110 | --no-line-breaks \ 111 | --enable-comment-stripping \ 112 | --shorten-ids \ 113 | --remove-descriptive-elements \ 114 | --create-groups 115 | 116 | inkscape -C -w $(WIDTH) -h $(HEIGHT) \ 117 | -o assets/logo.$(WIDTH)x$(HEIGHT).png \ 118 | --export-type=png \ 119 | assets/logo.inkscape.svg 120 | 121 | .PHONY: 122 | assets_clean: FORCE 123 | -rm assets/logo.optimized.svg 124 | -rm assets/*.png 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [repo]: https://github.com/threadexio/zeus 2 | 3 | [latest-release]: https://github.com/threadexio/zeus/releases/latest 4 | [release-badge]: https://img.shields.io/github/v/release/threadexio/zeus?style=for-the-badge&display_name=release 5 | 6 | [issues]: https://github.com/threadexio/zeus/issues 7 | [issues-badge]: https://img.shields.io/github/issues-raw/threadexio/zeus?style=for-the-badge 8 | 9 | [build]: https://github.com/threadexio/zeus/actions/workflows/build.yaml 10 | [build-badge]: https://img.shields.io/github/workflow/status/threadexio/zeus/Build?style=for-the-badge 11 | 12 | [license]: https://github.com/threadexio/zeus/blob/master/LICENSE 13 | [license-badge]: https://img.shields.io/github/license/threadexio/zeus?style=for-the-badge 14 | 15 | [pkg-aur]: https://aur.archlinux.org/packages/zeus 16 | [pkg-aur-badge]: https://img.shields.io/aur/version/zeus?style=for-the-badge&label=AUR 17 | [pkg-bin-aur]: https://aur.archlinux.org/packages/zeus-bin 18 | [pkg-bin-aur-badge]: https://img.shields.io/aur/version/zeus-bin?style=for-the-badge&label=AUR 19 | 20 | [help]: https://github.com/threadexio/zeus/pulls 21 | [help-badge]: https://img.shields.io/badge/HELP-WANTED-green?style=for-the-badge&logo=github 22 | 23 | [wiki]: https://github.com/threadexio/zeus/wiki 24 | [usage]: https://github.com/threadexio/zeus/wiki/Usage 25 | [faq]: https://github.com/threadexio/zeus/wiki/FAQ 26 | [releases]: https://github.com/threadexio/zeus/releases 27 | [ci]: https://github.com/threadexio/zeus/actions 28 | [installing]: #installing 29 | [building]: #building 30 | 31 | 32 | 33 |
34 | 35 | 36 | 37 |

38 | zeus 39 |

40 | 41 | 42 | **[Wiki][wiki]**     43 | **[Install][installing]**     44 | **[Usage][usage]**     45 | **[FAQ][faq]**     46 | **[Releases][releases]**     47 | **[Issues][issues]**     48 | **[CI][ci]**     49 | 50 | --- 51 | 52 | [![release-badge]][releases] 53 | [![issues-badge]][issues] 54 | [![build-badge]][build] 55 | [![license-badge]][license] 56 | [![help-badge]][help] 57 | 58 |
59 | 60 | --- 61 | 62 |
63 | 64 | **Zeus**. A simple AUR helper which utilizes containers allowing developers and users alike to benefit from it's reproducible, clean and flexible builds. To get started with `zeus` follow the [install instructions][installing] or [build it yourself][building]. Be sure to check out the [wiki][wiki] for anything else. 65 | 66 | 67 |
68 | 69 | ## Installing 70 | 71 | Currently there are 2 packages in the AUR. 72 | 73 | - `zeus` - Which builds from the [latest release][latest-release] 74 | - `zeus-bin` - Which unpacks prebuilt binaries from the [latest release][latest-release]. 75 | 76 | | Package | Version | 77 | | :--------: | :---------------------------------: | 78 | | `zeus` | [![pkg-aur-badge]][pkg-aur] | 79 | | `zeus-bin` | [![pkg-bin-aur-badge]][pkg-bin-aur] | 80 | 81 | > **NOTE:** The binaries for `zeus-bin` are built in [Github Actions][build] 82 | 83 | After installing one of the 2 packages, there is one final step towards getting up and running. 84 | 85 | Building the actual builder container. 86 | 87 | ```shell 88 | $ zeus -B 89 | ``` 90 | 91 | > If your user does _**not**_ have access to the docker socket, you will have to run the previous command as root and subsequently every time you want to use the program. 92 | 93 |
94 | 95 | ## Building 96 | 97 | After cloning the repository, use the `build` target in the `Makefile` to build everything. 98 | 99 | ```shell 100 | $ make build 101 | ``` 102 | 103 | > By default the `build` target builds the debug version, if you wish to build the release version set `BUILD_TYPE=release`. 104 | 105 | ```shell 106 | $ export BUILD_TYPE=release 107 | $ make build 108 | ``` 109 | 110 | Testing local changes can be done in 2 ways. 111 | 112 |
113 | 114 | ### Not installing locally 115 | 116 | This method involves no extra steps. 117 | 118 | Running the built binary is as simple as: 119 | 120 | ```shell 121 | $ ./target/$BUILD_TYPE/zeus 122 | ``` 123 | 124 |
125 | 126 | ### Installing locally 127 | 128 | Installing locally for easier testing is possible with the `install` target. 129 | 130 | ```shell 131 | # make install 132 | ``` 133 | 134 | > `DESTDIR` and `PREFIX` can be used to alter the installation. 135 | 136 | After all this you should be able to just run `zeus` directly in the terminal. 137 | 138 | ```shell 139 | $ zeus 140 | ``` 141 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.box = "archlinux/archlinux" 6 | config.vm.box_check_update = true 7 | 8 | config.vm.synced_folder ".", "/zeus", 9 | sshfs_opts_append: "-o ro -o idmap=user", 10 | type: "sshfs" 11 | 12 | config.vm.provision "shell", inline: <<-SHELL 13 | pacman --needed --noconfirm -Syu base-devel docker 14 | gpasswd -a vagrant docker 15 | sudo systemctl enable docker.service 16 | SHELL 17 | end 18 | -------------------------------------------------------------------------------- /apparmor/zeus: -------------------------------------------------------------------------------- 1 | # vim:syntax=apparmor 2 | # AppArmor policy for zeus 3 | # Auther: threadexio 4 | # Copyright lololol (C) 1337 threadexio 5 | 6 | abi , 7 | 8 | include 9 | 10 | profile zeus "/{usr,usr/local}/bin/zeus" { 11 | include 12 | include 13 | include 14 | 15 | /proc/self/cgroup r, 16 | /proc/@{pid}/cgroup r, 17 | 18 | # Read-only data 19 | /{usr,usr/local}/share/zeus/** r, 20 | 21 | # List installed packages 22 | /var/cache/aur/ r, 23 | 24 | # Runtime socket & locking 25 | /var/cache/aur/.zeus* rwk, 26 | 27 | # Automatic install/uninstall 28 | /usr/bin/sudo Ux, 29 | 30 | # AUR requests 31 | network tcp, 32 | 33 | include 34 | } 35 | -------------------------------------------------------------------------------- /apparmor/zeus.d/docker: -------------------------------------------------------------------------------- 1 | abi , 2 | 3 | /usr/bin/docker ux, 4 | -------------------------------------------------------------------------------- /assets/logo.256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/threadexio/zeus/7bdb2138e2deb917b68a08f7a21a5700e7438fd1/assets/logo.256x256.png -------------------------------------------------------------------------------- /assets/logo.512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/threadexio/zeus/7bdb2138e2deb917b68a08f7a21a5700e7438fd1/assets/logo.512x512.png -------------------------------------------------------------------------------- /assets/logo.inkscape.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 39 | 42 | 43 | 45 | 62 | 69 | 70 | 75 | 78 | 83 | 90 | 97 | 104 | 111 | 118 | 125 | 130 | 131 | 134 | 141 | 148 | 155 | 162 | 169 | 176 | 183 | 190 | 191 | 194 | 199 | 212 | 225 | 226 | 229 | 233 | 237 | 241 | 245 | 249 | 253 | 258 | 263 | 264 | 265 | 266 | -------------------------------------------------------------------------------- /assets/logo.optimized.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/social-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/threadexio/zeus/7bdb2138e2deb917b68a08f7a21a5700e7438fd1/assets/social-image.png -------------------------------------------------------------------------------- /assets/social-image.xcf.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/threadexio/zeus/7bdb2138e2deb917b68a08f7a21a5700e7438fd1/assets/social-image.xcf.xz -------------------------------------------------------------------------------- /completions/zeus.bash: -------------------------------------------------------------------------------- 1 | _zeus() { 2 | local i cur prev opts cmds 3 | COMPREPLY=() 4 | cur="${COMP_WORDS[COMP_CWORD]}" 5 | prev="${COMP_WORDS[COMP_CWORD-1]}" 6 | cmd="" 7 | opts="" 8 | 9 | for i in ${COMP_WORDS[@]} 10 | do 11 | case "${i}" in 12 | "$1") 13 | cmd="zeus" 14 | ;; 15 | build) 16 | cmd+="__build" 17 | ;; 18 | completions) 19 | cmd+="__completions" 20 | ;; 21 | help) 22 | cmd+="__help" 23 | ;; 24 | query) 25 | cmd+="__query" 26 | ;; 27 | remove) 28 | cmd+="__remove" 29 | ;; 30 | runtime) 31 | cmd+="__runtime" 32 | ;; 33 | sync) 34 | cmd+="__sync" 35 | ;; 36 | *) 37 | ;; 38 | esac 39 | done 40 | 41 | case "${cmd}" in 42 | zeus) 43 | opts="-h -V -d --help --version --color --debug --force --builddir --aur --rt --rtdir sync remove build query completions runtime help" 44 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then 45 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 46 | return 0 47 | fi 48 | case "${prev}" in 49 | --color) 50 | COMPREPLY=($(compgen -W "always auto never" -- "${cur}")) 51 | return 0 52 | ;; 53 | --builddir) 54 | COMPREPLY=($(compgen -f "${cur}")) 55 | return 0 56 | ;; 57 | --aur) 58 | COMPREPLY=($(compgen -f "${cur}")) 59 | return 0 60 | ;; 61 | --rt) 62 | COMPREPLY=($(compgen -f "${cur}")) 63 | return 0 64 | ;; 65 | --rtdir) 66 | COMPREPLY=($(compgen -f "${cur}")) 67 | return 0 68 | ;; 69 | *) 70 | COMPREPLY=() 71 | ;; 72 | esac 73 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 74 | return 0 75 | ;; 76 | zeus__build) 77 | opts="-h --image --name --help" 78 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then 79 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 80 | return 0 81 | fi 82 | case "${prev}" in 83 | --image) 84 | COMPREPLY=($(compgen -f "${cur}")) 85 | return 0 86 | ;; 87 | --name) 88 | COMPREPLY=($(compgen -f "${cur}")) 89 | return 0 90 | ;; 91 | *) 92 | COMPREPLY=() 93 | ;; 94 | esac 95 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 96 | return 0 97 | ;; 98 | zeus__completions) 99 | opts="-h --shell --help" 100 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then 101 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 102 | return 0 103 | fi 104 | case "${prev}" in 105 | --shell) 106 | COMPREPLY=($(compgen -f "${cur}")) 107 | return 0 108 | ;; 109 | *) 110 | COMPREPLY=() 111 | ;; 112 | esac 113 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 114 | return 0 115 | ;; 116 | zeus__help) 117 | opts="..." 118 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then 119 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 120 | return 0 121 | fi 122 | case "${prev}" in 123 | *) 124 | COMPREPLY=() 125 | ;; 126 | esac 127 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 128 | return 0 129 | ;; 130 | zeus__query) 131 | opts="-i -h --info --by --output --help ..." 132 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then 133 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 134 | return 0 135 | fi 136 | case "${prev}" in 137 | --by) 138 | COMPREPLY=($(compgen -W "name description maintainer depends makedepends optdepends checkdepends" -- "${cur}")) 139 | return 0 140 | ;; 141 | --output) 142 | COMPREPLY=($(compgen -W "pretty json" -- "${cur}")) 143 | return 0 144 | ;; 145 | *) 146 | COMPREPLY=() 147 | ;; 148 | esac 149 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 150 | return 0 151 | ;; 152 | zeus__remove) 153 | opts="-h --uninstall --name --help ..." 154 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then 155 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 156 | return 0 157 | fi 158 | case "${prev}" in 159 | --name) 160 | COMPREPLY=($(compgen -f "${cur}")) 161 | return 0 162 | ;; 163 | *) 164 | COMPREPLY=() 165 | ;; 166 | esac 167 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 168 | return 0 169 | ;; 170 | zeus__runtime) 171 | opts="-l -h --list --help" 172 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then 173 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 174 | return 0 175 | fi 176 | case "${prev}" in 177 | *) 178 | COMPREPLY=() 179 | ;; 180 | esac 181 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 182 | return 0 183 | ;; 184 | zeus__sync) 185 | opts="-u -h --upgrade --install --buildargs --name --help ..." 186 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then 187 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 188 | return 0 189 | fi 190 | case "${prev}" in 191 | --buildargs) 192 | COMPREPLY=($(compgen -f "${cur}")) 193 | return 0 194 | ;; 195 | --name) 196 | COMPREPLY=($(compgen -f "${cur}")) 197 | return 0 198 | ;; 199 | *) 200 | COMPREPLY=() 201 | ;; 202 | esac 203 | COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) 204 | return 0 205 | ;; 206 | esac 207 | } 208 | 209 | complete -F _zeus -o bashdefault -o default zeus 210 | -------------------------------------------------------------------------------- /completions/zeus.fish: -------------------------------------------------------------------------------- 1 | complete -c zeus -n "__fish_use_subcommand" -l color -d 'Colorize the output' -r -f -a "{always ,auto ,never }" 2 | complete -c zeus -n "__fish_use_subcommand" -l builddir -d 'Package build directory' -r 3 | complete -c zeus -n "__fish_use_subcommand" -l aur -d 'AUR host' -r 4 | complete -c zeus -n "__fish_use_subcommand" -l rt -d 'Specify runtime to use' -r 5 | complete -c zeus -n "__fish_use_subcommand" -l rtdir -d 'Specify directory to search for runtimes' -r 6 | complete -c zeus -n "__fish_use_subcommand" -s h -l help -d 'Print help information' 7 | complete -c zeus -n "__fish_use_subcommand" -s V -l version -d 'Print version information' 8 | complete -c zeus -n "__fish_use_subcommand" -s d -l debug -d 'Show debug logs' 9 | complete -c zeus -n "__fish_use_subcommand" -l force -d 'Ignore all warnings' 10 | complete -c zeus -n "__fish_use_subcommand" -f -a "sync" -d 'Sync packages' 11 | complete -c zeus -n "__fish_use_subcommand" -f -a "remove" -d 'Remove packages' 12 | complete -c zeus -n "__fish_use_subcommand" -f -a "build" -d 'Build/Update builder image' 13 | complete -c zeus -n "__fish_use_subcommand" -f -a "query" -d 'Query the AUR' 14 | complete -c zeus -n "__fish_use_subcommand" -f -a "completions" -d 'Generate shell completions & others' 15 | complete -c zeus -n "__fish_use_subcommand" -f -a "runtime" -d 'Various runtime operations' 16 | complete -c zeus -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' 17 | complete -c zeus -n "__fish_seen_subcommand_from sync" -l buildargs -d 'Extra arguments for makepkg' -r 18 | complete -c zeus -n "__fish_seen_subcommand_from sync" -l name -d 'Builder machine name' -r 19 | complete -c zeus -n "__fish_seen_subcommand_from sync" -s u -l upgrade -d 'Upgrade packages' 20 | complete -c zeus -n "__fish_seen_subcommand_from sync" -l install -d 'Install packages after build' 21 | complete -c zeus -n "__fish_seen_subcommand_from sync" -s h -l help -d 'Print help information' 22 | complete -c zeus -n "__fish_seen_subcommand_from remove" -l name -d 'Builder machine name' -r 23 | complete -c zeus -n "__fish_seen_subcommand_from remove" -l uninstall -d 'Uninstall packages after remove' 24 | complete -c zeus -n "__fish_seen_subcommand_from remove" -s h -l help -d 'Print help information' 25 | complete -c zeus -n "__fish_seen_subcommand_from build" -l image -d 'Builder image name' -r 26 | complete -c zeus -n "__fish_seen_subcommand_from build" -l name -d 'Builder machine name' -r 27 | complete -c zeus -n "__fish_seen_subcommand_from build" -s h -l help -d 'Print help information' 28 | complete -c zeus -n "__fish_seen_subcommand_from query" -l by -d 'Query AUR packages by' -r -f -a "{name ,description ,maintainer ,depends ,makedepends ,optdepends ,checkdepends }" 29 | complete -c zeus -n "__fish_seen_subcommand_from query" -l output -d 'Output format' -r -f -a "{pretty ,json }" 30 | complete -c zeus -n "__fish_seen_subcommand_from query" -s i -l info -d 'Display additional information on results' 31 | complete -c zeus -n "__fish_seen_subcommand_from query" -s h -l help -d 'Print help information' 32 | complete -c zeus -n "__fish_seen_subcommand_from completions" -l shell -d 'Specify shell to generate completions for' -r 33 | complete -c zeus -n "__fish_seen_subcommand_from completions" -s h -l help -d 'Print help information' 34 | complete -c zeus -n "__fish_seen_subcommand_from runtime" -s l -l list -d 'List all available runtimes' 35 | complete -c zeus -n "__fish_seen_subcommand_from runtime" -s h -l help -d 'Print help information' 36 | -------------------------------------------------------------------------------- /completions/zeus.zsh: -------------------------------------------------------------------------------- 1 | #compdef zeus 2 | 3 | autoload -U is-at-least 4 | 5 | _zeus() { 6 | typeset -A opt_args 7 | typeset -a _arguments_options 8 | local ret=1 9 | 10 | if is-at-least 5.2; then 11 | _arguments_options=(-s -S -C) 12 | else 13 | _arguments_options=(-s -C) 14 | fi 15 | 16 | local context curcontext="$curcontext" state line 17 | _arguments "${_arguments_options[@]}" \ 18 | '--color=[Colorize the output]: :(always auto never)' \ 19 | '--builddir=[Package build directory]: : ' \ 20 | '--aur=[AUR host]: : ' \ 21 | '--rt=[Specify runtime to use]: : ' \ 22 | '--rtdir=[Specify directory to search for runtimes]: : ' \ 23 | '-h[Print help information]' \ 24 | '--help[Print help information]' \ 25 | '-V[Print version information]' \ 26 | '--version[Print version information]' \ 27 | '-d[Show debug logs]' \ 28 | '--debug[Show debug logs]' \ 29 | '--force[Ignore all warnings]' \ 30 | ":: :_zeus_commands" \ 31 | "*::: :->zeus" \ 32 | && ret=0 33 | case $state in 34 | (zeus) 35 | words=($line[1] "${words[@]}") 36 | (( CURRENT += 1 )) 37 | curcontext="${curcontext%:*:*}:zeus-command-$line[1]:" 38 | case $line[1] in 39 | (sync) 40 | _arguments "${_arguments_options[@]}" \ 41 | '--buildargs=[Extra arguments for makepkg]: : ' \ 42 | '--name=[Builder machine name]: : ' \ 43 | '-u[Upgrade packages]' \ 44 | '--upgrade[Upgrade packages]' \ 45 | '--install[Install packages after build]' \ 46 | '-h[Print help information]' \ 47 | '--help[Print help information]' \ 48 | '*::packages -- Packages to sync:' \ 49 | && ret=0 50 | ;; 51 | (remove) 52 | _arguments "${_arguments_options[@]}" \ 53 | '--name=[Builder machine name]: : ' \ 54 | '--uninstall[Uninstall packages after remove]' \ 55 | '-h[Print help information]' \ 56 | '--help[Print help information]' \ 57 | '*::packages -- Packages to remove:' \ 58 | && ret=0 59 | ;; 60 | (build) 61 | _arguments "${_arguments_options[@]}" \ 62 | '--image=[Builder image name]: : ' \ 63 | '--name=[Builder machine name]: : ' \ 64 | '-h[Print help information]' \ 65 | '--help[Print help information]' \ 66 | && ret=0 67 | ;; 68 | (query) 69 | _arguments "${_arguments_options[@]}" \ 70 | '(-i --info)--by=[Query AUR packages by]: :(name description maintainer depends makedepends optdepends checkdepends)' \ 71 | '--output=[Output format]: :(pretty json)' \ 72 | '(--by)-i[Display additional information on results]' \ 73 | '(--by)--info[Display additional information on results]' \ 74 | '-h[Print help information]' \ 75 | '--help[Print help information]' \ 76 | '*::keywords -- Keywords to use:' \ 77 | && ret=0 78 | ;; 79 | (completions) 80 | _arguments "${_arguments_options[@]}" \ 81 | '--shell=[Specify shell to generate completions for]: : ' \ 82 | '-h[Print help information]' \ 83 | '--help[Print help information]' \ 84 | && ret=0 85 | ;; 86 | (runtime) 87 | _arguments "${_arguments_options[@]}" \ 88 | '-l[List all available runtimes]' \ 89 | '--list[List all available runtimes]' \ 90 | '-h[Print help information]' \ 91 | '--help[Print help information]' \ 92 | && ret=0 93 | ;; 94 | (help) 95 | _arguments "${_arguments_options[@]}" \ 96 | '*::subcommand -- The subcommand whose help message to display:' \ 97 | && ret=0 98 | ;; 99 | esac 100 | ;; 101 | esac 102 | } 103 | 104 | (( $+functions[_zeus_commands] )) || 105 | _zeus_commands() { 106 | local commands; commands=( 107 | 'sync:Sync packages' \ 108 | 'remove:Remove packages' \ 109 | 'build:Build/Update builder image' \ 110 | 'query:Query the AUR' \ 111 | 'completions:Generate shell completions & others' \ 112 | 'runtime:Various runtime operations' \ 113 | 'help:Print this message or the help of the given subcommand(s)' \ 114 | ) 115 | _describe -t commands 'zeus commands' commands "$@" 116 | } 117 | (( $+functions[_zeus__build_commands] )) || 118 | _zeus__build_commands() { 119 | local commands; commands=() 120 | _describe -t commands 'zeus build commands' commands "$@" 121 | } 122 | (( $+functions[_zeus__completions_commands] )) || 123 | _zeus__completions_commands() { 124 | local commands; commands=() 125 | _describe -t commands 'zeus completions commands' commands "$@" 126 | } 127 | (( $+functions[_zeus__help_commands] )) || 128 | _zeus__help_commands() { 129 | local commands; commands=() 130 | _describe -t commands 'zeus help commands' commands "$@" 131 | } 132 | (( $+functions[_zeus__query_commands] )) || 133 | _zeus__query_commands() { 134 | local commands; commands=() 135 | _describe -t commands 'zeus query commands' commands "$@" 136 | } 137 | (( $+functions[_zeus__remove_commands] )) || 138 | _zeus__remove_commands() { 139 | local commands; commands=() 140 | _describe -t commands 'zeus remove commands' commands "$@" 141 | } 142 | (( $+functions[_zeus__runtime_commands] )) || 143 | _zeus__runtime_commands() { 144 | local commands; commands=() 145 | _describe -t commands 'zeus runtime commands' commands "$@" 146 | } 147 | (( $+functions[_zeus__sync_commands] )) || 148 | _zeus__sync_commands() { 149 | local commands; commands=() 150 | _describe -t commands 'zeus sync commands' commands "$@" 151 | } 152 | 153 | _zeus "$@" 154 | -------------------------------------------------------------------------------- /runtimes/zeus_rt_docker/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /runtimes/zeus_rt_docker/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zeus_rt_docker" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["threadexio"] 6 | description = "Docker Runtime for the Zeus AUR helper" 7 | license = "GPL-3.0-or-later" 8 | 9 | # The following are necessary for any runtime 10 | [lib] 11 | name = "rt_docker" 12 | crate-type = ["cdylib"] 13 | 14 | [dependencies.zeus] 15 | path = "../../" 16 | 17 | [dependencies] 18 | serde = { version = "^1.0", features = ["derive"] } 19 | serde_json = "^1.0" 20 | -------------------------------------------------------------------------------- /runtimes/zeus_rt_docker/data/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM archlinux/archlinux:base-devel 2 | 3 | RUN pacman -Syyu \ 4 | --noconfirm \ 5 | --needed \ 6 | gcc make cmake git 7 | 8 | RUN useradd -r -m builder 9 | RUN echo "builder ALL=(ALL:ALL) NOPASSWD: /usr/bin/pacman" > /etc/sudoers.d/builder 10 | 11 | VOLUME [ "/build" ] 12 | 13 | COPY --chown=root:root builder /usr/local/bin 14 | 15 | RUN chmod +x /usr/local/bin/* 16 | 17 | USER builder 18 | 19 | WORKDIR /build 20 | ENTRYPOINT ["/usr/local/bin/builder"] 21 | -------------------------------------------------------------------------------- /runtimes/zeus_rt_docker/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This is the zeus runtime driver for Docker. 2 | //! Available user configuration is done by the 3 | //! following environment variables: 4 | //! - `DOCKER_BIN` - This must point to the docker cli tool. (default: `/usr/bin/docker`) 5 | 6 | use zeus::{machine::*, *}; 7 | 8 | use std::env; 9 | use std::io::BufRead; 10 | use std::process; 11 | 12 | mod models; 13 | 14 | macro_rules! handle { 15 | ($x:expr) => { 16 | match $x { 17 | Ok(v) => v, 18 | Err(e) => { 19 | return Err(format!( 20 | "{}: {}", 21 | "could not execute docker", e 22 | )) 23 | }, 24 | } 25 | }; 26 | ($x:expr, $msg:tt) => { 27 | match $x { 28 | Ok(v) => v, 29 | Err(e) => return Err(format!("{}: {}", $msg, e)), 30 | } 31 | }; 32 | } 33 | 34 | macro_rules! check_exit { 35 | ($output:expr) => { 36 | if !$output.status.success() { 37 | return Err(format!( 38 | "{}", 39 | String::from_utf8_lossy(&$output.stderr[..]) 40 | )); 41 | } 42 | }; 43 | } 44 | 45 | #[derive(Default)] 46 | pub struct DockerRuntime { 47 | docker_bin: String, 48 | } 49 | 50 | declare_runtime!(DockerRuntime, DockerRuntime::default); 51 | 52 | impl IRuntime for DockerRuntime { 53 | fn name(&self) -> &'static str { 54 | "docker" 55 | } 56 | 57 | fn version(&self) -> &'static str { 58 | env!("CARGO_PKG_VERSION", "must be built with cargo") 59 | } 60 | 61 | fn rt_api_version(&self) -> u32 { 62 | 1 63 | } 64 | 65 | fn init(&mut self) -> Result<()> { 66 | self.docker_bin = env::var("DOCKER_BIN") 67 | .unwrap_or(String::from("/usr/bin/docker")); 68 | 69 | Ok(()) 70 | } 71 | 72 | fn exit(&mut self) {} 73 | 74 | fn list_images(&self) -> Result> { 75 | let child = handle!(process::Command::new(&self.docker_bin) 76 | .args(["image", "ls"]) 77 | .args(["--format", models::IMAGE_FMT]) 78 | .output()); 79 | 80 | check_exit!(child); 81 | 82 | let mut images: Vec = Vec::new(); 83 | 84 | for line in child.stdout.lines() { 85 | let line = match line { 86 | Ok(v) => v, 87 | Err(_) => continue, 88 | }; 89 | 90 | let image: models::Image = handle!( 91 | serde_json::from_str(&line), 92 | "could not decode docker output" 93 | ); 94 | 95 | images.push(image.name); 96 | } 97 | 98 | Ok(images) 99 | } 100 | 101 | fn make_image(&mut self, image_name: &str) -> Result<()> { 102 | let build_context = String::from("./"); 103 | 104 | let status = handle!(process::Command::new(&self.docker_bin) 105 | .args(["build"]) 106 | .args(["--pull", "--rm"]) 107 | .args(["-t", image_name]) 108 | .arg("--") 109 | .arg(build_context) 110 | .status()); 111 | 112 | if !status.success() { 113 | return Err(format!("error during image build")); 114 | } 115 | 116 | Ok(()) 117 | } 118 | 119 | fn delete_image(&mut self, image_name: &str) -> Result<()> { 120 | let child = handle!(process::Command::new(&self.docker_bin) 121 | .args(["image", "rm"]) 122 | .arg("--") 123 | .arg(image_name) 124 | .output()); 125 | 126 | check_exit!(child); 127 | 128 | Ok(()) 129 | } 130 | 131 | fn list_machines(&self) -> Result> { 132 | let child = handle!(process::Command::new(&self.docker_bin) 133 | .args(["container", "ls"]) 134 | .args(["-a"]) 135 | .args(["--format", models::CONTAINER_FMT]) 136 | .output()); 137 | 138 | check_exit!(child); 139 | 140 | let mut containers: Vec = Vec::new(); 141 | 142 | for line in child.stdout.lines() { 143 | let line = match line { 144 | Ok(v) => v, 145 | Err(_) => continue, 146 | }; 147 | 148 | let container: models::Container = handle!( 149 | serde_json::from_str(&line), 150 | "could not decode docker output" 151 | ); 152 | 153 | containers.push(container.name); 154 | } 155 | 156 | Ok(containers) 157 | } 158 | 159 | fn create_machine( 160 | &mut self, 161 | machine_name: &str, 162 | image_name: &str, 163 | config: &AppConfig, 164 | ) -> Result<()> { 165 | let child = handle!(process::Command::new(&self.docker_bin) 166 | .args(["container", "create"]) 167 | .args(["-i", "-t",]) 168 | .args(["--name", machine_name]) 169 | .args([ 170 | "-v", 171 | "/var/cache/pacman/pkg:/var/cache/pacman/pkg:rw" 172 | ]) 173 | .args(["-v", &format!("{}:/build:rw", config.build_dir)]) 174 | .args([ 175 | "--cap-drop=all", 176 | "--cap-add=CAP_SETUID", 177 | "--cap-add=CAP_SETGID", 178 | "--cap-add=CAP_SYS_CHROOT", 179 | ]) 180 | .arg("--") 181 | .arg(image_name) 182 | .output()); 183 | 184 | check_exit!(child); 185 | 186 | Ok(()) 187 | } 188 | 189 | fn start_machine(&mut self, machine_name: &str) -> Result<()> { 190 | let status = handle!(process::Command::new(&self.docker_bin) 191 | .args(["container", "start"]) 192 | .args(["-a", "-i"]) 193 | .arg("--") 194 | .arg(machine_name) 195 | .status()); 196 | 197 | if !status.success() { 198 | return Err(format!( 199 | "failed to start and attach to machine" 200 | )); 201 | } 202 | 203 | Ok(()) 204 | } 205 | 206 | fn stop_machine(&mut self, machine_name: &str) -> Result<()> { 207 | let child = handle!(process::Command::new(&self.docker_bin) 208 | .args(["container", "kill"]) 209 | .arg("--") 210 | .arg(machine_name) 211 | .output()); 212 | 213 | check_exit!(child); 214 | 215 | Ok(()) 216 | } 217 | 218 | fn delete_machine(&mut self, machine_name: &str) -> Result<()> { 219 | let child = handle!(process::Command::new(&self.docker_bin) 220 | .args(["container", "rm"]) 221 | .args(["-f", "-v"]) 222 | .arg("--") 223 | .arg(machine_name) 224 | .output()); 225 | 226 | check_exit!(child); 227 | 228 | Ok(()) 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /runtimes/zeus_rt_docker/src/models.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | 3 | pub const IMAGE_FMT: &'static str = 4 | "{\"name\":\"{{.Repository}}:{{.Tag}}\"}"; 5 | 6 | #[derive(Deserialize)] 7 | pub struct Image { 8 | pub name: String, 9 | } 10 | 11 | pub const CONTAINER_FMT: &'static str = "{\"name\":\"{{.Names}}\"}"; 12 | 13 | #[derive(Deserialize)] 14 | pub struct Container { 15 | pub name: String, 16 | } 17 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 70 2 | hard_tabs = true 3 | tab_spaces = 4 4 | newline_style = "Unix" 5 | use_small_heuristics = "Off" 6 | fn_call_width = 60 7 | attr_fn_like_width = 60 8 | struct_lit_width = 60 9 | struct_variant_width = 60 10 | array_width = 60 11 | chain_width = 60 12 | single_line_if_else_max_width = 0 13 | reorder_imports = true 14 | reorder_modules = true 15 | remove_nested_parens = true 16 | match_arm_leading_pipes = "Never" 17 | fn_args_layout = "Tall" 18 | match_block_trailing_comma = true 19 | edition = "2021" 20 | merge_derives = true 21 | use_try_shorthand = true 22 | use_field_init_shorthand = true 23 | force_explicit_abi = true 24 | -------------------------------------------------------------------------------- /scripts/make_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | O="$PWD/zeus.tar.gz" 5 | 6 | DESTDIR="$(mktemp -d -t zeus.XXXXXX)" 7 | export DESTDIR 8 | 9 | export BUILD_TYPE=release 10 | export PREFIX=/usr 11 | 12 | make build completions install 13 | 14 | (cd "$DESTDIR" && tar -acvpf "$O" --owner=0 --group=0 -- *) 15 | -------------------------------------------------------------------------------- /src/aur.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::str::FromStr; 3 | 4 | use const_format::formatcp; 5 | use reqwest::blocking::{Client, ClientBuilder}; 6 | use serde::{Deserialize, Serialize}; 7 | 8 | /// Type alias for timestamps 9 | pub type Timestamp = u64; 10 | /// Type alias for id fields 11 | pub type Id = u64; 12 | /// Type alias for version number fields 13 | pub type Version = u8; 14 | 15 | /// Type alias for request results 16 | pub type AurResult = reqwest::Result; 17 | 18 | /// Package search types 19 | #[allow(dead_code)] 20 | #[derive(Debug)] 21 | pub enum By { 22 | /// Search by package name 23 | Name, 24 | /// Search by package name and description 25 | NameDesc, 26 | /// Search by maintainer 27 | Maintainer, 28 | /// Search by dependencies 29 | Depends, 30 | /// Search by dev dependencies 31 | MakeDepends, 32 | /// Search by optional dependencies 33 | OptDepends, 34 | /// Search by testing dependencies 35 | CheckDepends, 36 | } 37 | 38 | #[derive(Debug)] 39 | pub struct AurBuilder { 40 | host: String, 41 | protocol: String, 42 | 43 | version: Version, 44 | rpc_path: String, 45 | } 46 | 47 | /// Structure representing an AUR instance 48 | #[derive( 49 | Debug, Default, PartialEq, Clone, Serialize, Deserialize, 50 | )] 51 | pub struct Aur { 52 | base_url: String, 53 | rpc_url: String, 54 | } 55 | 56 | #[allow(non_snake_case)] 57 | #[derive( 58 | Debug, Default, PartialEq, Clone, Serialize, Deserialize, 59 | )] 60 | pub struct Package { 61 | pub ID: Option, 62 | pub Name: Option, 63 | pub PackageBaseID: Option, 64 | pub PackageBase: Option, 65 | pub Version: Option, 66 | pub Description: Option, 67 | pub URL: Option, 68 | pub NumVotes: Option, 69 | pub Popularity: Option, 70 | pub OutOfDate: Option, 71 | pub Maintainer: Option, 72 | pub FirstSubmitted: Option, 73 | pub LastModified: Option, 74 | pub URLPath: Option, 75 | 76 | pub Depends: Option>, 77 | pub MakeDepends: Option>, 78 | pub OptDepends: Option>, 79 | pub CheckDepends: Option>, 80 | pub Conflicts: Option>, 81 | pub Provides: Option>, 82 | pub Replaces: Option>, 83 | pub Groups: Option>, 84 | pub License: Option>, 85 | pub Keywords: Option>, 86 | 87 | pub package_files: Option>, 88 | } 89 | 90 | /// Structure representing the responses 91 | #[derive(Debug, Serialize, Deserialize)] 92 | pub struct AurResponse { 93 | /// Number of returned packages 94 | pub resultcount: usize, 95 | 96 | /// Packages returned 97 | pub results: Vec, 98 | 99 | /// Query type 100 | pub r#type: String, 101 | /// AUR version 102 | pub version: Version, 103 | } 104 | 105 | fn make_req_client() -> Client { 106 | use crate::config; 107 | ClientBuilder::new() 108 | .user_agent(formatcp!("{}-{}", config::NAME, config::VERSION)) 109 | .build() 110 | .unwrap() 111 | } 112 | 113 | impl fmt::Display for By { 114 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 115 | write!( 116 | f, 117 | "{}", 118 | match self { 119 | By::Name => "name".to_owned(), 120 | By::NameDesc => "name-desc".to_owned(), 121 | By::Maintainer => "maintainer".to_owned(), 122 | By::Depends => "depends".to_owned(), 123 | By::MakeDepends => "makedepends".to_owned(), 124 | By::OptDepends => "optdepends".to_owned(), 125 | By::CheckDepends => "checkdepends".to_owned(), 126 | } 127 | ) 128 | } 129 | } 130 | 131 | impl FromStr for By { 132 | type Err = String; 133 | 134 | fn from_str(s: &str) -> Result { 135 | match s { 136 | "name" => Ok(Self::Name), 137 | "description" => Ok(Self::NameDesc), 138 | "maintainer" => Ok(Self::Maintainer), 139 | "depends" => Ok(Self::Depends), 140 | "makedepends" => Ok(Self::MakeDepends), 141 | "optdepends" => Ok(Self::OptDepends), 142 | "checkdepends" => Ok(Self::CheckDepends), 143 | _ => unreachable!(), 144 | } 145 | } 146 | } 147 | 148 | #[allow(dead_code)] 149 | impl AurBuilder { 150 | /// Create a new AUR instance 151 | pub fn build(self) -> Aur { 152 | Aur { 153 | base_url: format!("{}://{}/", self.protocol, self.host), 154 | rpc_url: format!( 155 | "{}://{}/{}/?v={}", 156 | self.protocol, self.host, self.rpc_path, self.version 157 | ), 158 | } 159 | } 160 | 161 | /// Set AUR host 162 | /// 163 | /// # Example: 164 | /// ``` 165 | /// let aur_instance = aur::Aur::new() 166 | /// .host("aur.example.com") 167 | /// .build(); 168 | /// ``` 169 | pub fn host(mut self, host: String) -> Self { 170 | self.host = host; 171 | self 172 | } 173 | 174 | /// Set AUR protocol 175 | /// 176 | /// # Example: 177 | /// ``` 178 | /// let aur_instance = aur::Aur::new() 179 | /// .protocol("https") 180 | /// .build(); 181 | /// ``` 182 | pub fn protocol(mut self, protocol: String) -> Self { 183 | self.protocol = protocol; 184 | self 185 | } 186 | 187 | /// Set AUR RPC version 188 | /// 189 | /// # Example: 190 | /// ``` 191 | /// let aur_instance = aur::Aur::new() 192 | /// .version(5) 193 | /// .build(); 194 | /// ``` 195 | pub fn version(mut self, version: u8) -> Self { 196 | self.version = version; 197 | self 198 | } 199 | 200 | /// Set AUR RPC endpoint path from / 201 | /// 202 | /// # Example: 203 | /// ``` 204 | /// let aur_instance = aur::Aur::new() 205 | /// .rpc_path("rpc/") 206 | /// .build(); 207 | /// ``` 208 | pub fn rpc_path(mut self, rpc_path: String) -> Self { 209 | self.rpc_path = rpc_path; 210 | self 211 | } 212 | } 213 | 214 | #[allow(dead_code)] 215 | impl Aur { 216 | /// Create a new AurBuilder 217 | pub fn new() -> AurBuilder { 218 | AurBuilder { 219 | host: "aur.archlinux.org".to_owned(), 220 | protocol: "https".to_owned(), 221 | rpc_path: "rpc".to_owned(), 222 | version: 5, 223 | } 224 | } 225 | 226 | /// Get full URL of AUR instance 227 | /// 228 | /// # Example: 229 | /// ``` 230 | /// let aur_instance = aur::Aur::new().build(); 231 | /// 232 | /// let url = aur_instance.get_url(); 233 | /// ``` 234 | pub fn get_url(&self) -> &str { 235 | &self.base_url 236 | } 237 | 238 | /// Get full URL of AUR RPC endpoint 239 | /// 240 | /// # Example: 241 | /// ``` 242 | /// let aur_instance = aur::Aur::new().build(); 243 | /// 244 | /// let url = aur_instance.get_rpc_url(); 245 | /// ``` 246 | pub fn get_rpc_url(&self) -> &str { 247 | &self.rpc_url 248 | } 249 | 250 | /// Search for packages. 251 | /// 252 | /// # Example: 253 | /// ``` 254 | /// let aur_instance = aur::Aur::new().build(); 255 | /// 256 | /// let keywords :HashSet<&str> = HashSet::new(); 257 | /// keywords.insert("zeus"); 258 | /// keywords.insert("zeus-bin"); 259 | /// 260 | /// let response = aur_instance.search(aur::By::Name, &keywords); 261 | /// ``` 262 | pub fn search(&self, by: By, keywords: &Vec) -> AurResult 263 | where 264 | T: fmt::Display, 265 | { 266 | let mut url = format!( 267 | "{}&type=search&by={}", 268 | &self.rpc_url, 269 | by.to_string().to_lowercase() 270 | ); 271 | 272 | for keyword in keywords { 273 | url.push_str(&format!("&arg={}", keyword)); 274 | } 275 | 276 | let res: AurResponse = 277 | make_req_client().get(url).send()?.json()?; 278 | 279 | Ok(res) 280 | } 281 | 282 | /// Request package information. 283 | /// 284 | /// Example: 285 | /// ``` 286 | /// let aur_instance = aur::Aur::new().build(); 287 | /// 288 | /// let packages :HashSet<&str> = HashSet::new(); 289 | /// packages.insert("zeus"); 290 | /// packages.insert("zeus-bin"); 291 | /// 292 | /// let response = aur_instance.info(&packages); 293 | /// ``` 294 | pub fn info(&self, packages: &Vec) -> AurResult 295 | where 296 | T: fmt::Display, 297 | { 298 | let mut url = format!("{}&type=info", &self.rpc_url); 299 | 300 | for package in packages { 301 | url.push_str(&format!("&arg[]={}", package)); 302 | } 303 | 304 | let res: AurResponse = 305 | make_req_client().get(url).send()?.json()?; 306 | 307 | Ok(res) 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /src/builder.rs: -------------------------------------------------------------------------------- 1 | use std::process::{exit, ExitStatus}; 2 | 3 | use std::os::unix::net::UnixStream; 4 | 5 | mod aur; 6 | mod config; 7 | mod error; 8 | mod log; 9 | mod machine; 10 | mod message; 11 | mod unix; 12 | 13 | use aur::Package; 14 | use colored::Colorize; 15 | use config::{AppConfig, Operation}; 16 | use error::{Result, ZeusError}; 17 | use message::Message; 18 | 19 | fn chdir(dir: &str) -> Result<()> { 20 | zerr!( 21 | std::env::set_current_dir(dir), 22 | "fs", 23 | "Cannot change cwd to \"{}\"", 24 | dir 25 | ); 26 | 27 | Ok(()) 28 | } 29 | 30 | fn run_command(arg0: &str, args: &[&str]) -> Result { 31 | use std::process::Command; 32 | 33 | info!("builder", "Running: {} {}", arg0, args.join(" ")); 34 | 35 | let status = zerr!( 36 | Command::new(arg0).args(args).status(), 37 | "builder", 38 | "Cannot start: {}", 39 | arg0 40 | ); 41 | 42 | Ok(status) 43 | } 44 | 45 | fn update_package() -> Result<()> { 46 | let r = run_command("git", &["pull", "-f"])?; 47 | 48 | if !r.success() { 49 | return Err(ZeusError::new( 50 | "builder".to_owned(), 51 | format!("git failed with: {}", r.code().unwrap_or(-1)), 52 | )); 53 | } 54 | 55 | Ok(()) 56 | } 57 | 58 | fn clone_package(cfg: &AppConfig, package_name: &str) -> Result<()> { 59 | let status = run_command( 60 | "git", 61 | &[ 62 | "clone", 63 | "--", 64 | &format!("{}/{}.git", cfg.aur.get_url(), &package_name), 65 | ], 66 | )?; 67 | 68 | if !status.success() { 69 | return Err(ZeusError::new( 70 | "builder".to_owned(), 71 | format!( 72 | "git failed with: {}", 73 | status.code().unwrap_or(-1) 74 | ), 75 | )); 76 | } 77 | 78 | Ok(()) 79 | } 80 | 81 | fn make_package(cfg: &AppConfig) -> Result { 82 | let args: Vec<&str> = 83 | cfg.build_args.iter().map(|x| x.as_str()).collect(); 84 | 85 | let status = run_command( 86 | "makepkg", 87 | &[ 88 | &["--needed", "--noconfirm", "--noprogressbar", "-s"], 89 | args.as_slice(), 90 | ] 91 | .concat(), 92 | )?; 93 | 94 | if !status.success() { 95 | if let Some(exit_code) = status.code() { 96 | // 13 means a package has already been built 97 | if exit_code == 13 { 98 | return Ok(false); 99 | } 100 | } 101 | 102 | return Err(ZeusError::new( 103 | "builder".to_owned(), 104 | format!( 105 | "makepkg failed with: {}", 106 | status.code().unwrap_or(-1) 107 | ), 108 | )); 109 | } 110 | 111 | Ok(true) 112 | } 113 | 114 | fn get_package_files() -> Result> { 115 | use std::process::Command; 116 | 117 | let output = 118 | Command::new("makepkg").arg("--packagelist").output()?; 119 | 120 | Ok(String::from_utf8_lossy(&output.stdout) 121 | .lines() 122 | .map(|x| x.to_owned()) 123 | .collect()) 124 | } 125 | 126 | fn build_package( 127 | cfg: &AppConfig, 128 | package_name: &str, 129 | ) -> Result { 130 | use std::path::Path; 131 | if !Path::new(package_name).exists() { 132 | clone_package(&cfg, package_name)?; 133 | } 134 | 135 | chdir(package_name)?; 136 | 137 | if cfg.upgrade { 138 | update_package()?; 139 | } 140 | 141 | make_package(&cfg) 142 | } 143 | 144 | fn build_packages( 145 | cfg: &AppConfig, 146 | build_root: &str, 147 | ) -> Result> { 148 | let mut packages: Vec = vec![]; 149 | for package in &cfg.packages { 150 | if let Some(pkg_name) = package.Name.as_ref() { 151 | info!("builder", "Building package: {}", pkg_name); 152 | 153 | chdir(build_root)?; 154 | 155 | let mut pkg = package.clone(); 156 | 157 | let pkg_built = match build_package(&cfg, pkg_name) { 158 | Err(e) => { 159 | warning!("builder", "{}", e); 160 | continue; 161 | }, 162 | Ok(v) => v, 163 | }; 164 | 165 | if cfg.install { 166 | pkg.package_files = Some(match get_package_files() { 167 | Ok(v) => v, 168 | Err(e) => { 169 | warning!( 170 | "builder", 171 | "Could not get package files: {}", 172 | e 173 | ); 174 | vec![] 175 | }, 176 | }) 177 | } 178 | 179 | if pkg_built { 180 | packages.push(pkg); 181 | } 182 | } 183 | } 184 | 185 | Ok(packages) 186 | } 187 | 188 | fn remove_packages( 189 | cfg: &AppConfig, 190 | build_root: &str, 191 | ) -> Result> { 192 | let mut removed_packages: Vec = vec![]; 193 | chdir(build_root)?; 194 | 195 | use std::fs; 196 | use std::path::Path; 197 | for package in &cfg.packages { 198 | if let Some(pkg_name) = package.Name.as_ref() { 199 | info!("zeus", "Removing package: {}", pkg_name); 200 | 201 | let pkg_path = Path::new(pkg_name); 202 | 203 | let pkg = package.clone(); 204 | 205 | if pkg_path.exists() && pkg_path.is_dir() { 206 | match fs::remove_dir_all(pkg_path) { 207 | Ok(_) => { 208 | removed_packages.push(pkg); 209 | }, 210 | Err(e) => { 211 | warning!( 212 | "fs", 213 | "Cannot remove package directory \"{}\": {}", 214 | pkg_path.display(), 215 | e 216 | ); 217 | }, 218 | } 219 | } else { 220 | warning!( 221 | "zeus", 222 | "Package {} has not been synced", 223 | pkg_name 224 | ); 225 | } 226 | } 227 | } 228 | 229 | Ok(removed_packages) 230 | } 231 | 232 | fn main() { 233 | info!("builder", "Version: {}", config::VERSION.bright_blue()); 234 | 235 | match chdir("/build") { 236 | Err(e) => { 237 | error!(&e.caller, "{}", e.message); 238 | exit(1); 239 | }, 240 | _ => {}, 241 | }; 242 | 243 | let (mut tx, mut rx) = match UnixStream::connect(".zeus.sock") { 244 | Ok(v) => channels::channel::(v), 245 | Err(e) => { 246 | error!( 247 | "builder", 248 | "Cannot connect to socket \".zeus.sock\": {}", e 249 | ); 250 | exit(1); 251 | }, 252 | }; 253 | 254 | let cfg: config::AppConfig = match rx.recv() { 255 | Ok(v) => match v { 256 | Message::Config(c) => c, 257 | _ => { 258 | error!("builder", "Expected config, got: {:?}", v); 259 | exit(1); 260 | }, 261 | }, 262 | Err(e) => { 263 | error!("builder", "Cannot receive config: {}", e); 264 | exit(1); 265 | }, 266 | }; 267 | 268 | unsafe { 269 | log::LOGGER.debug = cfg.debug; 270 | } 271 | 272 | let op_res = match cfg.operation { 273 | Operation::Sync => build_packages(&cfg, "/build"), 274 | Operation::Remove => remove_packages(&cfg, "/build"), 275 | _ => { 276 | error!( 277 | "builder", 278 | "Unexpected operation: {:?}", cfg.operation 279 | ); 280 | exit(1); 281 | }, 282 | }; 283 | 284 | match op_res { 285 | Ok(v) => tx.send(Message::Success(v)), 286 | Err(e) => tx.send(Message::Failure(e.message)), 287 | } 288 | .unwrap(); 289 | } 290 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use crate::config::{self, defaults}; 2 | 3 | use clap::{Arg, Command}; 4 | 5 | use std::io::Write; 6 | 7 | use clap_complete::generate; 8 | pub use clap_complete::Shell; 9 | 10 | use const_format::formatcp; 11 | 12 | pub fn build_subcommands() -> Vec> { 13 | vec![ 14 | //////////////////////////////////////////////////// 15 | Command::new("sync") 16 | .short_flag('S') 17 | .long_flag("sync") 18 | .about("Sync packages") 19 | .arg( 20 | Arg::new("upgrade") 21 | .short('u') 22 | .long("upgrade") 23 | .help("Upgrade packages") 24 | .takes_value(false), 25 | ) 26 | .arg( 27 | Arg::new("install") 28 | .long("install") 29 | .help("Install packages after build") 30 | .takes_value(false), 31 | ) 32 | .arg( 33 | Arg::new("buildargs") 34 | .long("buildargs") 35 | .help("Extra arguments for makepkg") 36 | .takes_value(true), 37 | ) 38 | .arg( 39 | Arg::new("name") 40 | .long("name") 41 | .help("Builder machine name") 42 | .default_value(defaults::BUILDER_NAME), 43 | ) 44 | .arg( 45 | Arg::new("packages") 46 | .help("Packages to sync") 47 | .multiple_occurrences(true), 48 | ), 49 | //////////////////////////////////////////////////// 50 | Command::new("remove") 51 | .short_flag('R') 52 | .long_flag("remove") 53 | .about("Remove packages") 54 | .arg( 55 | Arg::new("uninstall") 56 | .long("uninstall") 57 | .help("Uninstall packages after remove") 58 | .takes_value(false), 59 | ) 60 | .arg( 61 | Arg::new("name") 62 | .long("name") 63 | .help("Builder machine name") 64 | .default_value(defaults::BUILDER_NAME), 65 | ) 66 | .arg( 67 | Arg::new("packages") 68 | .help("Packages to remove") 69 | .multiple_occurrences(true), 70 | ), 71 | //////////////////////////////////////////////////// 72 | Command::new("build") 73 | .short_flag('B') 74 | .long_flag("build") 75 | .about("Build/Update builder image") 76 | .arg( 77 | Arg::new("image") 78 | .long("image") 79 | .help("Builder image name") 80 | .default_value(defaults::BUILDER_IMAGE), 81 | ) 82 | .arg( 83 | Arg::new("name") 84 | .long("name") 85 | .help("Builder machine name") 86 | .default_value(defaults::BUILDER_NAME), 87 | ), 88 | //////////////////////////////////////////////////// 89 | Command::new("query") 90 | .short_flag('Q') 91 | .long_flag("query") 92 | .about("Query the AUR") 93 | .arg( 94 | Arg::new("info") 95 | .short('i') 96 | .long("info") 97 | .help("Display additional information on results") 98 | .takes_value(false) 99 | .conflicts_with("by"), 100 | ) 101 | .arg( 102 | Arg::new("by") 103 | .long("by") 104 | .help("Query AUR packages by") 105 | .possible_values([ 106 | "name", 107 | "description", 108 | "maintainer", 109 | "depends", 110 | "makedepends", 111 | "optdepends", 112 | "checkdepends", 113 | ]) 114 | .default_value("description") 115 | .conflicts_with("info"), 116 | ) 117 | .arg( 118 | Arg::new("output") 119 | .long("output") 120 | .help("Output format") 121 | .possible_values(["pretty", "json"]) 122 | .default_value("pretty"), 123 | ) 124 | .arg( 125 | Arg::new("keywords") 126 | .help("Keywords to use") 127 | .multiple_occurrences(true), 128 | ), 129 | //////////////////////////////////////////////////// 130 | Command::new("completions") 131 | .long_flag("completions") 132 | .about("Generate shell completions & others") 133 | .arg( 134 | Arg::new("shell") 135 | .long("shell") 136 | .help("Specify shell to generate completions for") 137 | .takes_value(true), 138 | ), 139 | //////////////////////////////////////////////////// 140 | Command::new("runtime") 141 | .long_flag("runtime") 142 | .about("Various runtime operations") 143 | .arg( 144 | Arg::new("list") 145 | .short('l') 146 | .long("list") 147 | .help("List all available runtimes") 148 | .takes_value(false) 149 | .exclusive(true), 150 | ), 151 | //////////////////////////////////////////////////// 152 | ] 153 | } 154 | 155 | pub fn build() -> Command<'static> { 156 | Command::new(config::NAME) 157 | .version(config::VERSION) 158 | .about(config::DESCRIPTION) 159 | .long_version(formatcp!( 160 | r#"{} 161 | 162 | _oo Copyright lololol (C) 2022 {} 163 | >-(_ \ 164 | / _/ This program may be freely distributed under 165 | / / the terms of the GNU General Public License v3.0. 166 | / ( 167 | ( `-. {} 168 | `--.._) 169 | Defaults: 170 | DATA_DIR | {} 171 | BUILDER_NAME | {} 172 | BUILDER_IMAGE | {} 173 | BUILD_DIR | {} 174 | AUR_HOST | {} 175 | RUNTIME | {} 176 | RUNTIME_DIR | {} 177 | "#, 178 | config::VERSION, 179 | config::AUTHORS, 180 | config::HOMEPAGE, 181 | defaults::DATA_DIR, 182 | defaults::BUILDER_NAME, 183 | defaults::BUILDER_IMAGE, 184 | defaults::BUILD_DIR, 185 | defaults::AUR_HOST, 186 | defaults::RUNTIME, 187 | defaults::RUNTIME_DIR, 188 | )) 189 | .arg( 190 | Arg::new("color") 191 | .long("color") 192 | .help("Colorize the output") 193 | .value_parser( 194 | clap::builder::PossibleValuesParser::new([ 195 | "always", "auto", "never", 196 | ]), 197 | ) 198 | .default_value("auto"), 199 | ) 200 | .arg( 201 | Arg::new("debug") 202 | .short('d') 203 | .long("debug") 204 | .help("Show debug logs") 205 | .takes_value(false), 206 | ) 207 | .arg( 208 | Arg::new("force") 209 | .long("force") 210 | .help("Ignore all warnings") 211 | .takes_value(false), 212 | ) 213 | .arg( 214 | Arg::new("builddir") 215 | .long("builddir") 216 | .help("Package build directory") 217 | .default_value(defaults::BUILD_DIR), 218 | ) 219 | .arg( 220 | Arg::new("aur") 221 | .long("aur") 222 | .help("AUR host") 223 | .default_value(defaults::AUR_HOST), 224 | ) 225 | .arg( 226 | Arg::new("rt") 227 | .long("rt") 228 | .help("Specify runtime to use") 229 | .default_value(defaults::RUNTIME), 230 | ) 231 | .arg( 232 | Arg::new("rtdir") 233 | .long("rtdir") 234 | .help("Specify directory to search for runtimes") 235 | .default_value(defaults::RUNTIME_DIR), 236 | ) 237 | .subcommand_required(true) 238 | .subcommands(build_subcommands()) 239 | } 240 | 241 | pub fn make_completions(s: Shell, buf: &mut dyn Write) { 242 | generate(s, &mut build(), config::NAME, buf); 243 | } 244 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::aur::{Aur, Package}; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | use const_format::formatcp; 6 | 7 | macro_rules! from_env { 8 | ($varname:tt, $envvar:tt) => { 9 | #[allow(dead_code)] 10 | pub const $varname: &'static str = 11 | env!($envvar, concat!($envvar, " not set")); 12 | }; 13 | } 14 | 15 | #[cfg(debug_assertions)] 16 | const BUILD_TYPE: &'static str = "dbg"; 17 | 18 | #[cfg(not(debug_assertions))] 19 | const BUILD_TYPE: &'static str = "rls"; 20 | 21 | pub const VERSION: &'static str = 22 | formatcp!("{}-{BUILD_TYPE}", env!("VERSION", "VERSION not set")); 23 | 24 | from_env!(NAME, "CARGO_CRATE_NAME"); 25 | from_env!(DESCRIPTION, "CARGO_PKG_DESCRIPTION"); 26 | from_env!(HOMEPAGE, "CARGO_PKG_HOMEPAGE"); 27 | from_env!(REPOSITORY, "CARGO_PKG_REPOSITORY"); 28 | from_env!(LICENSE, "CARGO_PKG_LICENSE"); 29 | from_env!(AUTHORS, "CARGO_PKG_AUTHORS"); 30 | 31 | #[allow(dead_code)] 32 | pub mod defaults { 33 | from_env!(DATA_DIR, "DEFAULT_DATA_DIR"); 34 | from_env!(BUILDER_NAME, "DEFAULT_NAME"); 35 | from_env!(BUILDER_IMAGE, "DEFAULT_IMAGE"); 36 | from_env!(BUILD_DIR, "DEFAULT_BUILDDIR"); 37 | from_env!(AUR_HOST, "DEFAULT_AUR_HOST"); 38 | from_env!(RUNTIME, "DEFAULT_RUNTIME"); 39 | from_env!(RUNTIME_DIR, "DEFAULT_RUNTIME_DIR"); 40 | } 41 | 42 | // Operations that are handled inside the machine 43 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 44 | pub enum Operation { 45 | Sync, 46 | Remove, 47 | Build, 48 | Query, 49 | Completions, 50 | Runtime, 51 | None, 52 | } 53 | 54 | impl Default for Operation { 55 | fn default() -> Self { 56 | Self::None 57 | } 58 | } 59 | 60 | impl From<&str> for Operation { 61 | fn from(s: &str) -> Self { 62 | use Operation::*; 63 | match s { 64 | "sync" => Sync, 65 | "remove" => Remove, 66 | "build" => Build, 67 | "query" => Query, 68 | "runtime" => Runtime, 69 | "completions" => Completions, 70 | _ => Default::default(), 71 | } 72 | } 73 | } 74 | 75 | #[derive( 76 | Debug, Default, PartialEq, Clone, Serialize, Deserialize, 77 | )] 78 | pub struct AppConfig { 79 | pub operation: Operation, 80 | 81 | /// Should we display debug logs? 82 | pub debug: bool, 83 | 84 | pub force: bool, 85 | 86 | /// Instance to communicate with the AUR RPC interface 87 | pub aur: Aur, 88 | 89 | /// Build directory for packages 90 | pub build_dir: String, 91 | 92 | /// Name of the runtime to load 93 | pub runtime: String, 94 | 95 | /// Directory to search for runtimes 96 | pub runtime_dir: String, 97 | 98 | // Sync 99 | pub upgrade: bool, 100 | pub build_args: Vec, 101 | 102 | // Should we install the packages to the host? 103 | pub install: bool, 104 | 105 | // Should we uninstall the packages from the host? 106 | pub uninstall: bool, 107 | 108 | // Machine 109 | /// Machine name 110 | pub machine: String, 111 | 112 | /// Machine image name 113 | pub image: String, 114 | 115 | /// Packages for an operation 116 | pub packages: Vec, 117 | 118 | /// Keywords for the query operation 119 | pub keywords: Vec, 120 | } 121 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt::Display; 3 | use std::result; 4 | 5 | #[allow(dead_code)] 6 | pub type Result = result::Result; 7 | 8 | #[derive(Debug)] 9 | pub struct ZeusError { 10 | pub caller: String, 11 | pub message: String, 12 | } 13 | 14 | #[allow(dead_code)] 15 | impl ZeusError { 16 | pub fn new(caller: String, message: String) -> Self { 17 | Self { 18 | caller: caller.to_owned(), 19 | message: message.to_owned(), 20 | } 21 | } 22 | } 23 | 24 | impl Display for ZeusError { 25 | fn fmt( 26 | &self, 27 | f: &mut std::fmt::Formatter<'_>, 28 | ) -> std::fmt::Result { 29 | f.write_fmt(format_args!("{}", self.message)) 30 | } 31 | } 32 | 33 | impl Error for ZeusError {} 34 | 35 | impl From for ZeusError { 36 | fn from(e: std::io::Error) -> Self { 37 | return ZeusError { 38 | caller: "system".to_string(), 39 | message: e.to_string(), 40 | }; 41 | } 42 | } 43 | 44 | impl From for ZeusError { 45 | fn from(e: crate::machine::Error) -> Self { 46 | return ZeusError { 47 | caller: "RuntimeManager".to_string(), 48 | message: format!("Error: {}", e), 49 | }; 50 | } 51 | } 52 | 53 | #[macro_export] 54 | macro_rules! zerr { 55 | ($x:expr, $caller:expr, $($arg:tt)*) => { 56 | match $x { 57 | Ok(v) => v, 58 | Err(e) => { 59 | return Err(ZeusError::new( 60 | $caller.to_string(), 61 | format!("{}: {}", format!($($arg)*), e), 62 | )); 63 | }, 64 | } 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod aur; 2 | mod config; 3 | mod error; 4 | pub mod machine; 5 | -------------------------------------------------------------------------------- /src/lock.rs: -------------------------------------------------------------------------------- 1 | use fs4::FileExt; 2 | 3 | use std::fs::File; 4 | use std::io; 5 | use std::path::{Path, PathBuf}; 6 | 7 | #[derive(Debug)] 8 | pub struct Lockfile { 9 | file: File, 10 | path: PathBuf, 11 | } 12 | 13 | #[allow(dead_code)] 14 | impl Lockfile { 15 | pub fn new(path: &Path) -> io::Result { 16 | Ok(Self { 17 | file: if path.exists() { 18 | File::options().read(true).open(path)? 19 | } else { 20 | File::options().create(true).write(true).open(path)? 21 | }, 22 | path: path.to_path_buf(), 23 | }) 24 | } 25 | 26 | pub fn lock(&self) -> io::Result<()> { 27 | self.file.lock_exclusive() 28 | } 29 | 30 | pub fn try_lock(&self) -> io::Result<()> { 31 | self.file.try_lock_exclusive() 32 | } 33 | 34 | pub fn unlock(&self) -> io::Result<()> { 35 | self.file.unlock() 36 | } 37 | } 38 | 39 | impl Drop for Lockfile { 40 | fn drop(&mut self) { 41 | let _ = self.unlock(); 42 | let _ = std::fs::remove_file(&self.path); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/log.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use colored::{Color, Colorize}; 4 | 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Colors { 7 | pub error: Color, 8 | pub warn: Color, 9 | pub info: Color, 10 | pub debug: Color, 11 | } 12 | 13 | #[allow(dead_code)] 14 | impl Colors { 15 | pub fn new() -> Self { 16 | Self { ..Default::default() } 17 | } 18 | 19 | pub fn error(mut self, c: Color) -> Self { 20 | self.error = c; 21 | self 22 | } 23 | pub fn warn(mut self, c: Color) -> Self { 24 | self.warn = c; 25 | self 26 | } 27 | pub fn info(mut self, c: Color) -> Self { 28 | self.info = c; 29 | self 30 | } 31 | pub fn debug(mut self, c: Color) -> Self { 32 | self.debug = c; 33 | self 34 | } 35 | 36 | pub(self) const fn _default() -> Self { 37 | Self { 38 | error: Color::Red, 39 | warn: Color::Yellow, 40 | info: Color::Green, 41 | debug: Color::Blue, 42 | } 43 | } 44 | } 45 | 46 | impl Default for Colors { 47 | fn default() -> Self { 48 | Self::_default() 49 | } 50 | } 51 | 52 | #[derive(Debug, Default, Clone, Copy)] 53 | pub struct Logger { 54 | pub colors: Colors, 55 | pub debug: bool, 56 | } 57 | 58 | #[allow(dead_code)] 59 | impl Logger { 60 | fn log_impl( 61 | &self, 62 | level: &str, 63 | c: Color, 64 | caller: &str, 65 | data: &str, 66 | ) { 67 | eprintln!( 68 | "{}{} {}{} {}", 69 | "[".bright_black(), 70 | level.color(c).bold(), 71 | caller.bold(), 72 | "]".bright_black(), 73 | data 74 | ); 75 | } 76 | 77 | pub fn e(&self, caller: &str, message: T) 78 | where 79 | T: Display, 80 | { 81 | self.log_impl( 82 | "ERROR", 83 | self.colors.error, 84 | caller, 85 | &message.to_string(), 86 | ); 87 | } 88 | pub fn w(&self, caller: &str, message: T) 89 | where 90 | T: Display, 91 | { 92 | self.log_impl( 93 | "WARN", 94 | self.colors.warn, 95 | caller, 96 | &message.to_string(), 97 | ); 98 | } 99 | pub fn i(&self, caller: &str, message: T) 100 | where 101 | T: Display, 102 | { 103 | self.log_impl( 104 | "INFO", 105 | self.colors.info, 106 | caller, 107 | &message.to_string(), 108 | ); 109 | } 110 | pub fn d(&self, caller: &str, message: T) 111 | where 112 | T: Display, 113 | { 114 | if !self.debug { 115 | return; 116 | } 117 | 118 | self.log_impl( 119 | "DEBUG", 120 | self.colors.debug, 121 | caller, 122 | &message.to_string(), 123 | ); 124 | } 125 | } 126 | 127 | pub static mut LOGGER: Logger = 128 | Logger { debug: false, colors: Colors::_default() }; 129 | 130 | pub mod macros { 131 | #[macro_export] 132 | macro_rules! error { 133 | ($caller:expr, $($arg:tt)*) => ({ 134 | #[allow(unused_unsafe)] 135 | unsafe { 136 | $crate::log::LOGGER.e($caller, format!($($arg)*)) 137 | } 138 | }); 139 | } 140 | #[macro_export] 141 | macro_rules! warning { 142 | ($caller:expr, $($arg:tt)*) => ({ 143 | #[allow(unused_unsafe)] 144 | unsafe { 145 | $crate::log::LOGGER.w($caller, format!($($arg)*)) 146 | } 147 | }); 148 | } 149 | #[macro_export] 150 | macro_rules! info { 151 | ($caller:expr, $($arg:tt)*) => ({ 152 | #[allow(unused_unsafe)] 153 | unsafe { 154 | $crate::log::LOGGER.i($caller, format!($($arg)*)) 155 | } 156 | }); 157 | } 158 | #[macro_export] 159 | macro_rules! debug { 160 | ($caller:expr, $($arg:tt)*) => ({ 161 | #[allow(unused_unsafe)] 162 | unsafe { 163 | $crate::log::LOGGER.d($caller, format!($($arg)*)) 164 | } 165 | }); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/machine/manager.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::ffi::OsStr; 3 | 4 | use libloading::{Library, Symbol}; 5 | 6 | use super::{constants, BoxedRuntime, Runtime}; 7 | 8 | use crate::error::ZeusError; 9 | 10 | #[derive(Debug)] 11 | #[allow(dead_code)] 12 | pub enum Error { 13 | Unloadable(libloading::Error), 14 | SymbolLookup(libloading::Error), 15 | RuntimeNotLoaded, 16 | RuntimeAlreadyLoaded, 17 | RuntimeInitError(super::Error), 18 | IncompatibleRuntimeApi, 19 | } 20 | 21 | impl std::fmt::Display for Error { 22 | fn fmt( 23 | &self, 24 | f: &mut std::fmt::Formatter<'_>, 25 | ) -> std::fmt::Result { 26 | use Error::*; 27 | 28 | match self { 29 | Unloadable(e) => write!(f, "cannot load runtime: {}", e), 30 | SymbolLookup(e) => { 31 | write!(f, "cannot find runtime constructor: {}", e) 32 | }, 33 | RuntimeNotLoaded => write!(f, "runtime is not loaded"), 34 | RuntimeAlreadyLoaded => { 35 | write!(f, "runtime is already loaded") 36 | }, 37 | RuntimeInitError(e) => write!(f, "runtime error: {}", e), 38 | IncompatibleRuntimeApi => write!( 39 | f, 40 | "runtime is incompatible with current version" 41 | ), 42 | } 43 | } 44 | } 45 | 46 | impl std::error::Error for Error {} 47 | 48 | impl From for ZeusError { 49 | fn from(e: Error) -> Self { 50 | Self { 51 | caller: "RuntimeManager".to_string(), 52 | message: e.to_string(), 53 | } 54 | } 55 | } 56 | 57 | #[allow(dead_code)] 58 | pub struct RuntimeLibrary { 59 | pub runtime: BoxedRuntime, 60 | pub library: Library, 61 | } 62 | 63 | impl std::fmt::Debug for RuntimeLibrary { 64 | fn fmt( 65 | &self, 66 | f: &mut std::fmt::Formatter<'_>, 67 | ) -> std::fmt::Result { 68 | f.debug_struct("RuntimeLibrary") 69 | .field("name", &self.runtime.name()) 70 | .field("version", &self.runtime.version()) 71 | .finish() 72 | } 73 | } 74 | 75 | impl Drop for RuntimeLibrary { 76 | fn drop(&mut self) { 77 | self.runtime.exit(); 78 | } 79 | } 80 | 81 | #[derive(Debug, Default)] 82 | pub struct RuntimeManager { 83 | pub runtimes: HashMap<&'static str, RuntimeLibrary>, 84 | } 85 | 86 | #[allow(dead_code)] 87 | impl RuntimeManager { 88 | pub fn new() -> Self { 89 | Self::default() 90 | } 91 | 92 | pub(crate) unsafe fn _load_unchecked>( 93 | &mut self, 94 | path: P, 95 | ) -> Result { 96 | let library = match Library::new(path) { 97 | Ok(lib) => lib, 98 | Err(e) => return Err(Error::Unloadable(e)), 99 | }; 100 | 101 | let constructor: Symbol = 102 | match library.get( 103 | constants::RUNTIME_CONSTRUCTOR_SYMBOL_NAME.as_bytes(), 104 | ) { 105 | Ok(symbol) => symbol, 106 | Err(e) => return Err(Error::SymbolLookup(e)), 107 | }; 108 | 109 | let runtime = Box::from_raw(constructor()); 110 | 111 | if runtime.rt_api_version() 112 | != constants::SUPPORTED_RT_API_VERSION 113 | { 114 | return Err(Error::IncompatibleRuntimeApi); 115 | } 116 | 117 | Ok(RuntimeLibrary { library, runtime }) 118 | } 119 | 120 | pub fn load>( 121 | &mut self, 122 | path: P, 123 | ) -> Result<&mut BoxedRuntime, Error> { 124 | unsafe { 125 | let mut rtlib = self._load_unchecked(path)?; 126 | let runtime = &mut rtlib.runtime; 127 | 128 | let runtime_name = runtime.name(); 129 | 130 | if self.is_loaded(runtime_name) { 131 | return Err(Error::RuntimeAlreadyLoaded); 132 | } 133 | 134 | match runtime.init() { 135 | Ok(_) => {}, 136 | Err(e) => return Err(Error::RuntimeInitError(e)), 137 | }; 138 | 139 | self.runtimes.insert(runtime_name, rtlib); 140 | 141 | let runtime = &mut self 142 | .runtimes 143 | .get_mut(runtime_name) 144 | .unwrap() 145 | .runtime; 146 | 147 | Ok(runtime) 148 | } 149 | } 150 | 151 | pub fn unload( 152 | &mut self, 153 | runtime_name: &str, 154 | ) -> Result<(), Error> { 155 | if !self.is_loaded(runtime_name) { 156 | return Err(Error::RuntimeNotLoaded); 157 | } 158 | 159 | self.runtimes.remove(runtime_name).unwrap(); 160 | 161 | Ok(()) 162 | } 163 | 164 | pub fn unload_all(&mut self) { 165 | for _ in self.runtimes.drain() {} 166 | } 167 | 168 | pub fn is_loaded(&self, runtime_name: &str) -> bool { 169 | self.runtimes.contains_key(runtime_name) 170 | } 171 | 172 | pub fn get(&self, runtime_name: &str) -> Option<&Runtime> { 173 | self.runtimes.get(runtime_name).map(|x| x.runtime.as_ref()) 174 | } 175 | 176 | pub fn get_mut( 177 | &mut self, 178 | runtime_name: &str, 179 | ) -> Option<&mut Runtime> { 180 | self.runtimes 181 | .get_mut(runtime_name) 182 | .map(|x| x.runtime.as_mut()) 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/machine/mod.rs: -------------------------------------------------------------------------------- 1 | //! Each runtime runs in a shared environment with the rest of the program, 2 | //! this means that whatever process-global data is changed by the runtime 3 | //! should be restored back to their initial state. This for example includes 4 | //! the CWD. When the runtime's `init()` is ran, the CWD is set to the program's 5 | //! data directory where it can store any persistent internal data that is not 6 | //! handled by an external daemon. The runtime is only allowed to access resources 7 | //! outside that path the current user has access to. It can't just read `/etc/shadow`, 8 | //! unless of course `zeus` is running as root. This can be mitigated by modifying 9 | //! the Apparmor rules to allow or disallow access. This requires the runtime 10 | //! developers to work together with the maintainers and developers of `zeus` or 11 | //! issue a patch for the Apparmor profile that each user has to apply. 12 | 13 | pub use crate::config::AppConfig; 14 | pub use std::io::{Read, Write}; 15 | 16 | pub mod constants { 17 | use super::*; 18 | 19 | /// Increasing this number means there has been a breaking change in the API. 20 | /// Removing or changing method signatures is a breaking change. 21 | pub const SUPPORTED_RT_API_VERSION: u32 = 1; 22 | 23 | // These should never really be changed 24 | pub const RUNTIME_CONSTRUCTOR_SYMBOL_NAME: &'static str = 25 | "_runtime_create"; 26 | pub type RuntimeConstructorSymbol = unsafe fn() -> *mut Runtime; 27 | } 28 | 29 | pub(crate) mod manager; 30 | 31 | pub type Error = String; 32 | pub type Result = std::result::Result; 33 | 34 | /// A trait specifying a common interface for all machine runtime drivers. 35 | pub type Runtime = dyn IRuntime; 36 | pub type BoxedRuntime = Box; 37 | pub trait IRuntime { 38 | /// Runtime driver name 39 | fn name(&self) -> &'static str; 40 | /// Runtime driver version 41 | fn version(&self) -> &'static str; 42 | 43 | /// A simplistic way to signal breaking changes in the API for runtimes. 44 | /// 45 | /// If `runtime.rt_api_version()` != `constants::SUPPORTED_RT_API_VERSION`, 46 | /// then the runtime will be considered incompatible and not load. 47 | fn rt_api_version(&self) -> u32; 48 | 49 | /// This will be ran on driver load. 50 | /// 51 | /// Returning an Err variant here will exit the program immediately reporting the error to the user. 52 | fn init(&mut self) -> Result<()>; 53 | 54 | /// This will be ran on driver unload. 55 | fn exit(&mut self); 56 | 57 | /// List images returning a vector containing their names. 58 | fn list_images(&self) -> Result>; 59 | 60 | /// Create or update an image. 61 | fn make_image(&mut self, image_name: &str) -> Result<()>; 62 | 63 | /// Delete an image. 64 | /// 65 | /// If: 66 | /// - the image does NOT exist 67 | /// - there are machines using the image 68 | /// 69 | /// Then: 70 | /// 71 | /// An error should be returned. 72 | fn delete_image(&mut self, image_name: &str) -> Result<()>; 73 | 74 | /// List machines returning a vector containing their names. 75 | fn list_machines(&self) -> Result>; 76 | 77 | /// Create a machine and apply the necessary configuration. 78 | /// 79 | /// If: 80 | /// - the machine already exists 81 | /// 82 | /// Then: 83 | /// 84 | /// An error should be returned. 85 | fn create_machine( 86 | &mut self, 87 | machine_name: &str, 88 | image_name: &str, 89 | config: &AppConfig, 90 | ) -> Result<()>; 91 | 92 | /// Start a machine and attach it to the terminal. The runtime is responsible for having 93 | /// forwarded the communication socket to the machine. 94 | /// 95 | /// If: 96 | /// - the machine does NOT exist 97 | /// 98 | /// Then: 99 | /// 100 | /// An error should be returned. 101 | fn start_machine(&mut self, machine_name: &str) -> Result<()>; 102 | 103 | /// Stop a machine. 104 | /// 105 | /// If: 106 | /// - the machine does NOT exist 107 | /// 108 | /// Then: 109 | /// 110 | /// An error should be returned. 111 | fn stop_machine(&mut self, machine_name: &str) -> Result<()>; 112 | 113 | /// Delete a machine completely. 114 | /// 115 | /// If: 116 | /// - the machine does NOT exist 117 | /// 118 | /// Then: 119 | /// 120 | /// An error should be returned. 121 | fn delete_machine(&mut self, machine_name: &str) -> Result<()>; 122 | } 123 | 124 | #[macro_export] 125 | macro_rules! declare_runtime { 126 | ($plugin:ty, $constructor:path) => { 127 | #[no_mangle] 128 | pub extern "C" fn _runtime_create( 129 | ) -> *mut $crate::machine::Runtime { 130 | let constructor: fn() -> $plugin = $constructor; 131 | let boxed = Box::new(constructor()); 132 | Box::into_raw(boxed) 133 | } 134 | }; 135 | } 136 | -------------------------------------------------------------------------------- /src/message.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::aur::Package; 4 | use crate::config::AppConfig; 5 | 6 | #[derive(Debug, Serialize, Deserialize)] 7 | pub enum Message { 8 | Config(AppConfig), 9 | Success(Vec), 10 | Failure(String), 11 | } 12 | -------------------------------------------------------------------------------- /src/ops/build.rs: -------------------------------------------------------------------------------- 1 | use super::prelude::*; 2 | 3 | pub fn build( 4 | runtime: &mut Runtime, 5 | mut cfg: AppConfig, 6 | args: &ArgMatches, 7 | ) -> Result<()> { 8 | cfg.image = args.value_of("image").unwrap().to_owned(); 9 | cfg.machine = args.value_of("name").unwrap().to_owned(); 10 | 11 | for machine in runtime.list_machines()? { 12 | if machine == cfg.machine { 13 | debug!( 14 | "MachineManager", 15 | "Removing old machine {}", cfg.machine 16 | ); 17 | runtime.delete_machine(&machine)?; 18 | } 19 | } 20 | 21 | debug!("ImageManager", "Updating image {}", cfg.image); 22 | runtime.make_image(&cfg.image)?; 23 | 24 | debug!("MachineManager", "Creating new machine {}", cfg.machine); 25 | runtime.create_machine(&cfg.machine, &cfg.image, &cfg)?; 26 | 27 | Ok(()) 28 | } 29 | -------------------------------------------------------------------------------- /src/ops/completions.rs: -------------------------------------------------------------------------------- 1 | use std::io::stdout; 2 | 3 | use crate::cli; 4 | 5 | use super::prelude::*; 6 | 7 | pub fn completions(args: &ArgMatches) -> Result<()> { 8 | if args.is_present("shell") { 9 | cli::make_completions( 10 | args.value_of_t::("shell") 11 | .unwrap_or(cli::Shell::Bash), 12 | &mut stdout(), 13 | ); 14 | } 15 | 16 | Ok(()) 17 | } 18 | -------------------------------------------------------------------------------- /src/ops/mod.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::Path; 3 | use std::thread; 4 | 5 | use crate::config::Operation; 6 | use crate::lock::Lockfile; 7 | use crate::machine::manager::RuntimeManager; 8 | use crate::message::Message; 9 | use crate::unix::LocalListener; 10 | 11 | mod build; 12 | mod completions; 13 | mod query; 14 | mod remove; 15 | mod runtime; 16 | mod sync; 17 | 18 | mod prelude { 19 | pub use crate::config::AppConfig; 20 | 21 | pub use crate::aur::Package; 22 | 23 | // Error handling 24 | pub use crate::error::{Result, ZeusError}; 25 | pub use crate::zerr; 26 | 27 | pub use crate::term::Terminal; 28 | 29 | // Logging 30 | pub use crate::log::Logger; 31 | pub use crate::{debug, error, info, warning}; 32 | 33 | // Extras 34 | pub use crate::machine::Runtime; 35 | pub use clap::ArgMatches; 36 | pub use colored::Colorize; 37 | 38 | pub use super::start_builder; 39 | } 40 | 41 | use prelude::*; 42 | 43 | pub fn start_builder( 44 | runtime: &mut Runtime, 45 | cfg: &AppConfig, 46 | ) -> Result> { 47 | if !runtime.list_machines()?.iter().any(|x| x == &cfg.machine) { 48 | return Err(ZeusError::new( 49 | "zeus".to_owned(), 50 | "No builder machine found.".to_owned(), 51 | )); 52 | } 53 | 54 | use std::sync::mpsc; 55 | let (local_tx, local_rx) = mpsc::channel::<()>(); 56 | 57 | let cfg1 = cfg.clone(); 58 | let manager_thread = 59 | thread::spawn(move || -> Result> { 60 | let socket_path = 61 | format!("{}/.zeus.sock", &cfg1.build_dir); 62 | let listener = zerr!( 63 | LocalListener::new(Path::new(&socket_path), 0o666), 64 | "unix", 65 | "Cannot listen on socket {}", 66 | &socket_path 67 | ); 68 | 69 | // let the main thread continue and start the machine 70 | local_tx.send(()).unwrap(); 71 | 72 | let (mut tx, mut rx) = zerr!( 73 | listener.accept(), 74 | "unix", 75 | "Cannot open communication stream with builder" 76 | ); 77 | 78 | tx.send(Message::Config(cfg1))?; 79 | 80 | loop { 81 | use std::io::ErrorKind; 82 | match rx.recv() { 83 | Err(e) if e.kind() == ErrorKind::WouldBlock => { 84 | continue 85 | }, 86 | Err(e) => { 87 | return Err(ZeusError::new( 88 | "zeus".to_string(), 89 | format!( 90 | "Cannot receive message from builder: {}", 91 | e 92 | ), 93 | )) 94 | }, 95 | Ok(v) => match v { 96 | Message::Success(pkgs) => { 97 | return Ok(pkgs); 98 | }, 99 | Message::Failure(error) => { 100 | return Err(ZeusError::new( 101 | "builder".to_string(), 102 | error, 103 | )) 104 | }, 105 | _ => {}, 106 | }, 107 | }; 108 | } 109 | }); 110 | 111 | // block until the manager thread is ready 112 | match local_rx.recv() { 113 | // this is a RecvErr, which means the manager exited prematurely 114 | Err(_) => { 115 | return manager_thread.join().unwrap(); 116 | }, 117 | _ => {}, 118 | } 119 | 120 | info!("zeus", "Starting builder..."); 121 | runtime.start_machine(&cfg.machine)?; 122 | 123 | return manager_thread.join().unwrap(); 124 | } 125 | 126 | fn get_runtime<'a>( 127 | cfg: &AppConfig, 128 | rt_manager: &'a mut RuntimeManager, 129 | ) -> Result<&'a mut Runtime> { 130 | let runtime = rt_manager 131 | .load(format!( 132 | "{}/librt_{}.so", 133 | cfg.runtime_dir, cfg.runtime 134 | ))? 135 | .as_mut(); 136 | 137 | zerr!( 138 | env::set_current_dir(crate::config::defaults::DATA_DIR), 139 | "system", 140 | "Cannot change directory to {}:", 141 | crate::config::defaults::DATA_DIR 142 | ); 143 | 144 | Ok(runtime) 145 | } 146 | 147 | fn get_lock( 148 | lockfile: &mut Option, 149 | cfg: &AppConfig, 150 | ) -> Result<()> { 151 | if lockfile.is_none() { 152 | *lockfile = Some(zerr!( 153 | Lockfile::new(Path::new(&format!( 154 | "{}/.zeus.lock", 155 | &cfg.build_dir 156 | ))), 157 | "system", 158 | "Cannot create lock" 159 | )); 160 | } 161 | 162 | Ok(zerr!( 163 | lockfile.as_ref().unwrap().try_lock(), 164 | "system", 165 | "Cannot obtain lock" 166 | )) 167 | } 168 | 169 | pub fn run_operation( 170 | term: &mut Terminal, 171 | cfg: AppConfig, 172 | args: &ArgMatches, 173 | ) -> Result<()> { 174 | let mut lockfile: Option = None; 175 | 176 | let mut rt_manager = RuntimeManager::new(); 177 | 178 | debug!("pre-op config", "{:?}", cfg); 179 | 180 | match cfg.operation { 181 | Operation::Build => { 182 | get_lock(&mut lockfile, &cfg)?; 183 | build::build( 184 | get_runtime(&cfg, &mut rt_manager)?, 185 | cfg, 186 | args, 187 | ) 188 | }, 189 | Operation::Remove => { 190 | get_lock(&mut lockfile, &cfg)?; 191 | remove::remove( 192 | term, 193 | get_runtime(&cfg, &mut rt_manager)?, 194 | cfg, 195 | args, 196 | ) 197 | }, 198 | Operation::Sync => { 199 | get_lock(&mut lockfile, &cfg)?; 200 | sync::sync( 201 | term, 202 | get_runtime(&cfg, &mut rt_manager)?, 203 | cfg, 204 | args, 205 | ) 206 | }, 207 | Operation::Runtime => { 208 | get_lock(&mut lockfile, &cfg)?; 209 | runtime::runtime(term, &mut rt_manager, cfg, args) 210 | }, 211 | Operation::Query => query::query(term, cfg, args), 212 | Operation::Completions => completions::completions(args), 213 | Operation::None => Err(ZeusError::new( 214 | "zeus".to_owned(), 215 | "No such operation".to_owned(), 216 | )), 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/ops/query.rs: -------------------------------------------------------------------------------- 1 | use std::io::stdout; 2 | 3 | use super::prelude::*; 4 | use crate::aur; 5 | 6 | macro_rules! print_if_some { 7 | ($a:expr,$b:expr) => {{ 8 | match $b { 9 | None => {}, 10 | Some(v) => { 11 | println!("{0: <16}: {1}", $a, v); 12 | }, 13 | } 14 | }}; 15 | } 16 | 17 | macro_rules! print_vec_if_some { 18 | ($a:expr,$b:expr) => {{ 19 | match $b { 20 | None => {}, 21 | Some(v) => { 22 | println!("{0: <16}: {1}", $a, v.join(" ")); 23 | }, 24 | } 25 | }}; 26 | } 27 | 28 | fn print_pretty_package(package: &aur::Package) { 29 | print_if_some!("Name", &package.Name); 30 | print_if_some!("Version", &package.Version); 31 | print_if_some!("Description", &package.Description); 32 | print_if_some!("URL", &package.URL); 33 | 34 | print_vec_if_some!("License", &package.License); 35 | print_vec_if_some!("Groups", &package.Groups); 36 | print_vec_if_some!("Provides", &package.Provides); 37 | print_vec_if_some!("Depends On", &package.Depends); 38 | print_vec_if_some!("Optional Deps", &package.OptDepends); 39 | print_vec_if_some!("Conflicts", &package.Conflicts); 40 | print_vec_if_some!("Replaces", &package.Replaces); 41 | 42 | println!( 43 | "{0: <16}: {1}", 44 | "Maintainer", 45 | &package.Maintainer.as_ref().unwrap_or(&"none".to_owned()) 46 | ); 47 | 48 | print_if_some!("Last Modified", &package.LastModified); 49 | print_if_some!("First Submitted", &package.FirstSubmitted); 50 | 51 | println!( 52 | "{0: <16}: {1}", 53 | "Out of date", 54 | &package.OutOfDate.unwrap_or(0) 55 | ); 56 | 57 | print_if_some!("Popularity", &package.Popularity); 58 | print_if_some!("Votes", &package.NumVotes); 59 | } 60 | 61 | pub fn query( 62 | _term: &mut Terminal, 63 | mut cfg: AppConfig, 64 | args: &ArgMatches, 65 | ) -> Result<()> { 66 | cfg.keywords = args 67 | .values_of("keywords") 68 | .unwrap_or_default() 69 | .map(|x| x.to_owned()) 70 | .collect(); 71 | 72 | if cfg.keywords.is_empty() { 73 | return Err(ZeusError::new( 74 | "zeus".to_owned(), 75 | "No keywords specified".to_owned(), 76 | )); 77 | } 78 | 79 | let by = args.value_of_t::("by").unwrap(); 80 | 81 | let res = match args.is_present("info") { 82 | true => cfg.aur.info(&cfg.keywords), 83 | false => cfg.aur.search(by, &cfg.keywords), 84 | }; 85 | 86 | let data = zerr!(res, "aur", "Error: "); 87 | 88 | match args.value_of("output").unwrap() { 89 | "json" => zerr!( 90 | serde_json::to_writer(stdout(), &data.results), 91 | "zeus", 92 | "Cannot serialize JSON: " 93 | ), 94 | _ => { 95 | if args.is_present("info") { 96 | for package in &data.results { 97 | print_pretty_package(package); 98 | } 99 | } else { 100 | for package in &data.results { 101 | println!( 102 | "{} {} - {}\n {}", 103 | "=>".green(), 104 | package 105 | .Name 106 | .as_ref() 107 | .unwrap_or(&"".to_owned()) 108 | .bold(), 109 | package 110 | .Version 111 | .as_ref() 112 | .unwrap_or(&"".to_owned()) 113 | .bright_blue(), 114 | package 115 | .Description 116 | .as_ref() 117 | .unwrap_or(&"".to_owned()), 118 | ); 119 | } 120 | } 121 | }, 122 | } 123 | 124 | Ok(()) 125 | } 126 | -------------------------------------------------------------------------------- /src/ops/remove.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | use super::prelude::*; 4 | 5 | pub fn remove( 6 | term: &mut Terminal, 7 | runtime: &mut Runtime, 8 | mut cfg: AppConfig, 9 | args: &ArgMatches, 10 | ) -> Result<()> { 11 | cfg.uninstall = args.is_present("uninstall"); 12 | 13 | cfg.machine = args.value_of("name").unwrap().to_owned(); 14 | 15 | cfg.packages = args 16 | .values_of("packages") 17 | .unwrap_or_default() 18 | .map(|x| Package { 19 | Name: Some(x.to_owned()), 20 | ..Default::default() 21 | }) 22 | .filter(|x| { 23 | let pkg_path = Path::new(&cfg.build_dir) 24 | .join(x.Name.as_ref().unwrap()); 25 | 26 | if pkg_path.exists() 27 | && pkg_path.is_dir() 28 | && pkg_path.join("PKGBUILD").exists() 29 | { 30 | true 31 | } else { 32 | warning!( 33 | "zeus", 34 | "Package {} was not found", 35 | x.Name.as_ref().unwrap() 36 | ); 37 | false 38 | } 39 | }) 40 | .collect(); 41 | 42 | if cfg.packages.is_empty() { 43 | return Err(ZeusError::new( 44 | "zeus".to_owned(), 45 | "No packages found.".to_owned(), 46 | )); 47 | } 48 | 49 | term.list( 50 | format!( 51 | "The following packages will be {}:", 52 | "REMOVED".bold() 53 | ), 54 | cfg.packages.iter().filter_map(|x| x.Name.as_ref()), 55 | 4, 56 | )?; 57 | 58 | if !term.yes_no_question( 59 | "Are you sure you want to remove these packages?", 60 | true, 61 | )? { 62 | error!("zeus", "Aborting..."); 63 | return Ok(()); 64 | } 65 | 66 | let removed_packages = start_builder(runtime, &cfg)?; 67 | 68 | if cfg.uninstall { 69 | use std::process::Command; 70 | 71 | let mut packages = vec![]; 72 | 73 | for p in &removed_packages { 74 | if let Some(pkg) = &p.Name { 75 | packages.push(pkg); 76 | } 77 | } 78 | 79 | zerr!( 80 | Command::new("sudo") 81 | .args(["pacman", "-R", "-c", "-s", "-n"]) 82 | .args(packages) 83 | .status(), 84 | "zeus", 85 | "Failed to execute pacman" 86 | ); 87 | } else { 88 | term.list( 89 | "Removed packages:", 90 | removed_packages.iter().filter_map(|x| x.Name.as_ref()), 91 | 1, 92 | )?; 93 | } 94 | 95 | Ok(()) 96 | } 97 | -------------------------------------------------------------------------------- /src/ops/runtime.rs: -------------------------------------------------------------------------------- 1 | use super::prelude::*; 2 | 3 | use crate::machine::manager::RuntimeManager; 4 | 5 | use std::fs::read_dir; 6 | 7 | pub fn runtime( 8 | term: &mut Terminal, 9 | rt_manager: &mut RuntimeManager, 10 | cfg: AppConfig, 11 | args: &ArgMatches, 12 | ) -> Result<()> { 13 | if args.is_present("list") { 14 | let runtime_dir = read_dir(&cfg.runtime_dir)?; 15 | 16 | let mut working_runtimes: Vec = Vec::new(); 17 | 18 | for entry in runtime_dir { 19 | let entry = match entry { 20 | Ok(v) => v, 21 | Err(_) => continue, 22 | }; 23 | 24 | let entry_name_os = entry.file_name(); 25 | 26 | let entry_name = match entry_name_os.to_str() { 27 | Some(v) => v, 28 | None => continue, 29 | }; 30 | 31 | if !entry_name.starts_with("librt_") 32 | || !entry_name.ends_with(".so") 33 | { 34 | continue; 35 | } 36 | 37 | if !entry.path().is_file() { 38 | continue; 39 | } 40 | 41 | debug!( 42 | "RuntimeManager", 43 | "Test-loading runtime {}", entry_name 44 | ); 45 | unsafe { 46 | let rtlib = 47 | match rt_manager._load_unchecked(entry.path()) { 48 | Ok(v) => v, 49 | Err(e) => { 50 | warning!( 51 | "RuntimeManager", 52 | "Runtime {} cannot be loaded: {}", 53 | entry_name, 54 | e 55 | ); 56 | continue; 57 | }, 58 | }; 59 | 60 | working_runtimes.push(format!( 61 | "{} - {} v{} (RT_API v{})", 62 | entry_name, 63 | rtlib.runtime.name().bold(), 64 | rtlib.runtime.version().yellow(), 65 | rtlib.runtime.rt_api_version() 66 | )); 67 | } 68 | } 69 | 70 | term.list( 71 | format!( 72 | "{} working {} found:", 73 | working_runtimes.len(), 74 | if working_runtimes.len() == 1 { 75 | "runtime" 76 | } else { 77 | "runtimes" 78 | } 79 | ), 80 | working_runtimes.iter(), 81 | 1, 82 | )?; 83 | } 84 | 85 | Ok(()) 86 | } 87 | -------------------------------------------------------------------------------- /src/ops/sync.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | use super::prelude::*; 4 | use super::start_builder; 5 | 6 | pub fn sync( 7 | term: &mut Terminal, 8 | runtime: &mut Runtime, 9 | mut cfg: AppConfig, 10 | args: &ArgMatches, 11 | ) -> Result<()> { 12 | cfg.upgrade = args.is_present("upgrade"); 13 | cfg.install = args.is_present("install"); 14 | 15 | cfg.build_args = args 16 | .value_of("buildargs") 17 | .unwrap_or_default() 18 | .split_ascii_whitespace() 19 | .map(|x| x.to_owned()) 20 | .collect(); 21 | 22 | cfg.machine = args.value_of("name").unwrap().to_owned(); 23 | 24 | cfg.packages = args 25 | .values_of("packages") 26 | .unwrap_or_default() 27 | .map(|x| Package { 28 | Name: Some(x.to_owned()), 29 | ..Default::default() 30 | }) 31 | .collect(); 32 | 33 | if cfg.packages.is_empty() && cfg.upgrade { 34 | // CHANGELOG: Simplify code 35 | 36 | let dir = zerr!( 37 | fs::read_dir(&cfg.build_dir), 38 | "fs", 39 | "Cannot list {}", 40 | &cfg.build_dir 41 | ); 42 | 43 | for entry in dir { 44 | let entry = match entry { 45 | Err(e) => { 46 | warning!( 47 | "fs", 48 | "Cannot read package directory: {}", 49 | e 50 | ); 51 | continue; 52 | }, 53 | Ok(v) => v, 54 | }; 55 | 56 | if entry.path().is_dir() { 57 | match entry.file_name().into_string() { 58 | Ok(v) => cfg.packages.push(Package { 59 | Name: Some(v), 60 | ..Default::default() 61 | }), 62 | Err(e) => { 63 | warning!( 64 | "fs", 65 | "Found invalid package directory: {}", 66 | e.to_string_lossy() 67 | ); 68 | continue; 69 | }, 70 | }; 71 | } 72 | } 73 | 74 | // CHANGELOG: dont ask what to upgrade 75 | } 76 | 77 | if cfg.packages.is_empty() { 78 | return Err(ZeusError::new( 79 | "zeus".to_owned(), 80 | "No packages found.".to_owned(), 81 | )); 82 | } 83 | 84 | // CHANGELOG: remove invalid packages 85 | 86 | cfg.packages = zerr!( 87 | cfg.aur.info( 88 | &cfg.packages 89 | .iter() 90 | .filter_map(|x| x.Name.as_ref()) 91 | .collect() 92 | ), 93 | "AUR", 94 | "Cannot request info for packages" 95 | ) 96 | .results; 97 | 98 | if cfg.packages.is_empty() { 99 | return Err(ZeusError::new( 100 | "zeus".to_owned(), 101 | "No valid packages found.".to_owned(), 102 | )); 103 | } 104 | 105 | term.list( 106 | format!( 107 | "The following packages will be {}:", 108 | match cfg.upgrade { 109 | true => "UPGRADED", 110 | false => "SYNCED", 111 | } 112 | .bold() 113 | ), 114 | cfg.packages.iter().filter_map(|x| x.Name.as_ref()), 115 | 4, 116 | )?; 117 | 118 | if !term.yes_no_question( 119 | "Are you sure you want to sync these packages?", 120 | true, 121 | )? { 122 | error!("zeus", "Aborting..."); 123 | return Ok(()); 124 | } 125 | 126 | let mut synced_packages = start_builder(runtime, &cfg)?; 127 | 128 | if cfg.install { 129 | use std::process::Command; 130 | 131 | let mut package_files: Vec = vec![]; 132 | 133 | for p in &mut synced_packages { 134 | if let Some(pkg_files) = &mut p.package_files { 135 | package_files.append( 136 | &mut pkg_files 137 | .iter() 138 | .filter_map(|x| { 139 | if let Some(s) = x.strip_prefix("/build") 140 | { 141 | Some(format!( 142 | "{}/{}", 143 | &cfg.build_dir, s 144 | )) 145 | } else { 146 | None 147 | } 148 | }) 149 | .collect(), 150 | ); 151 | } 152 | } 153 | 154 | if package_files.is_empty() { 155 | info!("zeus", "Nothing to install"); 156 | return Ok(()); 157 | } 158 | 159 | zerr!( 160 | Command::new("sudo") 161 | .args(["pacman", "-U"]) 162 | .args(package_files) 163 | .status(), 164 | "zeus", 165 | "Failed to execute pacman" 166 | ); 167 | } else { 168 | term.list( 169 | "Synced packages:", 170 | synced_packages.iter().filter_map(|x| x.Name.as_ref()), 171 | 1, 172 | )?; 173 | } 174 | 175 | Ok(()) 176 | } 177 | -------------------------------------------------------------------------------- /src/term.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt::Display; 3 | use std::io; 4 | use std::io::prelude::*; 5 | 6 | pub use colored::{control, Color, ColoredString, Colorize}; 7 | 8 | #[derive(Debug)] 9 | pub struct Terminal { 10 | pub input: io::Stdin, 11 | pub output: io::Stdout, 12 | pub error: io::Stderr, 13 | } 14 | 15 | #[allow(dead_code)] 16 | impl Terminal { 17 | pub fn new() -> Self { 18 | Self::default() 19 | } 20 | 21 | pub fn color(&mut self, enabled: bool) { 22 | control::set_override(enabled) 23 | } 24 | 25 | pub fn reset_color(&mut self) { 26 | control::unset_override() 27 | } 28 | 29 | pub fn prompt(&mut self, message: T) -> io::Result 30 | where 31 | T: Display, 32 | { 33 | write!( 34 | self.output, 35 | "{} {}\n{0} ", 36 | "=>".green().bold(), 37 | message 38 | )?; 39 | self.output.flush()?; 40 | 41 | let mut input = String::with_capacity(16); 42 | self.input.read_line(&mut input)?; 43 | 44 | Ok(input) 45 | } 46 | 47 | pub fn yes_no_question( 48 | &mut self, 49 | question: T, 50 | default: bool, 51 | ) -> io::Result 52 | where 53 | T: Display, 54 | { 55 | write!( 56 | self.output, 57 | "{} {} [{}] ", 58 | "=>".green().bold(), 59 | question, 60 | match default { 61 | true => "Y/n", 62 | false => "y/N", 63 | } 64 | .bold(), 65 | )?; 66 | self.output.flush()?; 67 | 68 | let mut answer: [u8; 1] = [0; 1]; 69 | self.input.read(&mut answer)?; 70 | 71 | match answer[0] as char { 72 | 'y' | 'Y' => Ok(true), 73 | 'n' | 'N' => Ok(false), 74 | '\n' => Ok(default), 75 | _ => Ok(false), 76 | } 77 | } 78 | 79 | pub fn question<'a, T, A>( 80 | &mut self, 81 | message: T, 82 | answers: Vec<&'a A>, 83 | default: &'a A, 84 | answers_per_line: usize, 85 | ) -> io::Result>> 86 | where 87 | T: Display, 88 | A: Display + ?Sized, 89 | { 90 | writeln!( 91 | self.output, 92 | "{} {} [{}]", 93 | "=>".green().bold(), 94 | message, 95 | default.to_string().bold() 96 | )?; 97 | 98 | let mut numbered_answers: HashMap = HashMap::new(); 99 | for (index, answer) in answers.iter().enumerate() { 100 | numbered_answers.insert(index, answer); 101 | write!( 102 | self.output, 103 | " {}) {}{}", 104 | index.to_string().yellow(), 105 | answer, 106 | if index % answers_per_line == answers_per_line - 1 { 107 | "\n" 108 | } else { 109 | "" 110 | } 111 | )?; 112 | } 113 | write!(self.output, "\n{} ", "=>".green().bold())?; 114 | self.output.flush()?; 115 | 116 | let mut input = String::with_capacity(16); 117 | self.input.read_line(&mut input)?; 118 | 119 | let mut ret: Vec<&A> = Vec::new(); 120 | 121 | if input.trim().is_empty() { 122 | return Ok(None); 123 | } 124 | 125 | for answer_number_str in input.trim().split_ascii_whitespace() 126 | { 127 | let answer_number: usize = match answer_number_str.parse() 128 | { 129 | Ok(v) => v, 130 | Err(_) => continue, 131 | }; 132 | 133 | if let Some(answer) = numbered_answers.get(&answer_number) 134 | { 135 | ret.push(answer) 136 | } 137 | } 138 | 139 | Ok(Some(ret)) 140 | } 141 | 142 | pub fn list( 143 | &mut self, 144 | header: H, 145 | items: I, 146 | items_per_line: usize, 147 | ) -> io::Result<()> 148 | where 149 | H: Display, 150 | T: Display, 151 | I: Iterator, 152 | { 153 | writeln!(self.output, "{} {}", "=>".green().bold(), header)?; 154 | 155 | for (index, item) in items.enumerate() { 156 | write!( 157 | self.output, 158 | " {}{}", 159 | item, 160 | if index % items_per_line == items_per_line - 1 { 161 | "\n" 162 | } else { 163 | "" 164 | } 165 | )?; 166 | } 167 | writeln!(self.output, "")?; 168 | 169 | Ok(()) 170 | } 171 | } 172 | 173 | impl Default for Terminal { 174 | fn default() -> Self { 175 | Self { 176 | input: io::stdin(), 177 | output: io::stdout(), 178 | error: io::stderr(), 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/unix.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io; 3 | use std::path::{Path, PathBuf}; 4 | 5 | use std::os::unix::fs::PermissionsExt; 6 | use std::os::unix::net::{UnixListener, UnixStream}; 7 | 8 | use serde::de::DeserializeOwned; 9 | use serde::ser::Serialize; 10 | 11 | use channels::{Receiver, Sender}; 12 | 13 | pub struct LocalListener { 14 | listener: UnixListener, 15 | path: PathBuf, 16 | } 17 | 18 | #[allow(dead_code)] 19 | impl LocalListener { 20 | pub fn new>( 21 | path: P, 22 | mode: u32, 23 | ) -> io::Result { 24 | let _ = fs::remove_file(&path); 25 | 26 | let listener = UnixListener::bind(&path)?; 27 | 28 | fs::set_permissions(&path, fs::Permissions::from_mode(mode))?; 29 | 30 | Ok(Self { path: path.as_ref().to_path_buf(), listener }) 31 | } 32 | 33 | pub fn accept( 34 | &self, 35 | ) -> io::Result<(Sender, Receiver)> 36 | { 37 | let (stream, _) = self.listener.accept()?; 38 | 39 | Ok(channels::channel::(stream)) 40 | } 41 | } 42 | 43 | impl std::ops::Deref for LocalListener { 44 | type Target = UnixListener; 45 | 46 | fn deref(&self) -> &Self::Target { 47 | &self.listener 48 | } 49 | } 50 | 51 | impl std::ops::DerefMut for LocalListener { 52 | fn deref_mut(&mut self) -> &mut Self::Target { 53 | &mut self.listener 54 | } 55 | } 56 | 57 | impl Drop for LocalListener { 58 | fn drop(&mut self) { 59 | let _ = fs::remove_file(self.path.as_path()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/zeus.rs: -------------------------------------------------------------------------------- 1 | mod cli; 2 | mod lock; 3 | mod message; 4 | mod ops; 5 | mod term; 6 | mod unix; 7 | 8 | pub mod aur; 9 | pub mod config; 10 | pub mod error; 11 | pub mod log; 12 | 13 | pub mod machine; 14 | 15 | use std::process::exit; 16 | 17 | fn main() { 18 | let args = cli::build().get_matches(); 19 | 20 | let mut term = term::Terminal::new(); 21 | 22 | unsafe { 23 | log::LOGGER.debug = args.is_present("debug"); 24 | } 25 | 26 | match args.value_of("color") { 27 | Some("always") => { 28 | term.color(true); 29 | }, 30 | Some("never") => { 31 | term.color(false); 32 | }, 33 | _ => {}, 34 | } 35 | 36 | let (command_name, command_args) = args.subcommand().unwrap(); 37 | 38 | let mut cfg = config::AppConfig { 39 | operation: config::Operation::from(command_name), 40 | 41 | debug: args.is_present("debug"), 42 | force: args.is_present("force"), 43 | 44 | // this should never fail, we set the default value in cli.rs 45 | build_dir: args.value_of("builddir").unwrap().to_owned(), 46 | 47 | aur: aur::Aur::new() 48 | .host(args.value_of("aur").unwrap().to_owned()) 49 | .build(), 50 | 51 | runtime: args.value_of("rt").unwrap().to_owned(), 52 | runtime_dir: args.value_of("rtdir").unwrap().to_owned(), 53 | 54 | // initialization of the rest will be in the code that handles the subcommands 55 | ..Default::default() 56 | }; 57 | 58 | if cfg.force { 59 | cfg.build_args.push("-f".to_owned()); 60 | } 61 | 62 | let res = ops::run_operation(&mut term, cfg, command_args); 63 | 64 | match res { 65 | Ok(_) => exit(0), 66 | Err(e) => { 67 | error!(&e.caller, "{}", e.message); 68 | exit(1); 69 | }, 70 | } 71 | } 72 | --------------------------------------------------------------------------------