diff --git a/Cargo.lock b/Cargo.lock index a07e1d1..f8135b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index b882576..59f9a53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/README.org b/README.org index b8a8bcd..bfed23a 100644 --- a/README.org +++ b/README.org @@ -1,5 +1,5 @@ #+options: toc:nil -* gg - git gut +* Seiðr #+html: 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. diff --git a/benches/basic_bench.rs b/benches/basic_bench.rs new file mode 100644 index 0000000..fafb388 --- /dev/null +++ b/benches/basic_bench.rs @@ -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); diff --git a/doc/ARCHITECTURE.org b/doc/ARCHITECTURE.org index 249cc73..8c2e0ad 100644 --- a/doc/ARCHITECTURE.org +++ b/doc/ARCHITECTURE.org @@ -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 diff --git a/doc/roadmap.org b/doc/roadmap.org index 159ff0e..53cbdf9 100644 --- a/doc/roadmap.org +++ b/doc/roadmap.org @@ -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 diff --git a/src/cli.rs b/src/cli.rs index 8c9ed78..fed50af 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -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, + #[command(subcommand)] pub command: Option, } @@ -80,33 +83,51 @@ pub struct Args { pub enum Commands { /// Link all... links #[command(visible_alias = "l")] - Link { msg: Option }, + Link {}, /// Do quick pull-commit-push with msg for commit #[command(visible_alias = "q")] - Quick { msg: Option }, + Quick { + category: Option, + repo: Option, + }, /// Do fast pull-commit-push with msg for commit, skipping repo on failure #[command(visible_alias = "f")] - Fast { msg: Option }, + Fast {}, /// Clone all repositories #[command(visible_alias = "c")] - Clone { msg: Option }, + Clone {}, /// Pull all repositories #[command(visible_alias = "p")] - Pull { msg: Option }, + Pull {}, /// Add all files in repositories #[command(visible_alias = "a")] - Add { msg: Option }, + Add {}, /// Perform a git commit in all repositories #[command(visible_alias = "ct")] - Commit { msg: Option }, + Commit {}, /// Perform a git commit in all repositories, with predefined message #[command(visible_alias = "m")] - CommitMsg { msg: Option }, + 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 }, } diff --git a/src/git.rs b/src/git.rs index cfb237c..bce9dbb 100644 --- a/src/git.rs +++ b/src/git.rs @@ -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>, + pub repos: Option>, /// 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, + pub path: Option, + pub url: Option, + // TODO: make default a standard GitRepo #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, // FIXME: not implemented pub flags: Option>, } -//////////////////////////////////// -//////////////////////////////////// -//////////////////////////////////// - /// 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 (bool)>, + pub closure: Box (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: ", self.kind); + return false; + } + if (self.path.is_none()) { + eprintln!("{:?} must have path: ", self.kind); + return false; + } + if (self.url.is_none()) { + eprintln!("{:?} must have url: ", 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 = 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(&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(&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(&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 = 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) { - 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 = 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) { + pub fn all_on_all(&self, closures: Vec, 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 = 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(&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(&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 = 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 = 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"); diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 667db91..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -// #[allow(unused)] -// pub mod git; -// #[allow(unused)] -// mod settings; -// #[allow(unused)] -// mod utils; diff --git a/src/lib.rs.old b/src/lib.rs.old new file mode 100644 index 0000000..0c5ac39 --- /dev/null +++ b/src/lib.rs.old @@ -0,0 +1,6 @@ +#[allow(unused)] +pub mod git; +#[allow(unused)] +mod settings; +#[allow(unused)] +mod utils; diff --git a/src/main.rs b/src/main.rs index e830ccd..960b401 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 = 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 = 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(), diff --git a/src/test/config.yaml b/src/test/config.yaml index 46994cb..d3c9b96 100644 --- a/src/test/config.yaml +++ b/src/test/config.yaml @@ -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 diff --git a/src/utils/strings.rs b/src/utils/strings.rs index 55b28bf..37f6849 100644 --- a/src/utils/strings.rs +++ b/src/utils/strings.rs @@ -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 +seidr Copyright (C) 2023 Christina Sørensen -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" diff --git a/tests/main.rs b/tests/main.rs index ddc61f5..6fc1f3d 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -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(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(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()); - } -} -*/