Compare commits
21 Commits
v1.0.2
...
b541865ff1
| Author | SHA1 | Date | |
|---|---|---|---|
| b541865ff1 | |||
| 03bc56007f | |||
| c5ecb78fd4 | |||
| 3c4bfca546 | |||
| 9c8fccbb4c | |||
| 29cbfbac66 | |||
| 4a2e959535 | |||
| 94d6f5d54d | |||
| f30432c1db | |||
| 1b34dee81e | |||
| 46abec1237 | |||
| 49eaf6dbfc | |||
| 02009762c1 | |||
| e52ad0bc24 | |||
| 218a6306d4 | |||
| a0c1a4e006 | |||
| 1dcd456cb2 | |||
| 2f7cc9c150 | |||
| c13d6e54ee | |||
| 7000ecb3bf | |||
| 1d3b12bf2f |
412
Cargo.lock
generated
412
Cargo.lock
generated
@@ -38,7 +38,7 @@ version = "1.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -49,9 +49,53 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"once_cell_polyfill",
|
"once_cell_polyfill",
|
||||||
"windows-sys",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.6.0"
|
version = "4.6.0"
|
||||||
@@ -74,6 +118,25 @@ dependencies = [
|
|||||||
"strsim",
|
"strsim",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete"
|
||||||
|
version = "4.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19c9f1dde76b736e3681f28cec9d5a61299cbaae0fce80a68e43724ad56031eb"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete_nushell"
|
||||||
|
version = "4.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbb9e9715d29a754b468591be588f6b926f5b0a1eb6a8b62acabeb66ff84d897"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.6.0"
|
version = "4.6.0"
|
||||||
@@ -104,7 +167,36 @@ version = "3.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -113,6 +205,25 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fsevent-sys"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@@ -131,6 +242,12 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.13.0"
|
version = "2.13.0"
|
||||||
@@ -141,12 +258,115 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inotify"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.0",
|
||||||
|
"inotify-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inotify-sys"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.2"
|
version = "1.70.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kqueue"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
|
||||||
|
dependencies = [
|
||||||
|
"kqueue-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kqueue-sys"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.183"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "notify"
|
||||||
|
version = "8.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.0",
|
||||||
|
"fsevent-sys",
|
||||||
|
"inotify",
|
||||||
|
"kqueue",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"mio",
|
||||||
|
"notify-types",
|
||||||
|
"walkdir",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "notify-types"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell_polyfill"
|
name = "once_cell_polyfill"
|
||||||
version = "1.70.2"
|
version = "1.70.2"
|
||||||
@@ -155,15 +375,26 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet"
|
name = "pallet"
|
||||||
version = "1.0.2"
|
version = "1.0.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
|
"clap_complete_nushell",
|
||||||
"colored",
|
"colored",
|
||||||
"glob",
|
"glob",
|
||||||
|
"notify",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sha256",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.106"
|
version = "1.0.106"
|
||||||
@@ -182,6 +413,15 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "same-file"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.228"
|
||||||
@@ -212,6 +452,19 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
"zmij",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@@ -221,6 +474,30 @@ dependencies = [
|
|||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha256"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"hex",
|
||||||
|
"sha2",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -238,6 +515,16 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.50.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "1.0.7+spec-1.1.0"
|
version = "1.0.7+spec-1.1.0"
|
||||||
@@ -277,6 +564,12 @@ version = "1.0.7+spec-1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d"
|
checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
@@ -289,12 +582,52 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "walkdir"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
|
dependencies = [
|
||||||
|
"same-file",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.1+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-link"
|
name = "windows-link"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.60.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.61.2"
|
version = "0.61.2"
|
||||||
@@ -304,8 +637,79 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.53.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
|
checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zmij"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pallet"
|
name = "pallet"
|
||||||
version = "1.0.2"
|
version = "1.0.6"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
description = "A project manager and build system for C inspired by Rust's Cargo"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.6.0", features = ["derive"] }
|
clap = { version = "4.6.0", features = ["derive"] }
|
||||||
|
clap_complete = "4.6.0"
|
||||||
|
clap_complete_nushell = "4.6.0"
|
||||||
colored = "3.1.1"
|
colored = "3.1.1"
|
||||||
glob = "0.3.3"
|
glob = "0.3.3"
|
||||||
|
notify = "8.2.0"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
serde_json = "1.0.149"
|
||||||
|
sha256 = "1.6.0"
|
||||||
toml = "1.0.7"
|
toml = "1.0.7"
|
||||||
|
|||||||
19
PKGBUILD
Normal file
19
PKGBUILD
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Maintainer: Shea Frembling <sfrembling@gmail.com>
|
||||||
|
pkgname=pallet
|
||||||
|
pkgver=1.0.6
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="A simple C project manager inspired by Cargo"
|
||||||
|
arch=('x86_64')
|
||||||
|
url=""
|
||||||
|
license=('MIT')
|
||||||
|
depends=('gcc' 'pkgconf')
|
||||||
|
makedepends=('rust' 'cargo')
|
||||||
|
source=()
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cargo build --release
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
install -Dm755 "$startdir/target/release/pallet" "$pkgdir/usr/bin/pallet"
|
||||||
|
}
|
||||||
26
README.md
26
README.md
@@ -4,6 +4,32 @@ Pallet is a project manager and build system for C inspired by Rust's Cargo.
|
|||||||
|
|
||||||
This is a toy project not meant to be taken very seriously.
|
This is a toy project not meant to be taken very seriously.
|
||||||
|
|
||||||
|
## Requirements for Use
|
||||||
|
|
||||||
|
[GCC](https://en.wikipedia.org/wiki/GNU_Compiler_Collection) is recommended as the compiler installed for `Pallet` projects.
|
||||||
|
|
||||||
|
You can define a different `gcc` compatible compiler instead per-project by editing `Pallet.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
name = "my-app"
|
||||||
|
default_build = "debug"
|
||||||
|
compiler = "clang"
|
||||||
|
|
||||||
|
[[build]]
|
||||||
|
name = "debug"
|
||||||
|
args = [
|
||||||
|
"-g",
|
||||||
|
"-O0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[build]]
|
||||||
|
name = "release"
|
||||||
|
args = [
|
||||||
|
"-DNDEBUG",
|
||||||
|
"-O3",
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
- `pallet new <project>`: initializes a new project at `project`
|
- `pallet new <project>`: initializes a new project at `project`
|
||||||
|
|||||||
561
src/app.rs
561
src/app.rs
@@ -4,14 +4,15 @@ use std::{
|
|||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use clap::CommandFactory;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use glob::glob;
|
use glob::glob;
|
||||||
|
|
||||||
const MAIN_C: &str = include_str!("templates/main.c");
|
const MAIN_C: &str = include_str!("templates/main.c");
|
||||||
const GITIGNORE: &str = "target/";
|
const GITIGNORE: &str = "target/\ncompile_commands.json\n";
|
||||||
|
|
||||||
#[derive(clap::Parser)]
|
#[derive(clap::Parser)]
|
||||||
#[clap(version)]
|
#[clap(version, about)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Subcommand,
|
command: Subcommand,
|
||||||
@@ -28,6 +29,9 @@ enum Subcommand {
|
|||||||
Init,
|
Init,
|
||||||
/// Run the local project
|
/// Run the local project
|
||||||
Run {
|
Run {
|
||||||
|
/// Force recompilation of the project
|
||||||
|
#[arg(long, short)]
|
||||||
|
force_recompile: bool,
|
||||||
/// The build mode to use
|
/// The build mode to use
|
||||||
mode: Option<String>,
|
mode: Option<String>,
|
||||||
/// Arguments to pass to the project binary
|
/// Arguments to pass to the project binary
|
||||||
@@ -36,59 +40,421 @@ enum Subcommand {
|
|||||||
},
|
},
|
||||||
/// Build the local project
|
/// Build the local project
|
||||||
Build {
|
Build {
|
||||||
|
/// Force recompilation of the project
|
||||||
|
#[arg(long, short)]
|
||||||
|
force_recompile: bool,
|
||||||
/// The build mode to use
|
/// The build mode to use
|
||||||
mode: Option<String>,
|
mode: Option<String>,
|
||||||
},
|
},
|
||||||
/// Clean all in progress files
|
/// Clean all in progress files
|
||||||
Clean,
|
Clean,
|
||||||
|
/// Utility functions
|
||||||
|
Utils {
|
||||||
|
#[clap(subcommand)]
|
||||||
|
command: UtilSubcommand,
|
||||||
|
},
|
||||||
|
/// List available build modes
|
||||||
|
List,
|
||||||
|
/// Add a new package to the project (throguh pkg-config)
|
||||||
|
Add {
|
||||||
|
/// The package to be added
|
||||||
|
package: String,
|
||||||
|
},
|
||||||
|
/// Watches for source code changes and triggers a recompilation && re-run on change
|
||||||
|
Watch {
|
||||||
|
/// The build mode to use
|
||||||
|
mode: Option<String>,
|
||||||
|
/// Arguments to pass to the project binary
|
||||||
|
#[arg(long, short)]
|
||||||
|
args: Option<Vec<String>>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::Subcommand)]
|
||||||
|
enum UtilSubcommand {
|
||||||
|
/// Generate shell completions
|
||||||
|
Completions {
|
||||||
|
/// The shell to generate completions for
|
||||||
|
#[arg(value_enum, long, short)]
|
||||||
|
shell: ShellCompletions,
|
||||||
|
},
|
||||||
|
/// Generate compile_commands.json for IDE support
|
||||||
|
GenCompileCommands {
|
||||||
|
/// The build mode to generate for
|
||||||
|
mode: Option<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, clap::ValueEnum)]
|
||||||
|
enum ShellCompletions {
|
||||||
|
Bash,
|
||||||
|
Fish,
|
||||||
|
PowerShell,
|
||||||
|
Zsh,
|
||||||
|
Nushell,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn run(self) {
|
pub fn run(self) {
|
||||||
match self.command {
|
match self.command {
|
||||||
Subcommand::New { name } => match create_project(&name) {
|
Subcommand::New { name } => {
|
||||||
Err(e) => {
|
if let Err(e) = create_project(&name) {
|
||||||
eprintln!("Error creating project '{name}': {e}");
|
eprintln!("Error creating project '{name}': {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
_ => {}
|
}
|
||||||
},
|
Subcommand::Init => {
|
||||||
Subcommand::Init => match create_project(".") {
|
if let Err(e) = create_project(".") {
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Error initializing project: {e}");
|
eprintln!("Error initializing project: {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
_ => {}
|
}
|
||||||
},
|
Subcommand::Run {
|
||||||
Subcommand::Run { mode, args } => {
|
mode,
|
||||||
match build(&mode) {
|
args,
|
||||||
Err(e) => {
|
force_recompile,
|
||||||
|
} => {
|
||||||
|
if let Err(e) = build(&mode, force_recompile) {
|
||||||
eprintln!("Error building project: {e}");
|
eprintln!("Error building project: {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
};
|
||||||
if let Err(e) = run(&mode, args) {
|
if let Err(e) = run(&mode, args) {
|
||||||
eprintln!("Error running project: {e}");
|
eprintln!("Error running project: {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Subcommand::Build { mode } => match build(&mode) {
|
Subcommand::Build {
|
||||||
Err(e) => {
|
mode,
|
||||||
|
force_recompile,
|
||||||
|
} => {
|
||||||
|
if let Err(e) = build(&mode, force_recompile) {
|
||||||
eprintln!("Error building project: {e}");
|
eprintln!("Error building project: {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
_ => {}
|
}
|
||||||
},
|
Subcommand::Clean => {
|
||||||
Subcommand::Clean => match clean() {
|
if let Err(e) = clean() {
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Error cleaning project: {e}");
|
eprintln!("Error cleaning project: {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
_ => {}
|
}
|
||||||
|
Subcommand::Utils { command } => match command {
|
||||||
|
UtilSubcommand::Completions { shell } => {
|
||||||
|
let name = env!("CARGO_PKG_NAME");
|
||||||
|
let mut command = App::command();
|
||||||
|
match shell {
|
||||||
|
ShellCompletions::Bash => clap_complete::generate(
|
||||||
|
clap_complete::shells::Bash,
|
||||||
|
&mut command,
|
||||||
|
name,
|
||||||
|
&mut std::io::stdout(),
|
||||||
|
),
|
||||||
|
ShellCompletions::Fish => clap_complete::generate(
|
||||||
|
clap_complete::shells::Fish,
|
||||||
|
&mut command,
|
||||||
|
name,
|
||||||
|
&mut std::io::stdout(),
|
||||||
|
),
|
||||||
|
ShellCompletions::PowerShell => clap_complete::generate(
|
||||||
|
clap_complete::shells::PowerShell,
|
||||||
|
&mut command,
|
||||||
|
name,
|
||||||
|
&mut std::io::stdout(),
|
||||||
|
),
|
||||||
|
ShellCompletions::Zsh => clap_complete::generate(
|
||||||
|
clap_complete::shells::Zsh,
|
||||||
|
&mut command,
|
||||||
|
name,
|
||||||
|
&mut std::io::stdout(),
|
||||||
|
),
|
||||||
|
ShellCompletions::Nushell => clap_complete::generate(
|
||||||
|
clap_complete_nushell::Nushell,
|
||||||
|
&mut command,
|
||||||
|
name,
|
||||||
|
&mut std::io::stdout(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UtilSubcommand::GenCompileCommands { mode } => {
|
||||||
|
if let Err(e) = gen_compile_commands(&mode) {
|
||||||
|
eprintln!("Error generating compile commands: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
Subcommand::List => {
|
||||||
|
if let Err(e) = list() {
|
||||||
|
eprintln!("Error listing build profiles: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Subcommand::Add { package } => {
|
||||||
|
if let Err(e) = add_package(&package) {
|
||||||
|
eprintln!("Error adding package {package} to project: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Subcommand::Watch { mode, args } => {
|
||||||
|
if let Err(e) = watch(&mode, args) {
|
||||||
|
eprintln!("Error running watch: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn watch(mode: &Option<String>, args: Option<Vec<String>>) -> std::io::Result<()> {
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
// save terminal state
|
||||||
|
let mut stdout = std::io::stdout();
|
||||||
|
// enter alternate screen — this is a separate terminal buffer,
|
||||||
|
// exiting it restores everything exactly as it was
|
||||||
|
write!(stdout, "\x1b[?1049h")?;
|
||||||
|
stdout.flush()?;
|
||||||
|
|
||||||
|
// make sure we always restore the terminal, even on panic
|
||||||
|
let result = watch_inner(mode, args);
|
||||||
|
|
||||||
|
// exit alternate screen
|
||||||
|
write!(stdout, "\x1b[?1049l")?;
|
||||||
|
stdout.flush()?;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn watch_inner(mode: &Option<String>, args: Option<Vec<String>>) -> std::io::Result<()> {
|
||||||
|
use notify::{Event, RecursiveMode, Watcher, recommended_watcher};
|
||||||
|
use std::io::Write;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
let clear = || {
|
||||||
|
let mut stdout = std::io::stdout();
|
||||||
|
write!(stdout, "\x1b[2J\x1b[H").ok();
|
||||||
|
stdout.flush().ok();
|
||||||
|
};
|
||||||
|
|
||||||
|
let print_header = |label: &str| {
|
||||||
|
println!(
|
||||||
|
" {} project (ctrl+c to stop) — {label}",
|
||||||
|
"Watching".green().bold()
|
||||||
|
);
|
||||||
|
println!("{}", "─".repeat(50).dimmed());
|
||||||
|
};
|
||||||
|
|
||||||
|
// track the running child process
|
||||||
|
let mut child: Option<std::process::Child> = None;
|
||||||
|
|
||||||
|
let kill_child = |child: &mut Option<std::process::Child>| {
|
||||||
|
if let Some(c) = child {
|
||||||
|
c.kill().ok();
|
||||||
|
c.wait().ok();
|
||||||
|
}
|
||||||
|
*child = None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let run_child = |mode: &Option<String>,
|
||||||
|
args: &Option<Vec<String>>|
|
||||||
|
-> std::io::Result<std::process::Child> {
|
||||||
|
let conf = get_config().ok_or(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"no Pallet.toml found",
|
||||||
|
))?;
|
||||||
|
let build_config = conf.get_or_default(mode).ok_or(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"build layout not found",
|
||||||
|
))?;
|
||||||
|
let mut command = Command::new(format!("target/{}/{}", build_config.name, conf.name));
|
||||||
|
if let Some(a) = args {
|
||||||
|
for arg in a {
|
||||||
|
command.arg(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
command
|
||||||
|
.spawn()
|
||||||
|
.map_err(|e| std::io::Error::other(format!("{e}")))
|
||||||
|
};
|
||||||
|
|
||||||
|
// initial build + run
|
||||||
|
clear();
|
||||||
|
print_header("starting");
|
||||||
|
if build(mode, false).is_ok() {
|
||||||
|
child = run_child(mode, &args).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel::<notify::Result<Event>>();
|
||||||
|
let mut watcher = recommended_watcher(tx).map_err(|e| std::io::Error::other(format!("{e}")))?;
|
||||||
|
watcher
|
||||||
|
.watch(Path::new("src"), RecursiveMode::Recursive)
|
||||||
|
.map_err(|e| std::io::Error::other(format!("{e}")))?;
|
||||||
|
|
||||||
|
let mut last_build = Instant::now()
|
||||||
|
.checked_sub(Duration::from_secs(1))
|
||||||
|
.unwrap_or(Instant::now());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match rx.recv() {
|
||||||
|
Ok(Ok(event)) => {
|
||||||
|
let is_relevant = matches!(
|
||||||
|
event.kind,
|
||||||
|
notify::EventKind::Create(_)
|
||||||
|
| notify::EventKind::Modify(_)
|
||||||
|
| notify::EventKind::Remove(_)
|
||||||
|
);
|
||||||
|
let affects_source = event.paths.iter().any(|p| {
|
||||||
|
matches!(
|
||||||
|
p.extension().and_then(|e| e.to_str()),
|
||||||
|
Some("c") | Some("h")
|
||||||
|
)
|
||||||
|
});
|
||||||
|
let debounced = last_build.elapsed() > Duration::from_millis(500);
|
||||||
|
|
||||||
|
if is_relevant && affects_source && debounced {
|
||||||
|
last_build = Instant::now();
|
||||||
|
|
||||||
|
// kill whatever is currently running
|
||||||
|
kill_child(&mut child);
|
||||||
|
|
||||||
|
clear();
|
||||||
|
print_header("rebuilding");
|
||||||
|
|
||||||
|
match build(mode, false) {
|
||||||
|
Ok(_) => {
|
||||||
|
child = run_child(mode, &args).ok();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!(" {} {e}", "Error".red().bold());
|
||||||
|
// child stays None until next successful build
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Err(e)) => eprintln!(" {} watch error: {e}", "Error".red().bold()),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!(" {} channel error: {e}", "Error".red().bold());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kill_child(&mut child);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_package(package: &str) -> std::io::Result<()> {
|
||||||
|
let status = Command::new("pkg-config")
|
||||||
|
.arg("--exists")
|
||||||
|
.arg(package)
|
||||||
|
.status()
|
||||||
|
.map_err(|_| {
|
||||||
|
std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"pkg-config not found - please install it first",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
eprintln!(
|
||||||
|
" {} pkg-config could not find package '{package}'",
|
||||||
|
"Error".red().bold()
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
" {} try installing the development package for '{package}', e.g.:",
|
||||||
|
"Hint".yellow().bold()
|
||||||
|
);
|
||||||
|
eprintln!(" Arch: sudo pacman -S {package}");
|
||||||
|
eprintln!(" Debian: sudo apt install lib{package}-dev");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut conf = get_config().ok_or(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"no Pallet.toml found in local directory",
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let deps = conf.dependencies.get_or_insert_with(Vec::new);
|
||||||
|
|
||||||
|
if deps.contains(&package.to_owned()) {
|
||||||
|
println!(
|
||||||
|
" {} '{package}' is already a dependency",
|
||||||
|
"Warning".yellow().bold()
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
deps.push(package.to_owned());
|
||||||
|
|
||||||
|
std::fs::write(
|
||||||
|
"Pallet.toml",
|
||||||
|
toml::to_string_pretty(&conf).expect("valid TOML"),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
println!(" {} {package}", "Added".green().bold());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_compile_commands(mode: &Option<String>) -> std::io::Result<()> {
|
||||||
|
let conf = get_config().ok_or(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"no Pallet.toml found in current directory",
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let build_config = conf.get_or_default(mode).ok_or(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"build layout not found",
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let compiler = conf.compiler.as_deref().unwrap_or("gcc");
|
||||||
|
let cwd = std::env::current_dir()?;
|
||||||
|
let obj_dir = format!("target/{}/obj", build_config.name);
|
||||||
|
|
||||||
|
let source_files: Vec<PathBuf> = glob("src/*.c")
|
||||||
|
.map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, format!("{e}")))?
|
||||||
|
.filter_map(|e| e.ok())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let entries: Vec<serde_json::Value> = source_files
|
||||||
|
.iter()
|
||||||
|
.map(|src| {
|
||||||
|
let stem = src.file_stem().unwrap().to_string_lossy();
|
||||||
|
let obj = format!("{}/{}.o", obj_dir, stem);
|
||||||
|
let command = std::iter::once(compiler.to_string())
|
||||||
|
.chain(build_config.args.iter().cloned())
|
||||||
|
.chain(["-c".to_string(), src.to_string_lossy().to_string()])
|
||||||
|
.chain(["-o".to_string(), obj])
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ");
|
||||||
|
serde_json::json!({
|
||||||
|
"directory": cwd.to_string_lossy(),
|
||||||
|
"file": cwd.join(src).to_string_lossy(),
|
||||||
|
"command": command
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let json = serde_json::to_string_pretty(&entries)
|
||||||
|
.map_err(|e| std::io::Error::other(format!("{e}")))?;
|
||||||
|
|
||||||
|
std::fs::write("compile_commands.json", json)?;
|
||||||
|
|
||||||
|
println!(" {} compile_commands.json", "Generated".green().bold());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list() -> std::io::Result<()> {
|
||||||
|
let conf = get_config().ok_or(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"no Pallet.toml found in local directory",
|
||||||
|
))?;
|
||||||
|
for build in conf.build {
|
||||||
|
println!(" - {}: {:?}", build.name.green().bold(), build.args);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_project<P: AsRef<Path>>(directory: P) -> std::io::Result<()> {
|
fn create_project<P: AsRef<Path>>(directory: P) -> std::io::Result<()> {
|
||||||
@@ -124,7 +490,19 @@ fn create_project<P: AsRef<Path>>(directory: P) -> std::io::Result<()> {
|
|||||||
std::fs::write("src/main.c", MAIN_C)?;
|
std::fs::write("src/main.c", MAIN_C)?;
|
||||||
std::fs::write(".gitignore", GITIGNORE)?;
|
std::fs::write(".gitignore", GITIGNORE)?;
|
||||||
|
|
||||||
let config = crate::config::Config::new(&pathdir.to_string_lossy());
|
let lossy = pathdir.to_string_lossy();
|
||||||
|
|
||||||
|
let app_name = if lossy == "." {
|
||||||
|
let root = std::env::current_dir()?;
|
||||||
|
root.file_name()
|
||||||
|
.expect("a valid file name")
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
} else {
|
||||||
|
lossy.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = crate::config::Config::new(&app_name);
|
||||||
|
|
||||||
let serial = toml::to_string_pretty(&config).expect("a valid TOML structure");
|
let serial = toml::to_string_pretty(&config).expect("a valid TOML structure");
|
||||||
|
|
||||||
@@ -143,7 +521,7 @@ fn get_config() -> Option<crate::config::Config> {
|
|||||||
toml::from_str(&raw).ok()
|
toml::from_str(&raw).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(mode: &Option<String>) -> std::io::Result<()> {
|
fn build(mode: &Option<String>, force_recompile: bool) -> std::io::Result<()> {
|
||||||
let conf = match get_config() {
|
let conf = match get_config() {
|
||||||
Some(conf) => conf,
|
Some(conf) => conf,
|
||||||
None => {
|
None => {
|
||||||
@@ -166,32 +544,132 @@ fn build(mode: &Option<String>) -> std::io::Result<()> {
|
|||||||
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
std::fs::create_dir_all(format!("target/{}", build_config.name))?;
|
let obj_dir = format!("target/{}/obj", build_config.name);
|
||||||
|
|
||||||
let mut command = Command::new("gcc");
|
std::fs::create_dir_all(&obj_dir)?;
|
||||||
|
|
||||||
for arg in &build_config.args {
|
let compiler = conf.compiler.as_deref().unwrap_or("gcc");
|
||||||
command.arg(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
for entry in glob("src/*.c")
|
let mut extra_compile_flags: Vec<String> = Vec::new();
|
||||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, format!("{e}").as_str()))?
|
let mut extra_link_flags: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
if let Some(deps) = &conf.dependencies
|
||||||
|
&& !deps.is_empty()
|
||||||
{
|
{
|
||||||
if let Ok(path) = entry {
|
let cflags = Command::new("pkg-config")
|
||||||
command.arg(path.to_string_lossy().to_string());
|
.arg("--cflags")
|
||||||
}
|
.args(deps)
|
||||||
|
.output()
|
||||||
|
.map_err(|_| {
|
||||||
|
std::io::Error::new(std::io::ErrorKind::NotFound, "pkg-config not found")
|
||||||
|
})?;
|
||||||
|
if !cflags.status.success() {
|
||||||
|
return Err(std::io::Error::other(
|
||||||
|
"pkg-config --cflags failed - is the package installed?",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
command
|
let libs = Command::new("pkg-config")
|
||||||
|
.arg("--libs")
|
||||||
|
.args(deps)
|
||||||
|
.output()
|
||||||
|
.map_err(|_| {
|
||||||
|
std::io::Error::new(std::io::ErrorKind::NotFound, "pkg-config not found")
|
||||||
|
})?;
|
||||||
|
if !libs.status.success() {
|
||||||
|
return Err(std::io::Error::other(
|
||||||
|
"pkg-config --libs failed - is the pacakge installed?",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
extra_compile_flags = String::from_utf8_lossy(&cflags.stdout)
|
||||||
|
.split_whitespace()
|
||||||
|
.map(str::to_owned)
|
||||||
|
.collect();
|
||||||
|
extra_link_flags = String::from_utf8_lossy(&libs.stdout)
|
||||||
|
.split_whitespace()
|
||||||
|
.map(str::to_owned)
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
let source_files: Vec<PathBuf> = glob("src/*.c")
|
||||||
|
.map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, format!("{e}")))?
|
||||||
|
.filter_map(|e| e.ok())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut any_changed = false;
|
||||||
|
|
||||||
|
for src in &source_files {
|
||||||
|
let stem = src.file_stem().unwrap().to_string_lossy();
|
||||||
|
let obj_path = format!("{}/{}.o", obj_dir, stem);
|
||||||
|
let hash_path = format!("{}/{}.c.hash", obj_dir, stem);
|
||||||
|
|
||||||
|
let hash = hash_file(src)?;
|
||||||
|
|
||||||
|
let needs_compile = force_recompile
|
||||||
|
|| match std::fs::read_to_string(&hash_path) {
|
||||||
|
Ok(old) => old.trim() != hash.trim(),
|
||||||
|
Err(_) => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if needs_compile {
|
||||||
|
println!(" {} {}", "Compiling".green().bold(), src.display());
|
||||||
|
|
||||||
|
let status = Command::new(compiler)
|
||||||
|
.args(&build_config.args)
|
||||||
|
.args(&extra_compile_flags)
|
||||||
|
.arg("-c")
|
||||||
|
.arg(src)
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
.arg(format!("target/{}/{}", build_config.name, conf.name));
|
.arg(&obj_path)
|
||||||
|
.status()?;
|
||||||
|
|
||||||
let mut child = command.spawn()?;
|
if !status.success() {
|
||||||
|
return Err(std::io::Error::other(format!(
|
||||||
|
"failed to compile {}",
|
||||||
|
src.display()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
child.wait()?;
|
std::fs::write(&hash_path, &hash)?;
|
||||||
|
any_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let binary = format!("target/{}/{}", build_config.name, conf.name);
|
||||||
|
let binary_exists = PathBuf::from(&binary).exists();
|
||||||
|
|
||||||
|
if !any_changed && binary_exists {
|
||||||
|
println!(
|
||||||
|
" {} (code not changed, recompile not made)",
|
||||||
|
"Finished".green().bold()
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj_files: Vec<String> = source_files
|
||||||
|
.iter()
|
||||||
|
.map(|src| {
|
||||||
|
let stem = src.file_stem().unwrap().to_string_lossy();
|
||||||
|
format!("{}/{}.o", obj_dir, stem)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let status = Command::new(compiler)
|
||||||
|
.args(&obj_files)
|
||||||
|
.args(&extra_link_flags)
|
||||||
|
.arg("-o")
|
||||||
|
.arg(&binary)
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
return Err(std::io::Error::other("linking failed"));
|
||||||
|
}
|
||||||
|
|
||||||
let stop = start.elapsed();
|
let stop = start.elapsed();
|
||||||
|
|
||||||
|
gen_compile_commands(mode)?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
" {} '{}' profile for project '{}' in {:.2}s",
|
" {} '{}' profile for project '{}' in {:.2}s",
|
||||||
"Finished".green().bold(),
|
"Finished".green().bold(),
|
||||||
@@ -203,6 +681,11 @@ fn build(mode: &Option<String>) -> std::io::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hash_file(path: &Path) -> std::io::Result<String> {
|
||||||
|
let contents = std::fs::read_to_string(path)?;
|
||||||
|
Ok(sha256::digest(contents))
|
||||||
|
}
|
||||||
|
|
||||||
fn run(mode: &Option<String>, args: Option<Vec<String>>) -> std::io::Result<()> {
|
fn run(mode: &Option<String>, args: Option<Vec<String>>) -> std::io::Result<()> {
|
||||||
let conf = match get_config() {
|
let conf = match get_config() {
|
||||||
Some(conf) => conf,
|
Some(conf) => conf,
|
||||||
@@ -240,7 +723,7 @@ fn run(mode: &Option<String>, args: Option<Vec<String>>) -> std::io::Result<()>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn clean() -> std::io::Result<()> {
|
fn clean() -> std::io::Result<()> {
|
||||||
if let None = get_config() {
|
if get_config().is_none() {
|
||||||
return Err(std::io::Error::new(
|
return Err(std::io::Error::new(
|
||||||
std::io::ErrorKind::NotFound,
|
std::io::ErrorKind::NotFound,
|
||||||
"no Pallet.toml found in local dir",
|
"no Pallet.toml found in local dir",
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#[derive(serde::Deserialize, serde::Serialize, Default)]
|
#[derive(serde::Deserialize, serde::Serialize, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
/// The C compiler to use (defaults to "gcc")
|
||||||
|
pub compiler: Option<String>,
|
||||||
/// The name of the output binary
|
/// The name of the output binary
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// The default build to use
|
/// The default build to use
|
||||||
@@ -12,6 +14,8 @@ pub struct Config {
|
|||||||
pub authors: Option<Vec<String>>,
|
pub authors: Option<Vec<String>>,
|
||||||
/// Build configs
|
/// Build configs
|
||||||
pub build: Vec<BuildConf>,
|
pub build: Vec<BuildConf>,
|
||||||
|
/// Build dependnecies verified by pkg-config
|
||||||
|
pub dependencies: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
|||||||
Reference in New Issue
Block a user