Compare commits

...

10 commits

13 changed files with 518 additions and 245 deletions

266
Cargo.lock generated
View file

@ -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.0"
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",

View file

@ -1,7 +1,7 @@
[package]
name = "refractr"
license = "MPL-2.0"
version = "0.6.0"
version = "0.6.2"
edition = "2021"
[dependencies]

View file

@ -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
View file

@ -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
View 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"]

View 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
View 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 Normal file
View file

@ -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

View file

@ -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"]

View file

@ -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)
}

View file

@ -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://")

View file

@ -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")]
@ -39,8 +41,19 @@ struct Args {
)]
create: bool,
#[arg(short = 's', long, help = "Exit on push errors instead of ignoring")]
#[arg(
short = 's',
long,
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 {
@ -68,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
@ -121,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 {
@ -138,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(())

View file

@ -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,21 +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: {}: {}",
@ -47,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> {
@ -56,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
@ -90,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);
@ -113,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()) {
@ -120,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,
),
@ -195,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,
),
@ -287,10 +288,22 @@ impl Refractr {
2,
format!("Interval for {} has arrived, pulling", repos[i].cfg.from),
);
if let Err(e) = self.fetch(
&repos[i].repo,
&repos[i].cfg.branches,
repos[i].ssh,
&repos[i].cfg.git.ssh_identity_file,
self.strict.clone(),
) {
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();
}
@ -310,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 => {
@ -365,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,
),
@ -374,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,
@ -384,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,
);
@ -393,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) => {
@ -415,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,
@ -442,20 +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,
@ -465,7 +521,7 @@ impl Refractr {
loop_repos.len()
),
);
return self.looper(loop_repos);
result = self.looper(loop_repos);
} else {
common::verbose(
self.verbose,
@ -474,6 +530,13 @@ impl Refractr {
);
}
Ok(())
if !self.persist {
match result {
Ok(()) => return self.clean(work_dirs),
Err(_) => result = self.clean(work_dirs),
}
}
result
}
}