Compare commits
8 commits
Author | SHA1 | Date | |
---|---|---|---|
8614bfacbd | |||
736b62528b | |||
9d5639462a | |||
fb25f0c0f4 | |||
fb8ed1ae8c | |||
b98a3beec4 | |||
1690131e4f | |||
21080610a7 |
13 changed files with 500 additions and 245 deletions
266
Cargo.lock
generated
266
Cargo.lock
generated
|
@ -79,9 +79,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.17"
|
||||
version = "1.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
||||
checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
|
@ -102,9 +102,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.32"
|
||||
version = "4.5.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
|
||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -112,9 +112,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.32"
|
||||
version = "4.5.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
|
||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -176,9 +176,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.4.5"
|
||||
version = "3.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
|
||||
checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"windows-sys",
|
||||
|
@ -230,6 +230,18 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.20.1"
|
||||
|
@ -246,9 +258,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
@ -264,21 +276,22 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
|||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
|
||||
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"potential_utf",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid"
|
||||
version = "1.5.0"
|
||||
name = "icu_locale_core"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
|
||||
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
|
@ -287,31 +300,11 @@ dependencies = [
|
|||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_locid_transform_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "1.5.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
|
||||
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
|
@ -319,67 +312,54 @@ dependencies = [
|
|||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"write16",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "1.5.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
|
||||
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "1.5.1"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
|
||||
checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locid_transform",
|
||||
"icu_locale_core",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"potential_utf",
|
||||
"zerotrie",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "1.5.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
|
||||
checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "1.5.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
|
||||
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_provider_macros",
|
||||
"icu_locale_core",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerotrie",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider_macros"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
|
@ -393,9 +373,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "idna_adapter"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
|
||||
dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
|
@ -403,9 +383,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
@ -419,18 +399,19 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
|||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.32"
|
||||
version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
|
@ -473,15 +454,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.5"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
|
||||
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.26"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
|
@ -491,9 +472,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
|||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.29.0"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
|
@ -503,9 +484,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.1"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
|
@ -515,9 +496,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
|||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.106"
|
||||
version = "0.9.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
|
||||
checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
@ -538,10 +519,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
name = "potential_utf"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
|
||||
dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -570,9 +560,15 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
|
||||
[[package]]
|
||||
name = "refractr"
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"colored",
|
||||
|
@ -619,9 +615,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
|
@ -636,9 +632,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
|
@ -654,9 +650,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -665,9 +661,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.1"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -676,9 +672,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
|
||||
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"zerovec",
|
||||
|
@ -686,9 +682,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.20"
|
||||
version = "0.8.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
||||
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
|
@ -698,26 +694,33 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.24"
|
||||
version = "0.22.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
||||
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_write",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_write"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
|
@ -761,12 +764,6 @@ dependencies = [
|
|||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
|
@ -791,6 +788,15 @@ version = "0.9.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
|
@ -878,30 +884,33 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.4"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.5"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.5"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
|
||||
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
|
@ -911,9 +920,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.7.5"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
||||
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -943,10 +952,21 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
name = "zerotrie"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
|
||||
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
|
@ -955,9 +975,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.10.3"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "refractr"
|
||||
license = "MPL-2.0"
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
|
12
Dockerfile
12
Dockerfile
|
@ -1,12 +0,0 @@
|
|||
FROM git.brysonsteck.xyz/brysonsteck/refractr:latest
|
||||
|
||||
# replace "path/" with the path containing your refractr configs
|
||||
COPY path/ /etc/refractr
|
||||
|
||||
# use --secret with docker build to specify your ssh key
|
||||
# make sure your configs use the location below
|
||||
RUN --mount=type=secret,id=key,target=/id.pub \
|
||||
cp /id.pub /etc/refractr && chmod 400 /etc/refractr/id.pub
|
||||
|
||||
# add arguments to specify verbosity and configs as needed
|
||||
CMD ["refractr", "-c", "/etc/refractr/config.json"]
|
24
build
24
build
|
@ -2,22 +2,32 @@
|
|||
# Create all the different builds for refractr
|
||||
|
||||
version=$(cat Cargo.toml | grep -m1 version | awk -F' ' '{print $3}' | sed 's|"||g')
|
||||
major_version=$(echo $version | awk -F'.' '{print $1}')
|
||||
uid=$(id -u)
|
||||
gid=$(id -g)
|
||||
cargo update
|
||||
cargo clean
|
||||
date=$(date -u --rfc-3339=seconds)
|
||||
cargo=$(which cargo 2> /dev/null)
|
||||
|
||||
if [ -n "$cargo" ]; then
|
||||
cargo update
|
||||
cargo clean
|
||||
fi
|
||||
|
||||
# docker builds
|
||||
docker build -t refractr:$version --build-arg UID=$uid --build-arg GID=$gid --build-arg VERSION=$version -f package.Dockerfile .
|
||||
docker tag refractr:$version refractr:latest
|
||||
if test "$1" = "push"; then
|
||||
docker build -t refractr:$version -t refractr:$major_version -t refractr:latest \
|
||||
--build-arg VERSION=$version --build-arg DATE="$date" -f docker/Dockerfile .
|
||||
if [ "$1" = "push" ]; then
|
||||
docker tag refractr:$version git.brysonsteck.xyz/brysonsteck/refractr:latest
|
||||
docker tag refractr:$version git.brysonsteck.xyz/brysonsteck/refractr:$version
|
||||
docker tag refractr:$version git.brysonsteck.xyz/brysonsteck/refractr:$major_version
|
||||
docker push -a git.brysonsteck.xyz/brysonsteck/refractr
|
||||
docker image rm git.brysonsteck.xyz/brysonsteck/refractr:latest
|
||||
docker image rm git.brysonsteck.xyz/brysonsteck/refractr:$version
|
||||
docker image rm git.brysonsteck.xyz/brysonsteck/refractr:$major_version
|
||||
fi
|
||||
|
||||
# rust build
|
||||
cargo build
|
||||
cargo build --release
|
||||
if [ -n "$cargo" ]; then
|
||||
cargo build
|
||||
cargo build --release
|
||||
fi
|
||||
|
|
31
docker/Dockerfile
Normal file
31
docker/Dockerfile
Normal file
|
@ -0,0 +1,31 @@
|
|||
FROM rust:1-alpine AS build
|
||||
|
||||
ENV REFRACTR_DOCKER="true"
|
||||
|
||||
WORKDIR /usr/src/refractr
|
||||
COPY . .
|
||||
|
||||
RUN apk upgrade --no-cache && apk add --no-cache pkgconfig libc-dev openssl-dev openssl openssl-libs-static
|
||||
RUN cargo install --path . && cargo clean
|
||||
|
||||
FROM alpine:3 AS package
|
||||
|
||||
ARG VERSION
|
||||
ARG DATE
|
||||
|
||||
LABEL org.opencontainers.image.title="refractr"
|
||||
LABEL org.opencontainers.image.authors="me@brysonsteck.xyz"
|
||||
LABEL org.opencontainers.image.version="${VERSION}"
|
||||
LABEL org.opencontainers.image.url="https://git.brysonsteck.xyz/brysonsteck/-/packages/container/refractr/${VERSION}"
|
||||
LABEL org.opencontainers.image.source="https://git.brysonsteck.xyz/brysonsteck/refractr"
|
||||
LABEL org.opencontainers.image.licenses="MPL-2.0"
|
||||
LABEL org.opencontainers.image.created="${DATE}"
|
||||
|
||||
RUN apk upgrade --no-cache && apk add --no-cache openssl
|
||||
RUN mkdir /etc/refractr
|
||||
COPY ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
|
||||
COPY --from=build /usr/src/refractr /usr/src
|
||||
COPY --from=build /usr/local/cargo/bin/refractr /usr/local/bin
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
17
docker/docker-compose.example.yaml
Normal file
17
docker/docker-compose.example.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
services:
|
||||
refractr:
|
||||
image: git.brysonsteck.xyz/brysonsteck/refractr:latest
|
||||
environment:
|
||||
# change these to your uid/gid
|
||||
# if omitted, the container will guess
|
||||
- UID=1000
|
||||
- GID=1000
|
||||
volumes:
|
||||
- /home/bryson/configs:/etc/refractr:ro
|
||||
secrets:
|
||||
- ssh_key
|
||||
|
||||
secrets:
|
||||
ssh_key:
|
||||
# available in /run/secrets/ssh_key
|
||||
file: /home/bryson/.ssh/id_rsa
|
38
docker/entrypoint.sh
Executable file
38
docker/entrypoint.sh
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh
|
||||
# Entrypoint file for refractr
|
||||
# Runs refractr with some verbosity and all configs in /etc/refractr
|
||||
#
|
||||
# Copyright 2025 Bryson Steck <me@brysonsteck.xyz>
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
|
||||
if [ -z "$UID" ]; then
|
||||
set=$(ls -lnd /etc/refractr/ | awk '{print $3}')
|
||||
echo "UID not set! Setting to id $set (owner of /etc/refractr)"
|
||||
export UID=$set
|
||||
fi
|
||||
|
||||
if [ -z "$GID" ]; then
|
||||
set=$(ls -lnd /etc/refractr/ | awk '{print $4}')
|
||||
echo "GID not set! Setting to id $set (group of /etc/refractr)"
|
||||
export GID=$set
|
||||
fi
|
||||
|
||||
if ! ls /etc/refractr/*.toml &> /dev/null; then
|
||||
echo "Failed to find any toml config files for refractr!"
|
||||
echo "Make sure you copied configs or set up volumes correctly."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
args=""
|
||||
for config in /etc/refractr/*.toml; do
|
||||
args="${args}-c '${config}' "
|
||||
done
|
||||
|
||||
addgroup -g $GID dockeruser
|
||||
adduser -u $UID -G $(grep :$GID: /etc/group | awk -F: '{print $1}') -D dockeruser
|
||||
|
||||
su -p - dockeruser -c "refractr -vv ${args}"
|
101
man/refractr.1
101
man/refractr.1
|
@ -0,0 +1,101 @@
|
|||
.TH REFRACTR 1 "Updated 2025-03-25" "Bryson Steck"
|
||||
.SH NAME
|
||||
refractr \- an automated push mirroring utility for Git repositories
|
||||
.SH SYNOPSIS
|
||||
.B refractr
|
||||
[\fBOPTIONS\fR]
|
||||
.SH DESCRIPTION
|
||||
refractr is an automated push mirroring utility for Git repositories.
|
||||
|
||||
With no options, refractr will attempt to load the config located at /etc/refractr/config.toml and run with that configuration.
|
||||
For details for configuration files, see CONFIGURATION OPTIONS.
|
||||
.SH OPTIONS
|
||||
.sp
|
||||
.TP 0.5i
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Display a brief help message on the command line.
|
||||
.TP 0.5i
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
Display the version of refractr on the command line.
|
||||
.TP 0.5i
|
||||
\fB\-c\fR, \fB\-\-config\fR [FILE]
|
||||
Specify the absolute or relative path to a configuration file. Multiple configuration files can be specified by using multiple flags.
|
||||
.P
|
||||
.TP 0.5i
|
||||
\fB\-v\fR, \fB\-\-verbose...\fR
|
||||
Specify the level of verbose messages for refractr to output.
|
||||
The functionality of this flag is similar to ssh(1); adding multiple flags will increase the amount of output with specific messages to what refractr is doing.
|
||||
The more flags specified, the more low-level messages will appear.
|
||||
.TP 0.5i
|
||||
\fB\-e\fR, \fB\-\-create\fR
|
||||
Print a full, commented config file to the standard output and exit. You can use this to generate config files that you can fill in and pass to refractr with the -c flag.
|
||||
Information on the values for a refractr configuration can be found in the CONFIGURATION section.
|
||||
.TP 0.5i
|
||||
\fB\-s\fR, \fB\-\-strict\fR
|
||||
Enable strict mode.
|
||||
|
||||
By design, refractr will ignore problems that occur when pushing to remotes and verifying host signatures when using SSH remotes.
|
||||
Some of these errors may include networking issues and a host missing from your SSH known_hosts file, but refractr takes your configurations as
|
||||
implicit trust that the remotes you pull/push from are correct and reachable. This also makes it so refractr will continuously try to
|
||||
update the remotes with changes from the upstream repository to avoid synchronization issues.
|
||||
|
||||
If you wish for refractr to exit on these kinds of errors as a way to know of these issues, you can use this flag to enable "strict" mode.
|
||||
Doing so will make refractr exit instead of continue or loop forever when encountering these problems.
|
||||
.TP 0.5i
|
||||
\fB\-p\fR, \fB\-\-persist\fR
|
||||
Do not recursively delete the working directory as defined in your configuration file(s).
|
||||
This can be helpful for troubleshooting issues with your repository, a potential bug with refractr, or general development.
|
||||
.P
|
||||
.SH CONFIGURATION
|
||||
Below are the values for defining a refractr configuration.
|
||||
.TP 0.5i
|
||||
\fBfrom (string, REQUIRED)\fR
|
||||
The original/upstream repository URI. This field MUST START with "https://" or "ssh://".
|
||||
.TP 0.5i
|
||||
\fBto (array, REQUIRED)\fR
|
||||
The list of remotes you wish to push the repo to as cloned from the "from" field.
|
||||
This field must be SSH remotes and the repository must exist on the remotes.
|
||||
.TP 0.5i
|
||||
\fBbranches (array, REQUIRED)\fR
|
||||
The list of branches from the original/upstream repository you wish to push to the remotes.
|
||||
.TP 0.5i
|
||||
\fBwork_dir (string, OPTIONAL)\fR
|
||||
The path on the filesystem refractr will clone this repository to and work from.
|
||||
If omitted, this field defaults to "/tmp/refractr" on UNIX(-like) systems and "$env:TEMP\\refractr" on Windows.
|
||||
.TP 0.5i
|
||||
\fBpush_tags (boolean, REQUIRED)\fR
|
||||
Push tags pulled from the original/upstream repository to the remotes.
|
||||
.TP 0.5i
|
||||
\fBgit.ssh_identity_file (string, REQUIRED)\fR
|
||||
The path to your SSH private key for authenticating to the remotes specified in the "from" (if using SSH) and "to" fields.
|
||||
|
||||
If using Docker, you will need to copy your private key to your container or build it in an image using secrets in your Dockerfile.
|
||||
.TP 0.5i
|
||||
\fBschedule.enabled (bool, REQUIRED)\fR
|
||||
Enable the schedule feature of refractr. This allows you to regularly pull updates and push them out on a regular basis.
|
||||
.TP 0.5i
|
||||
\fBschedule.interval (integer, DEPENDS ON schedule.enabled)\fR
|
||||
The amount of time in seconds to pull updates and push them out to remotes.
|
||||
To avoid creating unneeded stress on servers, this value must be greater than or equal to 60.
|
||||
|
||||
If "schedule.enabled" is false, refractr will not check for this value.
|
||||
If "scheduled.enabled" is true, refractr will check this value. If it does not exist or is less than 60, refractr will return an error.
|
||||
.SH AUTHORS
|
||||
.B Bryson Steck <me@brysonsteck.xyz> (https://brysonsteck.xyz)
|
||||
.P
|
||||
.SH CONTRIBUTE
|
||||
refractr is free and open source! Please report any bugs in, provide feedback for, or contribute to refractr by visiting the Codeberg repository:
|
||||
.IR https://codeberg.org/brysonsteck/refractr
|
||||
|
||||
The Codeberg repository is proof of refractr at work. An upstream, read-only version of the repository is also available at:
|
||||
.IR https://git.brysonsteck.xyz/brysonsteck/refractr
|
||||
.P
|
||||
.SH LICENSE
|
||||
Copyright 2025 Bryson Steck
|
||||
|
||||
The binaries and source code of refractr is distributed under and subject to the terms of the Mozilla Public License v2 (MPL-2.0).
|
||||
A copy of this license should have been distributed with this software. If you did not receive a copy, you can view the license at:
|
||||
.IR https://www.mozilla.org/en-US/MPL/2.0/
|
||||
|
||||
License violations can be reported by creating an issue in the Codeberg repository under the CONTRIBUTE section.
|
||||
.EFRATR
|
|
@ -1,22 +0,0 @@
|
|||
FROM rust:slim
|
||||
ARG UID="1000"
|
||||
ARG GID="1000"
|
||||
ARG VERSION
|
||||
ENV REFRACTR_DOCKER="true"
|
||||
|
||||
LABEL org.opencontainers.image.authors="me@brysonsteck.xyz"
|
||||
LABEL version="${VERSION}"
|
||||
LABEL license="MPL-2.0"
|
||||
|
||||
WORKDIR /usr/src/refractr
|
||||
COPY . .
|
||||
|
||||
RUN apt update && apt install pkg-config libssl-dev -y
|
||||
RUN cargo install --path .
|
||||
|
||||
RUN groupadd -g $GID refractr
|
||||
RUN useradd -u $UID -g $GID -mN refractr
|
||||
RUN mkdir /etc/refractr && chown refractr:refractr /etc/refractr
|
||||
USER refractr
|
||||
|
||||
CMD ["refractr"]
|
|
@ -16,6 +16,7 @@ pub enum ExitCode {
|
|||
PushError = 6,
|
||||
FetchError = 7,
|
||||
ConfigError = 8,
|
||||
HaltError = 130,
|
||||
}
|
||||
|
||||
pub struct ReturnData {
|
||||
|
@ -23,11 +24,15 @@ pub struct ReturnData {
|
|||
pub msg: String,
|
||||
}
|
||||
|
||||
pub fn error(msg: String, code: ExitCode) {
|
||||
pub fn error_quit(msg: String, code: ExitCode) {
|
||||
eprintln!("{} {}", "error:".red().bold(), msg);
|
||||
quit::with_code(code as u8)
|
||||
}
|
||||
|
||||
pub fn error(msg: String) {
|
||||
eprintln!("{} {}", "error:".red().bold(), msg);
|
||||
}
|
||||
|
||||
pub fn warning(msg: String) {
|
||||
eprintln!("{} {}", "warning:".yellow().bold(), msg)
|
||||
}
|
||||
|
|
|
@ -123,6 +123,19 @@ pub struct Schedule {
|
|||
pub interval: Option<i32>,
|
||||
}
|
||||
|
||||
pub fn get_work_dir(work_dir: &Option<String>) -> String {
|
||||
match work_dir {
|
||||
None => {
|
||||
if cfg!(windows) {
|
||||
format!("{}\\refractr", env::var("TEMP").unwrap())
|
||||
} else {
|
||||
format!("/tmp/refractr")
|
||||
}
|
||||
},
|
||||
Some(path) => path.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_config(paths: Vec<PathBuf>, refractr: &Refractr) -> Result<Vec<ConfigFile>, String> {
|
||||
let mut config_files: Vec<ConfigFile> = vec![];
|
||||
for path in paths {
|
||||
|
@ -233,18 +246,12 @@ fn verify_config(config: &Config) -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
match &config.work_dir {
|
||||
Some(path) => format!("{}", path),
|
||||
None => {
|
||||
if cfg!(windows) {
|
||||
match env::var("TEMP") {
|
||||
Ok(val) => val,
|
||||
Err(_) => return Err(format!("cannot determine the default temp dir")),
|
||||
}
|
||||
} else {
|
||||
format!("/tmp/refractr")
|
||||
if let None = &config.work_dir {
|
||||
if cfg!(windows) {
|
||||
if let Err(e) = env::var("TEMP") {
|
||||
return Err(format!("cannot determine the default temp dir: {}", e));
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
if !&config.from.starts_with("ssh://")
|
||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -15,6 +15,8 @@ use crate::refractr::Refractr;
|
|||
use clap::Parser;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
#[cfg(target_family = "windows")]
|
||||
use username;
|
||||
#[cfg(target_family = "unix")]
|
||||
|
@ -45,6 +47,13 @@ struct Args {
|
|||
help = "Exit on push and unknown host errors instead of ignoring them"
|
||||
)]
|
||||
strict: bool,
|
||||
|
||||
#[arg(
|
||||
short = 'p',
|
||||
long,
|
||||
help = "Do not clean the working directories specified in config(s)"
|
||||
)]
|
||||
persist: bool,
|
||||
}
|
||||
|
||||
fn get_config_default() -> &'static str {
|
||||
|
@ -72,10 +81,12 @@ fn main() -> Result<(), String> {
|
|||
},
|
||||
None => false,
|
||||
},
|
||||
persist: args.persist,
|
||||
pid: process::id(),
|
||||
strict: args.strict,
|
||||
unix: cfg!(unix),
|
||||
verbose: args.verbose,
|
||||
run: Arc::new(AtomicBool::new(true))
|
||||
};
|
||||
|
||||
// warn to avoid root/admin
|
||||
|
@ -125,7 +136,7 @@ fn main() -> Result<(), String> {
|
|||
let mut cfgs = vec![];
|
||||
match config::read_config(args.config, &refractr) {
|
||||
Ok(c) => cfgs = c,
|
||||
Err(e) => common::error(format!("{}", e), common::ExitCode::ConfigError),
|
||||
Err(e) => common::error_quit(format!("{}", e), common::ExitCode::ConfigError),
|
||||
};
|
||||
|
||||
if refractr.verbose >= 2 {
|
||||
|
@ -142,7 +153,7 @@ fn main() -> Result<(), String> {
|
|||
);
|
||||
match refractr.run(cfgs) {
|
||||
Ok(_) => (),
|
||||
Err(e) => common::error(format!("{}", e.msg), e.code),
|
||||
Err(e) => common::error_quit(format!("{}", e.msg), e.code),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
181
src/refractr.rs
181
src/refractr.rs
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
use crate::common::{self, ExitCode, ReturnData};
|
||||
use crate::config::{Config, ConfigFile};
|
||||
use crate::config::{self, Config, ConfigFile};
|
||||
|
||||
use git2::build::RepoBuilder;
|
||||
use git2::string_array::StringArray;
|
||||
|
@ -15,8 +15,7 @@ use git2::{CertificateCheckStatus, Cred, FetchOptions, PushOptions, RemoteCallba
|
|||
use git2::{Error, ErrorCode};
|
||||
use hex;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::fs::{self, remove_dir_all};
|
||||
use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
@ -25,22 +24,23 @@ use std::time;
|
|||
|
||||
pub struct Refractr {
|
||||
pub docker: bool,
|
||||
pub persist: bool,
|
||||
pub pid: u32,
|
||||
pub strict: bool,
|
||||
pub unix: bool,
|
||||
pub verbose: u8,
|
||||
pub run: Arc<AtomicBool>
|
||||
}
|
||||
|
||||
struct OpenedRepository {
|
||||
repo: Repository,
|
||||
path: String,
|
||||
remotes: Vec<String>,
|
||||
cfg: Config,
|
||||
ssh: bool,
|
||||
}
|
||||
|
||||
impl Refractr {
|
||||
fn set_up_work_dir(&self, work_dir: PathBuf) -> Result<String, String> {
|
||||
fn set_up_work_dir(&self, work_dir: PathBuf) -> Result<(), String> {
|
||||
if let Err(e) = fs::create_dir_all(&work_dir) {
|
||||
return Err(format!(
|
||||
"could not create working directory: {}: {}",
|
||||
|
@ -48,7 +48,7 @@ impl Refractr {
|
|||
e
|
||||
));
|
||||
}
|
||||
Ok(work_dir.to_string_lossy().to_string())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_up_ssh(&self, key_path: String, strict: bool) -> Result<RemoteCallbacks, String> {
|
||||
|
@ -57,7 +57,7 @@ impl Refractr {
|
|||
cb.certificate_check(move |cert, url| {
|
||||
let sha256 = hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec());
|
||||
if strict {
|
||||
common::error(
|
||||
common::error_quit(
|
||||
format!(
|
||||
"unknown host {} with sha256 host key {}, exiting",
|
||||
url, sha256
|
||||
|
@ -91,11 +91,10 @@ impl Refractr {
|
|||
refs_branches
|
||||
}
|
||||
|
||||
fn fast_forward(&self, repo_dir: &str, branches: &Vec<String>) -> Result<(), Error> {
|
||||
let repo = Repository::open(repo_dir)?;
|
||||
|
||||
common::verbose(self.verbose, 2, format!("Pulling origin"));
|
||||
repo.find_remote("origin")?.fetch(&branches, None, None)?;
|
||||
fn fast_forward(&self, repo: &Repository, branches: &Vec<String>) -> Result<(), Error> {
|
||||
common::verbose(self.verbose, 2, format!("Fast forwarding repo"));
|
||||
let mut fo = FetchOptions::new();
|
||||
fo.download_tags(git2::AutotagOption::All);
|
||||
|
||||
for branch in branches {
|
||||
let refname = format!("refs/remotes/origin/{}", branch);
|
||||
|
@ -114,6 +113,7 @@ impl Refractr {
|
|||
ssh_key: &String,
|
||||
strict: bool,
|
||||
) -> Result<(), Error> {
|
||||
common::verbose(self.verbose, 2, format!("Fetching repo"));
|
||||
let mut fo = FetchOptions::new();
|
||||
if ssh {
|
||||
match self.set_up_ssh(ssh_key.clone(), strict.clone()) {
|
||||
|
@ -121,7 +121,7 @@ impl Refractr {
|
|||
fo.remote_callbacks(cb);
|
||||
()
|
||||
},
|
||||
Err(e) => common::error(
|
||||
Err(e) => common::error_quit(
|
||||
format!("error setting up ssh: {}", e),
|
||||
ExitCode::ConfigError,
|
||||
),
|
||||
|
@ -196,7 +196,7 @@ impl Refractr {
|
|||
po.remote_callbacks(cb);
|
||||
()
|
||||
},
|
||||
Err(e) => common::error(
|
||||
Err(e) => common::error_quit(
|
||||
format!("error setting up ssh: {}", e),
|
||||
ExitCode::ConfigError,
|
||||
),
|
||||
|
@ -295,15 +295,15 @@ impl Refractr {
|
|||
&repos[i].cfg.git.ssh_identity_file,
|
||||
self.strict.clone(),
|
||||
) {
|
||||
common::error(
|
||||
common::error_quit(
|
||||
format!("failed to fetch repo {}: {}", repos[i].cfg.from, e),
|
||||
ExitCode::FetchError,
|
||||
);
|
||||
}
|
||||
|
||||
let _ = self.fast_forward(&repos[i].path, &repos[i].cfg.branches);
|
||||
let _ = self.fast_forward(&repos[i].repo, &repos[i].cfg.branches);
|
||||
if let Err(e) = self.push_remotes(&repos[i].cfg, &repos[i].repo, &repos[i].remotes) {
|
||||
common::error(e, ExitCode::PushError)
|
||||
common::error_quit(e, ExitCode::PushError)
|
||||
};
|
||||
current_ints[i] = original_ints[i].clone();
|
||||
}
|
||||
|
@ -323,37 +323,43 @@ impl Refractr {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn clean(&self, dirs: Vec<String>) -> Result<(), ReturnData> {
|
||||
for dir in dirs {
|
||||
common::verbose(self.verbose, 1, format!("removing working dir {}", dir));
|
||||
if let Err(e) = remove_dir_all(&dir) {
|
||||
common::warning(format!("could not clean up working dir: {}: {}", dir, e));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run(&self, cfgs: Vec<ConfigFile>) -> Result<(), ReturnData> {
|
||||
let r = self.run.clone();
|
||||
ctrlc::set_handler(move ||
|
||||
r.store(true, Ordering::SeqCst)
|
||||
).expect("failed to set ^c handler");
|
||||
|
||||
common::verbose(self.verbose, 3, format!("Starting main refractr loop"));
|
||||
let mut loop_repos = Vec::new();
|
||||
let mut work_dirs = Vec::new();
|
||||
|
||||
for cfg in cfgs {
|
||||
// set up the working directory
|
||||
common::verbose(self.verbose, 3, format!("Loading config: {}", cfg.path));
|
||||
let work_dir = self.set_up_work_dir(match &cfg.config.work_dir {
|
||||
None => {
|
||||
if cfg!(windows) {
|
||||
PathBuf::from(format!("{}\\refractr", env::var("TEMP").unwrap()))
|
||||
} else {
|
||||
PathBuf::from("/tmp/refractr")
|
||||
}
|
||||
},
|
||||
Some(path) => PathBuf::from(path),
|
||||
});
|
||||
let path_str = match work_dir {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
return Err(ReturnData {
|
||||
code: ExitCode::FilesystemError,
|
||||
msg: e,
|
||||
})
|
||||
},
|
||||
};
|
||||
let work_dir = config::get_work_dir(&cfg.config.work_dir);
|
||||
if let Err(e) = self.set_up_work_dir(PathBuf::from(&work_dir)) {
|
||||
return Err(ReturnData {
|
||||
msg: e,
|
||||
code: ExitCode::FilesystemError,
|
||||
});
|
||||
}
|
||||
common::verbose(
|
||||
self.verbose,
|
||||
2,
|
||||
format!("Created working directory: {}", &path_str),
|
||||
format!("Created working directory: {}", work_dir),
|
||||
);
|
||||
|
||||
let repo_name = match &cfg.config.from.split("/").last() {
|
||||
Some(split) => split.to_string(),
|
||||
None => {
|
||||
|
@ -378,7 +384,7 @@ impl Refractr {
|
|||
fo.remote_callbacks(cb);
|
||||
()
|
||||
},
|
||||
Err(e) => common::error(
|
||||
Err(e) => common::error_quit(
|
||||
format!("error setting up ssh: {}", e),
|
||||
ExitCode::ConfigError,
|
||||
),
|
||||
|
@ -387,7 +393,7 @@ impl Refractr {
|
|||
fo.download_tags(git2::AutotagOption::All);
|
||||
builder.fetch_options(fo);
|
||||
|
||||
let repo_dir = format!("{}{}{}", &path_str, MAIN_SEPARATOR_STR, repo_name);
|
||||
let repo_dir = format!("{}{}{}", &work_dir, MAIN_SEPARATOR_STR, repo_name);
|
||||
common::verbose(
|
||||
self.verbose,
|
||||
1,
|
||||
|
@ -397,7 +403,7 @@ impl Refractr {
|
|||
Ok(repo) => repo,
|
||||
Err(e) => {
|
||||
if e.code() != ErrorCode::Exists {
|
||||
common::error(
|
||||
common::error_quit(
|
||||
format!("failed to clone repo to {}: {}", repo_dir, e),
|
||||
ExitCode::FilesystemError,
|
||||
);
|
||||
|
@ -406,15 +412,51 @@ impl Refractr {
|
|||
"found existing repo at {}, attempting to use",
|
||||
repo_dir
|
||||
));
|
||||
match self.fast_forward(&repo_dir, &cfg.config.branches) {
|
||||
Ok(_) => {
|
||||
if let Ok(repo) = Repository::open(Path::new(&repo_dir)) {
|
||||
repo
|
||||
} else {
|
||||
return Err(ReturnData {
|
||||
code: ExitCode::RepositoryError,
|
||||
msg: format!("failed to obtain existing repo"),
|
||||
});
|
||||
match Repository::open(Path::new(&repo_dir)) {
|
||||
Ok(r) => {
|
||||
if let Ok(rem) = r.find_remote("origin") {
|
||||
match rem.url() {
|
||||
Some(url) => {
|
||||
if url != &cfg.config.from {
|
||||
return Err(ReturnData {
|
||||
code: ExitCode::RepositoryError,
|
||||
msg: format!(
|
||||
"existing repo's origin does not match 'from' value in config: {}",
|
||||
url
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(ReturnData {
|
||||
code: ExitCode::RepositoryError,
|
||||
msg: format!("could not obtain existing repo's origin: {}", repo_dir),
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
// fetch updates for the repo
|
||||
if let Err(e) = self.fetch(
|
||||
&r,
|
||||
&cfg.config.branches,
|
||||
ssh,
|
||||
&cfg.config.git.ssh_identity_file,
|
||||
self.strict.clone(),
|
||||
) {
|
||||
common::error_quit(
|
||||
format!("failed to fetch repo {}: {}", cfg.config.from, e),
|
||||
ExitCode::FetchError,
|
||||
);
|
||||
}
|
||||
// fast forward
|
||||
match self.fast_forward(&r, &cfg.config.branches) {
|
||||
Ok(_) => r,
|
||||
Err(e) => {
|
||||
return Err(ReturnData {
|
||||
code: ExitCode::RepositoryError,
|
||||
msg: format!("failed to fast forward existing repo: {}", e),
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
|
@ -428,23 +470,11 @@ impl Refractr {
|
|||
};
|
||||
|
||||
if let Err(e) = self.set_up_refs(&repo, &cfg.config.branches) {
|
||||
common::error(
|
||||
common::error_quit(
|
||||
format!("failed to set up refs: {}", e),
|
||||
ExitCode::RepositoryError,
|
||||
);
|
||||
}
|
||||
if let Err(e) = self.fetch(
|
||||
&repo,
|
||||
&cfg.config.branches,
|
||||
ssh,
|
||||
&cfg.config.git.ssh_identity_file,
|
||||
self.strict.clone(),
|
||||
) {
|
||||
common::error(
|
||||
format!("failed to fetch repo {}: {}", cfg.config.from, e),
|
||||
ExitCode::FetchError,
|
||||
);
|
||||
}
|
||||
|
||||
let remotes = match self.make_remotes(&repo, &cfg) {
|
||||
Ok(v) => v,
|
||||
|
@ -455,21 +485,33 @@ impl Refractr {
|
|||
})
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(e) = self.push_remotes(&cfg.config, &repo, &remotes) {
|
||||
common::error(e, ExitCode::PushError);
|
||||
common::error_quit(e, ExitCode::PushError);
|
||||
}
|
||||
|
||||
if cfg.config.schedule.enabled {
|
||||
loop_repos.push(OpenedRepository {
|
||||
repo,
|
||||
path: repo_dir,
|
||||
remotes,
|
||||
cfg: cfg.config,
|
||||
ssh,
|
||||
});
|
||||
if !work_dirs.contains(&work_dir) {
|
||||
work_dirs.push(work_dir);
|
||||
}
|
||||
} else {
|
||||
if let Err(e) = self.clean(vec![work_dir]) {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
if self.run.load(Ordering::SeqCst) {
|
||||
common::error_quit(format!("exiting"), ExitCode::HaltError);
|
||||
}
|
||||
}
|
||||
// end for
|
||||
|
||||
let mut result = Ok(());
|
||||
if loop_repos.len() >= 1 {
|
||||
common::verbose(
|
||||
self.verbose,
|
||||
|
@ -479,7 +521,7 @@ impl Refractr {
|
|||
loop_repos.len()
|
||||
),
|
||||
);
|
||||
return self.looper(loop_repos);
|
||||
result = self.looper(loop_repos);
|
||||
} else {
|
||||
common::verbose(
|
||||
self.verbose,
|
||||
|
@ -488,6 +530,13 @@ impl Refractr {
|
|||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
if !self.persist {
|
||||
match result {
|
||||
Ok(()) => return self.clean(work_dirs),
|
||||
Err(_) => result = self.clean(work_dirs),
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue