git flow was a mistake #11

Merged
cafkafk merged 29 commits from dev into main 2023-08-09 16:27:57 +02:00
14 changed files with 978 additions and 541 deletions

557
Cargo.lock generated
View file

@ -4,13 +4,19 @@ version = 3
[[package]]
name = "aho-corasick"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
dependencies = [
"memchr",
]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
version = "0.3.2"
@ -28,15 +34,15 @@ dependencies = [
[[package]]
name = "anstyle"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "anstyle-parse"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
@ -68,15 +74,30 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
[[package]]
name = "bumpalo"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.0.79"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
@ -85,10 +106,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.3.2"
name = "ciborium"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "401a4694d2bf92537b6867d94de48c4842089645fdcdf6c71865b175d836e9c2"
checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
[[package]]
name = "ciborium-ll"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
dependencies = [
"ciborium-io",
"half",
]
[[package]]
name = "clap"
version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
dependencies = [
"clap_builder",
"clap_derive",
@ -97,13 +145,12 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.3.1"
version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980"
checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
dependencies = [
"anstream",
"anstyle",
"bitflags",
"clap_lex",
"once_cell",
"strsim",
@ -111,14 +158,14 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.3.2"
version = "4.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.18",
"syn 2.0.28",
]
[[package]]
@ -143,6 +190,91 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "criterion"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
"cast",
"ciborium",
"clap",
"criterion-plot",
"is-terminal",
"itertools",
"num-traits",
"once_cell",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "env_logger"
version = "0.10.0"
@ -157,10 +289,16 @@ dependencies = [
]
[[package]]
name = "errno"
version = "0.3.1"
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [
"errno-dragonfly",
"libc",
@ -178,24 +316,16 @@ dependencies = [
]
[[package]]
name = "gg"
version = "0.2.0"
dependencies = [
"clap",
"clap_mangen",
"log",
"pretty_env_logger",
"relative-path",
"serde",
"serde_yaml",
"spinners",
]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
version = "0.12.3"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "heck"
@ -205,9 +335,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "humantime"
@ -217,42 +347,48 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "indexmap"
version = "1.9.3"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [
"autocfg",
"equivalent",
"hashbrown",
]
[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]]
name = "is-terminal"
version = "0.4.7"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]]
name = "itoa"
version = "1.0.6"
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "js-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
@ -262,24 +398,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.144"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
name = "maplit"
@ -294,10 +427,72 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "once_cell"
version = "1.17.1"
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "num-traits"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "plotters"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
[[package]]
name = "plotters-svg"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
dependencies = [
"plotters-backend",
]
[[package]]
name = "pretty_env_logger"
@ -311,27 +506,61 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.59"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.28"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.8.3"
name = "rayon"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "regex"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
dependencies = [
"aho-corasick",
"memchr",
@ -340,9 +569,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.7.2"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
[[package]]
name = "relative-path"
@ -358,13 +587,12 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
[[package]]
name = "rustix"
version = "0.37.19"
version = "0.38.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
@ -372,41 +600,82 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.12"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.13"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "seidr"
version = "0.2.0"
dependencies = [
"clap",
"clap_mangen",
"criterion",
"log",
"pretty_env_logger",
"relative-path",
"serde",
"serde_yaml",
"spinners",
]
[[package]]
name = "serde"
version = "1.0.163"
version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.163"
version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.18",
"syn 2.0.28",
]
[[package]]
name = "serde_json"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.21"
version = "0.9.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c"
checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574"
dependencies = [
"indexmap",
"itoa",
@ -467,9 +736,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.18"
version = "2.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
dependencies = [
"proc-macro2",
"quote",
@ -486,16 +755,26 @@ dependencies = [
]
[[package]]
name = "unicode-ident"
version = "1.0.9"
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "unsafe-libyaml"
version = "0.2.8"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6"
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
[[package]]
name = "utf8parse"
@ -503,6 +782,80 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "walkdir"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.28",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.28",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
@ -545,9 +898,9 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.48.0"
version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",

View file

@ -1,14 +1,14 @@
[package]
name = "gg"
name = "seidr"
version = "0.2.0"
authors = ["Christina Sørensen"]
edition = "2021"
rust-version = "1.72.0"
rust-version = "1.70.0"
description = "A Rust GitOps/symlinkfarm orchestrator inspired by GNU Stow."
documentation = "https://github.com/cafkafk/gg"
documentation = "https://github.com/cafkafk/seidr"
readme = "./README.org"
homepage = "https://github.com/cafkafk/gg"
repository = "https://github.com/cafkafk/gg"
homepage = "https://github.com/cafkafk/seidr"
repository = "https://github.com/cafkafk/seidr"
license = "GPL-3.0-only"
keywords = ["git", "declarative", "cli", "devops", "terminal"]
categories = ["command-line-interface", "command-line-utilities"]
@ -16,8 +16,8 @@ categories = ["command-line-interface", "command-line-utilities"]
# build = "build.rs"
# links = "git2"
# exclude = "./vacation_photos"
# include = "./gg_memes"
publish = false
# include = "./seidr_memes"
# publish = false
# metadata
# deafult-run
# autobins
@ -52,3 +52,11 @@ strip = true
lto = "fat"
opt-level = 3
codegen-units = 1
[dev-dependencies]
criterion = { version = "0.5.1", features = ["html_reports"] }
[[bench]]
name = "basic_bench" # I'm just a basic bench, nothing fancy :p
harness = false

View file

@ -1,5 +1,5 @@
#+options: toc:nil
* gg - git gut
* Seiðr
#+html: <img src="https://img.shields.io/badge/license-GPLv3-blue"><img src="https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg">
A Rust GitOps/symlinkfarm orchestrator inspired by GNU Stow. Useful for dealing
@ -19,16 +19,16 @@ commit).
** Installation
#+begin_src sh
$ git clone https://github.com/cafkafk/gg
$ cd gg
$ git clone https://github.com/cafkafk/seidr
$ cd seidr
$ cargo install --path .
#+end_src
** Configuration
If you want a template, you can copy the file from src/test/config.yaml:
#+begin_src sh
$ mkdir -p ~/.config/gg/
$ cp src/test/config.yaml ~/.config/gg/config.yaml
$ mkdir -p ~/.config/seidr/
$ cp src/test/config.yaml ~/.config/seidr/config.yaml
#+end_src
You should *seriously* change this file before running any commands.

16
benches/basic_bench.rs Normal file
View file

@ -0,0 +1,16 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use seidr::git::Config;
use relative_path::RelativePath;
pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("config loading time", |b| {
b.iter(|| {
Config::new(black_box(
&RelativePath::new(black_box("./src/test/config.yaml")).to_string(),
))
});
});
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

View file

@ -6,7 +6,7 @@
There were 3 major designs considered so far (here in chronological order).
**** Vec Based
Code sketch in https://github.com/cafkafk/gg/commit/3d3b6d6646bda84333018cd621cd8bd6348b9cef
Code sketch in https://github.com/cafkafk/seidr/commit/3d3b6d6646bda84333018cd621cd8bd6348b9cef
#+begin_src mermaid :file ./doc/img/config-struct-vec.png :width 4000px
flowchart LR

View file

@ -1,5 +1,8 @@
#+title: Roadmap
* 0.2.1
- [X] jumps
- [-] repo and category selecting for subcommands
* 0.2.0 (maybe)
- [X] Links in categories?
- [X] Fix category with no links

View file

@ -21,7 +21,7 @@ use crate::utils::strings::INTERACTIVE_NOTICE;
use clap::{ArgAction, CommandFactory, Parser, Subcommand};
const CONFIG_FILE: &str = "/.config/gg/config.yaml";
const CONFIG_FILE: &str = "/.config/seidr/config.yaml";
const HELP_TEMPLATE: &str = "\
{before-help}{name} {version}
@ -36,7 +36,7 @@ const HELP_TEMPLATE: &str = "\
//#[clap(author, version, about, long_about = None)]
#[derive(Parser, Debug)]
#[clap(
name="gg - git gut",
name="seidr - git gut",
author,
version,
long_version=env!("CARGO_PKG_VERSION"),
@ -72,6 +72,9 @@ pub struct Args {
#[arg(short, long)]
pub no_emoji: bool,
#[arg(short, long)]
pub message: Option<String>,
#[command(subcommand)]
pub command: Option<Commands>,
}
@ -80,33 +83,51 @@ pub struct Args {
pub enum Commands {
/// Link all... links
#[command(visible_alias = "l")]
Link { msg: Option<String> },
Link {},
/// Do quick pull-commit-push with msg for commit
#[command(visible_alias = "q")]
Quick { msg: Option<String> },
Quick {
category: Option<String>,
repo: Option<String>,
},
/// Do fast pull-commit-push with msg for commit, skipping repo on failure
#[command(visible_alias = "f")]
Fast { msg: Option<String> },
Fast {},
/// Clone all repositories
#[command(visible_alias = "c")]
Clone { msg: Option<String> },
Clone {},
/// Pull all repositories
#[command(visible_alias = "p")]
Pull { msg: Option<String> },
Pull {},
/// Add all files in repositories
#[command(visible_alias = "a")]
Add { msg: Option<String> },
Add {},
/// Perform a git commit in all repositories
#[command(visible_alias = "ct")]
Commit { msg: Option<String> },
Commit {},
/// Perform a git commit in all repositories, with predefined message
#[command(visible_alias = "m")]
CommitMsg { msg: Option<String> },
CommitMsg {},
/// Jump to a given object
#[command(subcommand, visible_alias = "j")]
Jump(JumpCommands),
}
#[derive(Subcommand, Debug)]
pub enum JumpCommands {
/// Jump to repo
#[command(visible_alias = "r")]
Repo { category: String, name: String },
/// Jump to link
#[command(visible_alias = "l")]
Link { category: String, name: String },
}

View file

@ -30,6 +30,7 @@ use crate::utils::strings::{failure_str, success_str};
/// An enum containing flags that change behaviour of repos and categories
#[derive(PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[non_exhaustive]
pub enum RepoFlags {
/// If clone is set, the repository should respond to the clone subcommand
Clone,
@ -51,6 +52,17 @@ pub enum RepoFlags {
Fast,
}
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug)]
#[non_exhaustive]
pub enum RepoKinds {
GitRepo,
GitHubRepo,
GitLabRepo,
GiteaRepo,
UrlRepo,
Link,
}
/// Represents the config.toml file.
///
/// For diagrams of the underlying architecture, consult ARCHITECHTURE.md
@ -73,7 +85,7 @@ pub struct Category {
///
/// Key should conceptually be seen as the name of the category.
#[serde(skip_serializing_if = "Option::is_none")]
pub repos: Option<HashMap<String, GitRepo>>,
pub repos: Option<HashMap<String, Repo>>,
/// map of all links in category
///
@ -93,30 +105,24 @@ pub struct Link {
/// Holds a single git repository and related fields.
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct GitRepo {
pub name: String,
pub path: String,
pub url: String,
pub struct Repo {
pub name: Option<String>,
pub path: Option<String>,
pub url: Option<String>,
// TODO: make default a standard GitRepo
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<RepoKinds>, // FIXME: not implemented
pub flags: Option<Vec<RepoFlags>>,
}
////////////////////////////////////
////////////////////////////////////
////////////////////////////////////
/// Represents a single operation on a repository
pub struct SeriesItem<'series> {
/// The string to be displayed to the user
operation: &'series str,
pub operation: &'series str,
/// The closure representing the actual operation
closure: Box<dyn Fn(&GitRepo) -> (bool)>,
pub closure: Box<dyn Fn(&Repo) -> (bool)>,
}
////////////////////////////////////
////////////////////////////////////
////////////////////////////////////
fn handle_file_exists(selff: &Link, tx_path: &Path, rx_path: &Path) -> bool {
match rx_path.read_link() {
Ok(file)
@ -169,31 +175,34 @@ impl Link {
}
}
impl GitRepo {
impl Repo {
/// Clones the repository to its specified folder.
fn clone(&self) -> bool {
pub fn clone(&self) -> bool {
if self
.flags
.as_ref()
.expect("failed to unwrap flags")
.contains(&RepoFlags::Clone)
{
// TODO: check if &self.name already exists in dir
// TODO: check if &self.name.as_ref() already exists in dir
let output = Command::new("git")
.current_dir(&self.path)
.current_dir(self.path.as_ref().unwrap())
.arg("clone")
.arg(&self.url)
.arg(&self.name)
.arg(self.url.as_ref().unwrap())
.arg(self.name.as_ref().unwrap())
.output()
.unwrap_or_else(|_| panic!("git repo failed to clone: {:?}", &self,));
output.status.success()
} else {
info!("{} has clone set to false, not cloned", &self.name);
info!(
"{} has clone set to false, not cloned",
&self.name.as_ref().unwrap()
);
false
}
}
/// Pulls the repository if able.
fn pull(&self) -> bool {
pub fn pull(&self) -> bool {
if self
.flags
.as_ref()
@ -202,18 +211,25 @@ impl GitRepo {
.any(|s| s == &RepoFlags::Pull || s == &RepoFlags::Fast)
{
let output = Command::new("git")
.current_dir(format!("{}{}", &self.path, &self.name))
.current_dir(format!(
"{}{}",
&self.path.as_ref().unwrap(),
&self.name.as_ref().unwrap()
))
.arg("pull")
.output()
.unwrap_or_else(|_| panic!("git repo failed to pull: {:?}", &self,));
output.status.success()
} else {
info!("{} has clone set to false, not pulled", &self.name);
info!(
"{} has clone set to false, not pulled",
&self.name.as_ref().unwrap()
);
false
}
}
/// Adds all files in the repository.
fn add_all(&self) -> bool {
pub fn add_all(&self) -> bool {
if self
.flags
.as_ref()
@ -222,14 +238,21 @@ impl GitRepo {
.any(|s| s == &RepoFlags::Add || s == &RepoFlags::Quick || s == &RepoFlags::Fast)
{
let output = Command::new("git")
.current_dir(format!("{}{}", &self.path, &self.name))
.current_dir(format!(
"{}{}",
&self.path.as_ref().unwrap(),
&self.name.as_ref().unwrap()
))
.arg("add")
.arg(".")
.output()
.unwrap_or_else(|_| panic!("git repo failed to add: {:?}", &self,));
output.status.success()
} else {
info!("{} has clone set to false, not cloned", &self.name);
info!(
"{} has clone set to false, not cloned",
&self.name.as_ref().unwrap()
);
false
}
}
@ -241,7 +264,7 @@ impl GitRepo {
/// use status() instead of output(), as that makes using the native editor
/// easy
#[allow(dead_code)]
fn commit(&self) -> bool {
pub fn commit(&self) -> bool {
if self
.flags
.as_ref()
@ -250,18 +273,25 @@ impl GitRepo {
.any(|s| s == &RepoFlags::Commit || s == &RepoFlags::Quick || s == &RepoFlags::Fast)
{
let status = Command::new("git")
.current_dir(format!("{}{}", &self.path, &self.name))
.current_dir(format!(
"{}{}",
&self.path.as_ref().unwrap(),
&self.name.as_ref().unwrap()
))
.arg("commit")
.status()
.unwrap_or_else(|_| panic!("git repo failed to commit: {:?}", &self,));
status.success()
} else {
info!("{} has push set to false, not cloned", &self.name);
info!(
"{} has push set to false, not cloned",
&self.name.as_ref().unwrap()
);
false
}
}
/// Tries to commit changes with a message argument.
fn commit_with_msg(&self, msg: &str) -> bool {
pub fn commit_with_msg(&self, msg: &str) -> bool {
if self
.flags
.as_ref()
@ -270,7 +300,11 @@ impl GitRepo {
.any(|s| s == &RepoFlags::Commit || s == &RepoFlags::Quick || s == &RepoFlags::Fast)
{
let output = Command::new("git")
.current_dir(format!("{}{}", &self.path, &self.name))
.current_dir(format!(
"{}{}",
&self.path.as_ref().unwrap(),
&self.name.as_ref().unwrap()
))
.arg("commit")
.arg("-m")
.arg(msg)
@ -278,12 +312,15 @@ impl GitRepo {
.unwrap_or_else(|_| panic!("git repo failed to commit: {:?}", &self,));
output.status.success()
} else {
info!("{} has clone set to false, not cloned", &self.name);
info!(
"{} has clone set to false, not cloned",
&self.name.as_ref().unwrap()
);
false
}
}
/// Attempts to push the repository.
fn push(&self) -> bool {
pub fn push(&self) -> bool {
if self
.flags
.as_ref()
@ -292,13 +329,20 @@ impl GitRepo {
.any(|s| s == &RepoFlags::Push || s == &RepoFlags::Quick || s == &RepoFlags::Fast)
{
let output = Command::new("git")
.current_dir(format!("{}{}", &self.path, &self.name))
.current_dir(format!(
"{}{}",
&self.path.as_ref().unwrap(),
&self.name.as_ref().unwrap()
))
.arg("push")
.output()
.unwrap_or_else(|_| panic!("git repo failed to push: {:?}", &self,));
output.status.success()
} else {
info!("{} has clone set to false, not cloned", &self.name);
info!(
"{} has clone set to false, not cloned",
&self.name.as_ref().unwrap()
);
false
}
}
@ -308,8 +352,118 @@ impl GitRepo {
fn remove() -> Result<(), std::io::Error> {
// https://doc.rust-lang.org/std/fs/fn.remove_dir_all.html
unimplemented!("This seems to easy to missuse/exploit");
// fs::remove_dir_all(format!("{}{}", &self.path, &self.name))
// fs::remove_dir_all(format!("{}{}", &self.path.as_ref(), &self.name.as_ref()))
}
fn check_is_valid_gitrepo(&self) -> bool {
if (self.name.is_none()) {
eprintln!("{:?} must have name: <string>", self.kind);
return false;
}
if (self.path.is_none()) {
eprintln!("{:?} must have path: <string>", self.kind);
return false;
}
if (self.url.is_none()) {
eprintln!("{:?} must have url: <string>", self.kind);
return false;
}
assert!(self.name.is_some());
assert!(self.path.is_some());
assert!(self.url.is_some());
true
}
fn check_is_valid_githubrepo(&self) -> bool {
todo!();
}
fn check_is_valid_gitlabrepo(&self) -> bool {
todo!();
}
fn check_is_valid_gitearepo(&self) -> bool {
todo!();
}
fn check_is_valid_urlrepo(&self) -> bool {
todo!();
}
fn check_is_valid_link(&self) -> bool {
todo!();
}
/// Check if Repo is a valid instance of its kind
pub fn is_valid_kind(&self) -> bool {
use RepoKinds::*;
match &self.kind {
Some(GitRepo) => self.check_is_valid_gitrepo(),
Some(GitHubRepo) => self.check_is_valid_githubrepo(),
Some(GitLabRepo) => self.check_is_valid_gitlabrepo(),
Some(GiteaRepo) => self.check_is_valid_gitearepo(),
Some(UrlRepo) => self.check_is_valid_urlrepo(),
Some(Link) => self.check_is_valid_link(),
Some(kind) => {
panic!("kind {kind:?} not implemented");
false
}
None => {
println!("unknown kind {:?}", self.kind);
false
}
}
}
}
/// run_series runs a closure series on a Config struct
///
/// # Examples
///
///
/// ```
/// use seidr::git;
/// use seidr::git::Repo;
/// use seidr::git::Config;
/// use std::env::current_dir;
/// use seidr::git::SeriesItem;
/// use relative_path::RelativePath;
///
/// let root = current_dir().expect("failed to get current dir");
/// let config = Config::new(
/// &RelativePath::new("./src/test/config.yaml")
/// .to_logical_path(root)
/// .into_os_string()
/// .into_string()
/// .expect("failed to turnn config into string"),
/// );
///
/// let series: Vec<SeriesItem> = vec![
/// SeriesItem {
/// operation: "pull",
/// closure: Box::new(move |repo: &Repo| repo.pull()),
/// },
/// SeriesItem {
/// operation: "add",
/// closure: Box::new(move |repo: &Repo| repo.add_all()),
/// },
/// SeriesItem {
/// operation: "commit",
/// closure: Box::new(move |repo: &Repo| repo.commit()),
/// },
/// SeriesItem {
/// operation: "push",
/// closure: Box::new(move |repo: &Repo| repo.push()),
/// },
/// ];
///
/// // If we don't care if the series steps fail
/// run_series!(config, series);
///
/// // If we want to skip repo as soon as a step fails
/// run_series!(config, series, true);
/// ```
#[macro_export]
macro_rules! run_series {
($conf:ident, $closures:ident) => {
$conf.all_on_all($closures, false);
};
($conf:ident, $closures:ident, $stop_on_err:tt) => {
$conf.all_on_all($closures, $stop_on_err);
};
}
impl Config {
@ -332,7 +486,7 @@ impl Config {
/// NOTE: currently unused
fn on_all<F>(&self, f: F)
where
F: Fn(&GitRepo),
F: Fn(&Repo),
{
for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
@ -343,16 +497,16 @@ impl Config {
// /// Runs associated function on all repos in config
// fn on_all_spinner<F>(&self, op: &str, f: F)
// where
// F: Fn(&GitRepo) -> bool,
// F: Fn(&Repo) -> bool,
// {
// for category in self.categories.values() {
// for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
// if !settings::QUIET.load(std::sync::atomic::Ordering::Relaxed) {
// let mut sp = Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
// let mut sp = Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name.as_ref(), op));
// if f(repo) {
// sp.stop_and_persist(success_str(), format!("{}: {}", repo.name, op));
// sp.stop_and_persist(success_str(), format!("{}: {}", repo.name.as_ref(), op));
// } else {
// sp.stop_and_persist(failure_str(), format!("{}: {}", repo.name, op));
// sp.stop_and_persist(failure_str(), format!("{}: {}", repo.name.as_ref(), op));
// }
// } else {
// f(repo);
@ -363,24 +517,26 @@ impl Config {
/// Runs associated function on all repos in config
fn on_all_repos_spinner<F>(&self, op: &str, f: F)
where
F: Fn(&GitRepo) -> bool,
F: Fn(&Repo) -> bool,
{
for category in self.categories.values() {
match category.repos.as_ref() {
Some(repos) => {
for repo in repos.values() {
if !settings::QUIET.load(std::sync::atomic::Ordering::Relaxed) {
let mut sp =
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
let mut sp = Spinner::new(
Spinners::Dots10,
format!("{}: {}", repo.name.as_ref().unwrap(), op),
);
if f(repo) {
sp.stop_and_persist(
success_str(),
format!("{}: {}", repo.name, op),
format!("{}: {}", repo.name.as_ref().unwrap(), op),
);
} else {
sp.stop_and_persist(
failure_str(),
format!("{}: {}", repo.name, op),
format!("{}: {}", repo.name.as_ref().unwrap(), op),
);
}
} else {
@ -426,69 +582,6 @@ impl Config {
}
/// Runs associated function on all repos in config
///
/// TODO: need to be made over a generic repo type
///
/// # Current Problem
///
/// The goal of this function is that it should run some function on all
/// repos but stop executing further functions on any repo that fails,
/// without blocking the repos that don't have an issue.
///
/// This is actually somewhat hairy to do, at least at 6:16 am :S
///
/// However, at 6:24, we're so ready! Let's go!
///
/// Fun fact: only the last element of a tuple must have a dynamically typed size
///
/// # Usage
///
/// Here is an example of how an associated method could use this function.
///
/// ```
/// let series: Vec<SeriesItem> = vec![
/// SeriesItem {
/// operation: "pull",
/// closure: Box::new(move |repo: &GitRepo| repo.pull()),
/// },
/// SeriesItem {
/// operation: "add",
/// closure: Box::new(move |repo: &GitRepo| repo.add_all()),
/// },
/// SeriesItem {
/// operation: "commit",
/// closure: Box::new(move |repo: &GitRepo| repo.commit()),
/// },
/// SeriesItem {
/// operation: "push",
/// closure: Box::new(move |repo: &GitRepo| repo.push()),
/// },
/// ];
/// self.series_on_all(series);
/// ```
pub fn series_on_all(&self, closures: Vec<SeriesItem>) {
for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
for instruction in &closures {
let f = &instruction.closure;
let op = instruction.operation;
if !settings::QUIET.load(std::sync::atomic::Ordering::Relaxed) {
let mut sp =
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
if f(repo) {
sp.stop_and_persist(success_str(), format!("{}: {}", repo.name, op));
} else {
sp.stop_and_persist(failure_str(), format!("{}: {}", repo.name, op));
break;
}
} else {
f(repo);
}
}
}
}
}
/// Runs associated function on all repos in config
///
/// Unlike `series_on_all`, this does not stop if it encounters an error
///
/// # Usage
@ -496,42 +589,71 @@ impl Config {
/// Here is an example of how an associated method could use this function.
///
/// ```
/// # use seidr::git::Repo;
/// # use seidr::git::SeriesItem;
///
/// let series: Vec<SeriesItem> = vec![
/// SeriesItem {
/// operation: "pull",
/// closure: Box::new(move |repo: &GitRepo| repo.pull()),
/// closure: Box::new(move |repo: &Repo| repo.pull()),
/// },
/// SeriesItem {
/// operation: "add",
/// closure: Box::new(move |repo: &GitRepo| repo.add_all()),
/// closure: Box::new(move |repo: &Repo| repo.add_all()),
/// },
/// SeriesItem {
/// operation: "commit",
/// closure: Box::new(move |repo: &GitRepo| repo.commit()),
/// closure: Box::new(move |repo: &Repo| repo.commit()),
/// },
/// SeriesItem {
/// operation: "push",
/// closure: Box::new(move |repo: &GitRepo| repo.push()),
/// closure: Box::new(move |repo: &Repo| repo.push()),
/// },
/// ];
/// self.all_on_all(series);
/// ```
pub fn all_on_all(&self, closures: Vec<SeriesItem>) {
pub fn all_on_all(&self, closures: Vec<SeriesItem>, break_on_err: bool) {
// HACK: creates a empty repo, that is used if a category doesn't have
// any repos or don't define the repo field
let tmp: HashMap<String, Repo> = HashMap::new();
for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
for instruction in &closures {
let f = &instruction.closure;
let op = instruction.operation;
if !settings::QUIET.load(std::sync::atomic::Ordering::Relaxed) {
let mut sp =
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
if f(repo) {
sp.stop_and_persist(success_str(), format!("{}: {}", repo.name, op));
} else {
sp.stop_and_persist(failure_str(), format!("{}: {}", repo.name, op));
// HACK: if the repo doesn't exist here, we inject tmp
for (_, repo) in category.repos.as_ref().unwrap_or(&tmp).iter() {
use RepoKinds::*;
match &repo.kind {
Some(GitRepo) => {
for instruction in &closures {
let f = &instruction.closure;
let op = instruction.operation;
if !settings::QUIET.load(std::sync::atomic::Ordering::Relaxed) {
let mut sp = Spinner::new(
Spinners::Dots10,
format!("{}: {}", repo.name.as_ref().unwrap(), op),
);
if f(repo) {
sp.stop_and_persist(
success_str(),
format!("{}: {}", repo.name.as_ref().unwrap(), op),
);
} else {
sp.stop_and_persist(
failure_str(),
format!("{}: {}", repo.name.as_ref().unwrap(), op),
);
if break_on_err {
break;
}
}
} else {
f(repo);
}
}
} else {
f(repo);
}
None => {
println!("unknown kind {:?}", repo.kind);
}
Some(kind) => {
println!("unknown kind {kind:?}");
}
}
}
@ -539,9 +661,9 @@ impl Config {
}
pub fn get_repo<F>(&self, cat_name: &str, repo_name: &str, f: F)
where
F: FnOnce(&GitRepo),
F: FnOnce(&Repo),
{
f(&self
f(self
.categories
.get(cat_name)
.expect("failed to get category")
@ -549,13 +671,13 @@ impl Config {
.as_ref()
.expect("failed to get repo")
.get(repo_name)
.expect("failed to get category"))
.expect("failed to get category"));
}
pub fn get_link<F>(&self, cat_name: &str, link_name: &str, f: F)
where
F: FnOnce(&Link),
{
f(&self
f(self
.categories
.get(cat_name)
.expect("failed to get category")
@ -563,30 +685,27 @@ impl Config {
.as_ref()
.expect("failed to get repo")
.get(link_name)
.expect("failed to get category"))
.expect("failed to get category"));
}
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Tries to pull all repositories, skips if fail.
pub fn pull_all(&self) {
debug!("exectuting pull_all");
self.on_all_repos_spinner("pull", GitRepo::pull);
self.on_all_repos_spinner("pull", Repo::pull);
}
/// Tries to clone all repossitories, skips if fail.
pub fn clone_all(&self) {
debug!("exectuting clone_all");
self.on_all_repos_spinner("clone", GitRepo::clone);
self.on_all_repos_spinner("clone", Repo::clone);
}
/// Tries to add all work in all repossitories, skips if fail.
pub fn add_all(&self) {
debug!("exectuting clone_all");
self.on_all_repos_spinner("add", GitRepo::add_all);
self.on_all_repos_spinner("add", Repo::add_all);
}
/// Tries to commit all repossitories one at a time, skips if fail.
pub fn commit_all(&self) {
debug!("exectuting clone_all");
self.on_all_repos_spinner("commit", GitRepo::commit);
self.on_all_repos_spinner("commit", Repo::commit);
}
/// Tries to commit all repossitories with msg, skips if fail.
pub fn commit_all_msg(&self, msg: &str) {
@ -600,22 +719,22 @@ impl Config {
let series: Vec<SeriesItem> = vec![
SeriesItem {
operation: "pull",
closure: Box::new(GitRepo::pull),
closure: Box::new(Repo::pull),
},
SeriesItem {
operation: "add",
closure: Box::new(GitRepo::add_all),
closure: Box::new(Repo::add_all),
},
SeriesItem {
operation: "commit",
closure: Box::new(move |repo: &GitRepo| repo.commit_with_msg(msg)),
closure: Box::new(move |repo: &Repo| repo.commit_with_msg(msg)),
},
SeriesItem {
operation: "push",
closure: Box::new(GitRepo::push),
closure: Box::new(Repo::push),
},
];
self.all_on_all(series);
run_series!(self, series);
}
/// Tries to pull, add all, commit with msg "quick commit", and push all
/// repositories, skips if fail.
@ -624,26 +743,23 @@ impl Config {
let series: Vec<SeriesItem> = vec![
SeriesItem {
operation: "pull",
closure: Box::new(GitRepo::pull),
closure: Box::new(Repo::pull),
},
SeriesItem {
operation: "add",
closure: Box::new(GitRepo::add_all),
closure: Box::new(Repo::add_all),
},
SeriesItem {
operation: "commit",
closure: Box::new(move |repo: &GitRepo| repo.commit_with_msg(msg)),
closure: Box::new(move |repo: &Repo| repo.commit_with_msg(msg)),
},
SeriesItem {
operation: "push",
closure: Box::new(GitRepo::push),
closure: Box::new(Repo::push),
},
];
self.series_on_all(series);
run_series!(self, series, true);
}
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Tries to link all repositories, skips if fail.
pub fn link_all(&self) {
debug!("exectuting link_all");

View file

@ -1,6 +0,0 @@
// #[allow(unused)]
// pub mod git;
// #[allow(unused)]
// mod settings;
// #[allow(unused)]
// mod utils;

6
src/lib.rs.old Normal file
View file

@ -0,0 +1,6 @@
#[allow(unused)]
pub mod git;
#[allow(unused)]
mod settings;
#[allow(unused)]
mod utils;

View file

@ -29,7 +29,7 @@
//! aren't introduced.
//!
//! That said, we're in 0.0.Z, *here be dragons* for now.
#![feature(unsized_tuple_coercion)]
// #![feature(unsized_tuple_coercion)]
extern crate log;
extern crate pretty_env_logger;
@ -43,9 +43,8 @@ mod settings;
#[allow(unused)]
mod utils;
use cli::{Args, Commands};
use cli::{Args, Commands, JumpCommands};
use git::Config;
use utils::strings::{FAST_COMMIT, QUICK_COMMIT};
use clap::Parser;
@ -62,51 +61,101 @@ fn main() {
pretty_env_logger::init();
let mut args = Args::parse();
let config = Config::new(&args.config);
// Input from -m flag is stored here, this is just used to construct the
// persistent box
let mut message_input: String = String::new();
match &args {
args if args.license => println!("{}", utils::strings::INTERACTIVE_LICENSE),
args if args.warranty => println!("{}", utils::strings::INTERACTIVE_WARRANTY),
args if args.code_of_conduct => println!("{}", utils::strings::INTERACTIVE_COC),
args if args.quiet => settings::QUIET.store(true, Ordering::Relaxed),
args if args.no_emoji => settings::EMOJIS.store(true, Ordering::Relaxed),
args if args.message.is_some() => message_input = args.message.clone().unwrap(),
_ => (),
}
let message = Box::leak(message_input.into_boxed_str());
match &mut args.command {
Some(Commands::Link { msg: _ }) => {
Some(Commands::Link {}) => {
config.link_all();
}
Some(Commands::Quick { msg }) => {
let s = Box::leak(
msg.as_mut()
.get_or_insert(&mut QUICK_COMMIT.to_string())
.clone()
.into_boxed_str(),
);
config.quick(s);
// NOTE: This implements "sub-subcommand"-like matching on repository,
// name, and additional data for a subcommand
// TODO: generalize for reuse by all commands that operate on repo->name->msg
//
// What we want:
// - seidr quick
// - seidr quick category
// - seidr quick category repository
// - seidr quick -m "message"
// - seidr quick category -m "message"
// - seidr quick category repo -m "hi"
//
// What we are implementing:
// - [x] seidr quick
// - [ ] seidr quick category
// - [ ] seidr quick category repository
// - [ ] seidr quick category repository "stuff"
//
// Roadmap:
// - [-] basic command parsing
// - [ ] lacks -m flag
// - [ ] ability to run command on repos in category
// - [ ] ability to run command on single repo
Some(Commands::Quick { category, repo }) => match (&category, &repo) {
// - seidr quick
(None, None) => {
config.quick(message);
}
// - [ ] seidr quick category
(category, None) => {
println!("{}", category.as_ref().unwrap());
todo!();
}
(category, repo) => {
println!("{} {}", category.as_ref().unwrap(), repo.as_ref().unwrap());
todo!();
} // // - [ ] seidr quick category categorysitory "stuff"
// (category, repo) => {
// println!("{} {}", category.as_ref().unwrap(), repo.as_ref().unwrap(),);
// todo!();
// }
},
Some(Commands::Fast {}) => {
config.fast(message);
}
Some(Commands::Fast { msg }) => {
let s = Box::leak(
msg.as_mut()
.get_or_insert(&mut FAST_COMMIT.to_string())
.clone()
.into_boxed_str(),
);
config.fast(s);
}
Some(Commands::Clone { msg: _ }) => {
Some(Commands::Clone {}) => {
config.clone_all();
}
Some(Commands::Pull { msg: _ }) => {
Some(Commands::Pull {}) => {
config.pull_all();
}
Some(Commands::Add { msg: _ }) => {
Some(Commands::Add {}) => {
config.add_all();
}
Some(Commands::Commit { msg: _ }) => {
Some(Commands::Commit {}) => {
config.commit_all();
}
Some(Commands::CommitMsg { msg }) => {
config.commit_all_msg(msg.as_ref().expect("failed to get message from input"));
Some(Commands::CommitMsg {}) => {
config.commit_all_msg(message);
}
Some(Commands::Jump(cmd)) => match cmd {
JumpCommands::Repo { category, name } => {
config.get_repo(category, name, |repo| {
println!(
"{}{}",
repo.path.as_ref().unwrap(),
repo.name.as_ref().unwrap()
);
});
}
JumpCommands::Link { category, name } => {
config.get_link(category, name, |link| println!("{}", link.tx));
}
},
None => (),
}
trace!("{:?}", config);
@ -116,7 +165,7 @@ fn main() {
mod config {
use crate::*;
use git::RepoFlags::{Clone, Push};
use git::{Category, GitRepo};
use git::{Category, Repo};
use relative_path::RelativePath;
use std::collections::HashMap;
use std::env::current_dir;
@ -151,11 +200,12 @@ mod config {
.expect("failed to get repo")
.insert(
format!("{}", i).to_string(),
GitRepo {
name: "test repo".to_string(),
path: "/tmp".to_string(),
url: "https://github.com/cafkafk/gg".to_string(),
Repo {
name: Some("test repo".to_string()),
path: Some("/tmp".to_string()),
url: Some("https://github.com/cafkafk/seidr".to_string()),
flags: Some(vec![Clone, Push]),
kind: None,
},
);
}
@ -211,24 +261,85 @@ mod config {
#[allow(clippy::bool_assert_comparison)]
{
(&config).get_repo("config", "qmk_firmware", |repo| {
assert_eq!(repo.name, "qmk_firmware");
assert_eq!(repo.path, "/home/ces/org/src/git/");
assert_eq!(repo.url, "git@github.com:cafkafk/qmk_firmware.git");
assert_eq!(repo.name.as_ref().unwrap(), "qmk_firmware");
assert_eq!(repo.path.as_ref().unwrap(), "/home/ces/org/src/git/");
assert_eq!(
repo.url.as_ref().unwrap(),
"git@github.com:cafkafk/qmk_firmware.git"
);
});
(&config).get_link("stuff", "gg", |link| {
assert_eq!(link.name, "gg");
assert_eq!(link.tx, "/home/ces/.dots/gg");
assert_eq!(link.rx, "/home/ces/.config/gg");
(&config).get_link("stuff", "seidr", |link| {
assert_eq!(link.name, "seidr");
assert_eq!(link.tx, "/home/ces/.dots/seidr");
assert_eq!(link.rx, "/home/ces/.config/seidr");
});
}
}
#[test]
fn test_validators_config() {
use crate::git::SeriesItem;
let root = current_dir().expect("failed to get current dir");
let config = Config::new(
&RelativePath::new("./src/test/config.yaml")
.to_logical_path(&root)
.into_os_string()
.into_string()
.expect("failed to turn config into string"),
);
let series: Vec<SeriesItem> = vec![SeriesItem {
operation: "is_valid_kind",
closure: Box::new(Repo::is_valid_kind),
}];
run_series!(config, series, true);
}
#[test]
#[should_panic]
fn test_validators_fail() {
use crate::git::SeriesItem;
let default_category = Category {
flags: Some(vec![]),
repos: Some(HashMap::new()),
links: Some(HashMap::new()),
};
let mut config = Config {
categories: HashMap::new(),
};
config
.categories
.insert(format!("{}", 0).to_string(), default_category);
for i in 0..=5 {
config
.categories
.get_mut(&format!("{}", 0).to_string())
.expect("category not found")
.repos
.as_mut()
.expect("failed to get repo")
.insert(
format!("{}", i).to_string(),
// WE create a broken repo
Repo {
name: None,
path: Some("/tmp".to_string()),
url: Some("https://github.com/cafkafk/seidr".to_string()),
flags: Some(vec![Clone, Push]),
kind: Some(crate::git::RepoKinds::GitRepo),
},
);
}
let series: Vec<SeriesItem> = vec![SeriesItem {
operation: "is_valid_kind",
closure: Box::new(Repo::is_valid_kind),
}];
run_series!(config, series, true);
}
}
/* FIXME Unable to test with networking inside flake
#[cfg(test)]
mod repo_actions {
use crate::*;
use git::GitRepo;
use git::Repo;
use relative_path::RelativePath;
use std::env::current_dir;
use std::process::Command;
@ -248,7 +359,7 @@ mod repo_actions {
repos: vec![],
links: vec![],
};
let repo = GitRepo {
let repo = Repo {
name: test_repo_name.to_owned(),
path: test_repo_dir.to_owned(),
url: test_repo_url.to_owned(),

View file

@ -6,41 +6,47 @@ categories:
name: qmk_firmware
path: /home/ces/org/src/git/
url: git@github.com:cafkafk/qmk_firmware.git
kind: GitRepo
flags: [Clone, Push]
starship:
name: starship
path: /home/ces/org/src/git/
url: https://github.com/starship/starship.git
kind: GitRepo
flags: [Clone, Push]
utils:
repos:
gg:
name: gg
seidr:
name: seidr
path: /home/ces/.dots/
url: git@github.com:cafkafk/gg.git
url: git@github.com:cafkafk/seidr.git
kind: GitRepo
flags: [Clone, Push]
li:
name: li
path: /home/ces/org/src/git/
url: git@github.com:cafkafk/li.git
kind: GitRepo
flags: [Clone, Push]
empty:
stuff:
flags: []
repos:
gg:
name: gg
seidr:
name: seidr
path: /home/ces/.dots/
url: git@github.com:cafkafk/gg.git
kind: GitRepo
url: git@github.com:cafkafk/seidr.git
li:
name: li
path: /home/ces/org/src/git/
kind: GitRepo
url: git@github.com:cafkafk/li.git
links:
gg:
name: gg
rx: /home/ces/.config/gg
tx: /home/ces/.dots/gg
seidr:
name: seidr
rx: /home/ces/.config/seidr
tx: /home/ces/.dots/seidr
starship:
name: starship
rx: /home/ces/.config/starship.toml
@ -48,10 +54,10 @@ categories:
fluff:
flags: []
links:
gg:
name: gg
rx: /home/ces/.config/gg
tx: /home/ces/.dots/gg
seidr:
name: seidr
rx: /home/ces/.config/seidr
tx: /home/ces/.dots/seidr
starship:
name: starship
rx: /home/ces/.config/starship.toml

View file

@ -26,11 +26,11 @@ use crate::settings;
/// Contains the notice for interactive programs from the GPLv3's "How to Apply
/// These Terms to Your New Programs"
pub const INTERACTIVE_NOTICE: &str = "\
gg Copyright (C) 2023 Christina Sørensen <cafkafk.com>
seidr Copyright (C) 2023 Christina Sørensen <cafkafk.com>
This program comes with ABSOLUTELY NO WARRANTY; for details type `gg
This program comes with ABSOLUTELY NO WARRANTY; for details type `seidr
--warranty'. This is free software, and you are welcome to redistribute it under
certain conditions; type `gg --license' for details. ";
certain conditions; type `seidr --license' for details. ";
/// Contains the license part of the long notice for interactive programs from
/// the GPLv3's "How to Apply These Terms to Your New Programs"

View file

@ -2,200 +2,3 @@
fn main() {
assert!(true);
}
/*
#[cfg(test)]
mod config {
use gg::git::RepoFlags::{Clone, Push};
use gg::git::{Category, Config, GitRepo, Link};
use relative_path::RelativePath;
use std::collections::HashMap;
use std::env::current_dir;
use std::fs::File;
use std::io::prelude::*;
#[test]
fn init_config() {
let _config = Config {
categories: HashMap::new(),
};
}
#[test]
fn init_config_populate() {
let default_category = Category {
flags: Some(vec![]),
repos: Some(HashMap::new()),
links: Some(HashMap::new()),
};
let mut config = Config {
categories: HashMap::new(),
};
config
.categories
.insert(format!("{}", 0).to_string(), default_category);
for i in 0..=5 {
config
.categories
.get_mut(&format!("{}", 0).to_string())
.expect("category not found")
.repos
.as_mut()
.expect("failed to get repo")
.insert(
format!("{}", i).to_string(),
GitRepo {
name: "test repo".to_string(),
path: "/tmp".to_string(),
url: "https://github.com/cafkafk/gg".to_string(),
flags: Some(vec![Clone, Push]),
},
);
}
}
#[test]
fn read_config_populate() {
let _config = Config::new(&RelativePath::new("./src/test/config.yaml").to_string());
}
#[test]
fn write_config() {
let root = current_dir().expect("failed to get current dir");
let config = Config::new(
&RelativePath::new("./src/test/config.yaml")
.to_logical_path(&root)
.into_os_string()
.into_string()
.expect("failed to turn config into string"),
);
let mut test_file = File::create(
RelativePath::new("./src/test/test.yaml")
.to_logical_path(&root)
.into_os_string()
.into_string()
.expect("failed to turn config into string"),
)
.expect("failed to create test file");
let contents = serde_yaml::to_string(&config).expect("failed to turn config into string");
test_file
.write_all(contents.as_bytes())
.expect("failed to write contents of config into file");
let test_config = Config::new(&RelativePath::new("./src/test/test.yaml").to_string());
assert_eq!(config, test_config);
}
#[allow(dead_code)]
fn get_category<'cat>(config: &'cat Config, name: &'cat str) -> &'cat Category {
config.categories.get(name).expect("failed to get category")
}
fn get_repo<F>(config: &Config, cat_name: &str, repo_name: &str, f: F)
where
F: FnOnce(&GitRepo),
{
f(config
.categories
.get(cat_name)
.expect("failed to get category")
.repos
.as_ref()
.expect("failed to get repo")
.get(repo_name)
.expect("failed to get category"))
}
fn get_link<F>(config: &Config, cat_name: &str, link_name: &str, f: F)
where
F: FnOnce(&Link),
{
f(config
.categories
.get(cat_name)
.expect("failed to get category")
.links
.as_ref()
.expect("failed to get repo")
.get(link_name)
.expect("failed to get category"))
}
#[test]
fn is_config_readable() {
let root = current_dir().expect("failed to get current dir");
let config = Config::new(
&RelativePath::new("./src/test/config.yaml")
.to_logical_path(root)
.into_os_string()
.into_string()
.expect("failed to turnn config into string"),
);
let _flags = vec![Clone, Push];
// FIXME not very extensive
#[allow(clippy::bool_assert_comparison)]
{
get_repo(&config, "config", "qmk_firmware", |repo| {
assert_eq!(repo.name, "qmk_firmware");
assert_eq!(repo.path, "/home/ces/org/src/git/");
assert_eq!(repo.url, "git@github.com:cafkafk/qmk_firmware.git");
});
get_link(&config, "stuff", "gg", |link| {
assert_eq!(link.name, "gg");
assert_eq!(link.tx, "/home/ces/.dots/gg");
assert_eq!(link.rx, "/home/ces/.config/gg");
});
}
/*
{
assert_eq!(config.links[0].name, "gg");
assert_eq!(config.links[0].rx, "/home/ces/.config/gg");
assert_eq!(config.links[0].tx, "/home/ces/.dots/gg");
assert_eq!(config.links[1].name, "starship");
assert_eq!(config.links[1].rx, "/home/ces/.config/starship.toml");
assert_eq!(config.links[1].tx, "/home/ces/.dots/starship.toml");
// FIXME doesn't check repoflags
}*/
}
}*/
/*
#[cfg(test)]
mod repo_actions {
use gg::git::GitRepo;
use gg::relative_path::RelativePath;
use gg::std::env::current_dir;
use gg::std::process::Command;
#[test]
#[allow(clippy::redundant_clone)]
fn test_repo_actions() {
let test_repo_name: String = "test".to_string();
let root = current_dir().unwrap();
let test_repo_dir: String = RelativePath::new("./src/test")
.to_logical_path(&root)
.into_os_string()
.into_string()
.unwrap();
let test_repo_url: String = "git@github.com:cafkafk/test.git".to_string();
println!("{}", test_repo_dir);
let mut config = Config {
repos: vec![],
links: vec![],
};
let repo = GitRepo {
name: test_repo_name.to_owned(),
path: test_repo_dir.to_owned(),
url: test_repo_url.to_owned(),
clone: true,
};
config.repos.push(repo);
// BUG FIXME can't do this in flake
// should have a good alternative
// config.clone_all();
// config.pull_all();
for r in config.repos.iter() {
Command::new("touch")
.current_dir(&(r.path.to_owned() + &r.name))
.arg("test")
.status()
.expect("failed to create test file");
}
config.add_all();
config.commit_all_msg(&"test".to_string());
}
}
*/