Compare commits
7 Commits
6aae4afa06
...
efc28c3bd0
Author | SHA1 | Date |
---|---|---|
Jean-Claude | efc28c3bd0 | |
Jean-Claude | 3325a28bd8 | |
Jean-Claude | e0c16c2cd4 | |
Jean-Claude | 7ecbf5b5a3 | |
Jean-Claude | 89235fc1b9 | |
Jean-Claude | 2b14de9287 | |
Jean-Claude | a2bb209e2c |
|
@ -2,6 +2,21 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.1"
|
||||
|
@ -81,6 +96,21 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -93,6 +123,37 @@ version = "3.12.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
|
@ -205,6 +266,12 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||
|
||||
[[package]]
|
||||
name = "dlv-list"
|
||||
version = "0.5.0"
|
||||
|
@ -244,6 +311,101 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.9"
|
||||
|
@ -255,6 +417,12 @@ dependencies = [
|
|||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.17.1"
|
||||
|
@ -270,6 +438,12 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
|
@ -344,6 +518,12 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.26"
|
||||
|
@ -447,17 +627,39 @@ dependencies = [
|
|||
"clap",
|
||||
"git2",
|
||||
"kamadak-exif",
|
||||
"pretty_assertions",
|
||||
"rand",
|
||||
"regex",
|
||||
"rstest",
|
||||
"rust-ini",
|
||||
"testdir",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mutate_once"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b"
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
|
@ -477,6 +679,15 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.30.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
|
@ -517,12 +728,40 @@ version = "2.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||
dependencies = [
|
||||
"diff",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.20+deprecated"
|
||||
|
@ -547,6 +786,36 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.1"
|
||||
|
@ -564,6 +833,41 @@ version = "0.7.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
|
||||
|
||||
[[package]]
|
||||
name = "relative-path"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca"
|
||||
|
||||
[[package]]
|
||||
name = "rstest"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"rstest_macros",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rstest_macros"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"glob",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"relative-path",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.19.0"
|
||||
|
@ -574,6 +878,21 @@ dependencies = [
|
|||
"ordered-multimap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.19"
|
||||
|
@ -588,6 +907,61 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
|
@ -605,6 +979,34 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.26.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c18a6156d1f27a9592ee18c1a846ca8dd5c258b7179fc193ae87c74ebb666f5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "testdir"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48b7965698cfb3d1ac1e6e54b4b45f5caa9e89bda223c8cf723d9cf53d7cefa7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backtrace",
|
||||
"cargo_metadata",
|
||||
"once_cell",
|
||||
"sysinfo",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.40"
|
||||
|
@ -770,6 +1172,26 @@ version = "0.2.86"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whoami"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -866,3 +1288,9 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
|
|
@ -16,3 +16,9 @@ kamadak-exif = "0.5.5"
|
|||
regex = "1.8.1"
|
||||
rust-ini = "0.19.0"
|
||||
thiserror = "1.0.40"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
rand = "0.8.5"
|
||||
rstest = "0.18.2"
|
||||
testdir = "0.8.0"
|
||||
|
|
|
@ -8,7 +8,7 @@ use super::git;
|
|||
|
||||
/// Represents an archive
|
||||
pub struct Archive {
|
||||
path: PathBuf,
|
||||
pub path: PathBuf,
|
||||
pub repo: git::git2::Repository,
|
||||
pub config: Config,
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ impl Archive {
|
|||
let path = Archive::get_root()?;
|
||||
|
||||
let repo = git2::Repository::init(&path)?;
|
||||
let config = Archive::get_config_from_main_branch()?;
|
||||
let config = Archive::get_config_from_main_branch(&path)?;
|
||||
Ok(Self { path, repo, config })
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ impl Archive {
|
|||
|
||||
/// Indicate if the archive is in a dirty state.
|
||||
pub fn is_dirty(&self) -> Result<bool, ArchiveError> {
|
||||
Ok(git::is_dirty(&self.repo)?)
|
||||
Ok(git::is_dirty(&self.path)?)
|
||||
}
|
||||
|
||||
/// Iteratively search archive root starting at CWD going up to /.
|
||||
|
@ -78,9 +78,12 @@ impl Archive {
|
|||
}
|
||||
|
||||
/// Get config by reading file from main branch.
|
||||
fn get_config_from_main_branch() -> Result<Config, ArchiveError> {
|
||||
fn get_config_from_main_branch(path: &PathBuf) -> Result<Config, ArchiveError> {
|
||||
let main_branch = "main"; // TODO: How to figure out which main branch is, without config? :D
|
||||
let out = git::show(vec![format!("{}:{}", main_branch, RELATIVE_CONFIG_FILE)])?;
|
||||
let out = git::show(
|
||||
path,
|
||||
vec![format!("{}:{}", main_branch, RELATIVE_CONFIG_FILE)],
|
||||
)?;
|
||||
Ok(Config::from_string(&out)?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ pub fn new(
|
|||
String::from("--message"),
|
||||
format!("Import {} images", state.images.len()),
|
||||
];
|
||||
git::run(args)?;
|
||||
git::run(&archive.path, args)?;
|
||||
|
||||
println!("Done importing {} images", state.images.len());
|
||||
Ok(())
|
||||
|
@ -193,11 +193,11 @@ fn prepare_branch_for_new_import(archive: &Archive, state: &ImportState) -> Resu
|
|||
String::from("--orphan"),
|
||||
String::from(&unique_branch),
|
||||
];
|
||||
git::run(args)?;
|
||||
git::run(&archive.path, args)?;
|
||||
|
||||
// TODO: use git2 library
|
||||
let args = vec![String::from("clean"), String::from("--force")];
|
||||
git::run(args)?;
|
||||
git::run(&archive.path, args)?;
|
||||
|
||||
// TODO: use git2 library
|
||||
let args = vec![
|
||||
|
@ -206,7 +206,7 @@ fn prepare_branch_for_new_import(archive: &Archive, state: &ImportState) -> Resu
|
|||
String::from("--message"),
|
||||
String::from("NEW EMPTY IMPORT"),
|
||||
];
|
||||
git::run(args)?;
|
||||
git::run(&archive.path, args)?;
|
||||
|
||||
assert!(archive.get_current_branch().unwrap() == unique_branch);
|
||||
Ok(())
|
||||
|
|
241
src/config.rs
241
src/config.rs
|
@ -9,12 +9,14 @@ use crate::error::{Config as ConfigError, ConfigFormat as ConfigFormatError};
|
|||
pub static RELATIVE_CONFIG_FILE: &str = "mia.ini";
|
||||
|
||||
/// List all sections of the config
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Config {
|
||||
pub general: General,
|
||||
pub schema: Schema,
|
||||
}
|
||||
|
||||
/// List all options of the 'General' section
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct General {
|
||||
pub import_branch_prefix: String,
|
||||
pub import_branch_schema: String,
|
||||
|
@ -22,6 +24,7 @@ pub struct General {
|
|||
}
|
||||
|
||||
/// List all options of the 'Schema' section
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Schema {
|
||||
pub default: String,
|
||||
pub custom: HashMap<String, String>,
|
||||
|
@ -159,7 +162,7 @@ impl Default for General {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
import_branch_prefix: String::from("import/"),
|
||||
import_branch_schema: String::from("*Sy*Sm*i*c"),
|
||||
import_branch_schema: String::from("*Sy*Sm*Sd*i*c"),
|
||||
main_branch: String::from("main"),
|
||||
}
|
||||
}
|
||||
|
@ -178,3 +181,239 @@ impl Default for Schema {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::conftest::*;
|
||||
use crate::error as Error;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::{fixture, rstest};
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::fs;
|
||||
|
||||
#[fixture]
|
||||
pub fn default_config_string() -> String {
|
||||
String::from(
|
||||
"[General]
|
||||
ImportBranchPrefix=import/
|
||||
ImportBranchSchema=*Sy*Sm*Sd*i*c
|
||||
MainBranch=main
|
||||
|
||||
[Schema]
|
||||
Default=%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x
|
||||
Event=%Y/*Sy*Sm*Sd-*Ey*Em*Ed*i/%y%m%d/%y%m%d_%H%M%S*c.*x",
|
||||
)
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
pub fn default_general() -> General {
|
||||
General {
|
||||
import_branch_prefix: String::from("import/"),
|
||||
import_branch_schema: String::from("*Sy*Sm*Sd*i*c"),
|
||||
main_branch: String::from("main"),
|
||||
}
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
pub fn default_schema() -> Schema {
|
||||
let mut schema = HashMap::new();
|
||||
schema.insert(
|
||||
String::from("Event"),
|
||||
String::from("%Y/*Sy*Sm*Sd-*Ey*Em*Ed*i/%y%m%d/%y%m%d_%H%M%S*c.*x"),
|
||||
);
|
||||
Schema {
|
||||
default: String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x"),
|
||||
custom: schema,
|
||||
}
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
pub fn default_config(default_general: General, default_schema: Schema) -> Config {
|
||||
Config {
|
||||
general: default_general,
|
||||
schema: default_schema,
|
||||
}
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
pub fn default_config_ini(default_config_string: String) -> Ini {
|
||||
Ini::load_from_str(&default_config_string).unwrap()
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn general_default(default_general: General) {
|
||||
let general = General::default();
|
||||
assert_eq!(general, default_general);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn schema_default(default_schema: Schema) {
|
||||
let schema = Schema::default();
|
||||
assert_eq!(schema, default_schema);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn config_default(default_config: Config) {
|
||||
let config = Config::default();
|
||||
assert_eq!(config, default_config);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn config_from_file(tmp_dir: PathBuf, default_config_string: String, default_config: Config) {
|
||||
// TODO: from_file also calls from_ini. Patch it?
|
||||
let mut path = tmp_dir;
|
||||
path.push("config");
|
||||
fs::write(&path, default_config_string).expect("Failed to write to file");
|
||||
|
||||
let config = Config::from_file(&path).unwrap();
|
||||
assert_eq!(config, default_config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_from_file_invalid_path_inexisting() {
|
||||
// TODO: from_file also calls from_ini. Patch it?
|
||||
let mut path = PathBuf::new();
|
||||
path.push("INVALID");
|
||||
let config = Config::from_file(&path);
|
||||
assert_matches!(config, Err(Error::Config::ReadFile { source: _ }));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn config_from_string(default_config_string: String, default_config: Config) {
|
||||
// TODO: from_string also calls from_ini. Patch it?
|
||||
let config = Config::from_string(&default_config_string).unwrap();
|
||||
assert_eq!(config, default_config);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(String::from(""))]
|
||||
#[case(String::from("[General]"))]
|
||||
#[case(String::from(
|
||||
"[General]
|
||||
ImportBranchPrefix=MISSING_FIELDS
|
||||
|
||||
[Schema]
|
||||
Default=MORE_MISSING_FIELDS"
|
||||
))]
|
||||
fn config_from_string_invalid(#[case] config_str: String) {
|
||||
// TODO: from_string also calls from_ini. Patch it?
|
||||
let config = Config::from_string(&config_str);
|
||||
assert!(config.is_err());
|
||||
assert!(matches!(config, Err(Error::Config::InvalidFormat(_))));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn config_from_ini(default_config_ini: Ini, default_config: Config) {
|
||||
let config = Config::from_ini(default_config_ini).unwrap();
|
||||
assert_eq!(config, default_config);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(Ini::load_from_str(&"").unwrap())]
|
||||
#[case(Ini::load_from_str(&"[General]").unwrap())]
|
||||
#[case(Ini::load_from_str(&"[General]
|
||||
ImportBranchPrefix=MISSING_FIELDS
|
||||
|
||||
[Schema]
|
||||
Default=MORE_MISSING_FIELDS").unwrap())]
|
||||
fn config_from_ini_invalid(#[case] config_ini: Ini) {
|
||||
let config = Config::from_ini(config_ini);
|
||||
assert!(matches!(config, Err(Error::Config::InvalidFormat(_))));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn config_dump_default(tmp_dir: PathBuf, default_config_string: String) {
|
||||
let mut path = tmp_dir;
|
||||
path.push("dump");
|
||||
assert!(Config::dump_default(&path).is_ok());
|
||||
let content = fs::read_to_string(&path).expect("Failed to read from file");
|
||||
let content = content.trim();
|
||||
assert_eq!(content, default_config_string);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(
|
||||
String::from("General"),
|
||||
String::from("ImportBranchPrefix"),
|
||||
String::from("import/")
|
||||
)]
|
||||
#[case(
|
||||
String::from("General"),
|
||||
String::from("ImportBranchSchema"),
|
||||
String::from("*Sy*Sm*Sd*i*c")
|
||||
)]
|
||||
#[case(
|
||||
String::from("General"),
|
||||
String::from("MainBranch"),
|
||||
String::from("main")
|
||||
)]
|
||||
#[case(
|
||||
String::from("Schema"),
|
||||
String::from("Default"),
|
||||
String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
#[case(
|
||||
String::from("Schema"),
|
||||
String::from("Event"),
|
||||
String::from("%Y/*Sy*Sm*Sd-*Ey*Em*Ed*i/%y%m%d/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
fn config_read_property(
|
||||
default_config_ini: Ini,
|
||||
#[case] section: String,
|
||||
#[case] key: String,
|
||||
#[case] expected: String,
|
||||
) {
|
||||
let property = Config::read_property(&default_config_ini, §ion, &key).unwrap();
|
||||
assert_eq!(property, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn config_read_property_invalid_section(default_config_ini: Ini) {
|
||||
let section = "INVALID_SECTION";
|
||||
let message: String = format!("Section '{}' is missing", section.to_owned());
|
||||
let property = Config::read_property(&default_config_ini, section, &"some_key");
|
||||
|
||||
assert_matches!(property, Err(Error::ConfigFormat::Custom{message: m}) if m == message);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn config_read_property_invalid_field(default_config_ini: Ini) {
|
||||
let section = "General";
|
||||
let key = "INVALID_KEY";
|
||||
let message: String = format!(
|
||||
"Field '{}' is missing in section '{}'",
|
||||
key.to_owned(),
|
||||
section.to_owned()
|
||||
);
|
||||
let property = Config::read_property(&default_config_ini, section, key);
|
||||
assert_matches!(property, Err(Error::ConfigFormat::Custom{message: m}) if m == message);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(String::from("General"), vec![
|
||||
(String::from("ImportBranchPrefix"), String::from("import/")),
|
||||
(String::from("ImportBranchSchema"), String::from("*Sy*Sm*Sd*i*c")),
|
||||
(String::from("MainBranch"), String::from("main"))])
|
||||
]
|
||||
#[case(String::from("Schema"), vec![
|
||||
(String::from("Default"), String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x")),
|
||||
(String::from("Event"), String::from("%Y/*Sy*Sm*Sd-*Ey*Em*Ed*i/%y%m%d/%y%m%d_%H%M%S*c.*x")),
|
||||
])]
|
||||
fn config_read_section(
|
||||
default_config_ini: Ini,
|
||||
#[case] section: String,
|
||||
#[case] expected: Vec<(String, String)>,
|
||||
) {
|
||||
let section = Config::read_section(&default_config_ini, §ion).unwrap();
|
||||
assert_eq!(section, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn config_read_section_invalid_section(default_config_ini: Ini) {
|
||||
let section = "INVALID_SECTION";
|
||||
let message: String = format!("Section '{}' is missing", section.to_owned());
|
||||
let property = Config::read_section(&default_config_ini, section);
|
||||
assert_matches!(property, Err(Error::ConfigFormat::Custom{message: m}) if m == message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// Testing fixtures and other things
|
||||
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
use rand::thread_rng;
|
||||
use rstest::fixture;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use testdir::testdir;
|
||||
|
||||
#[fixture]
|
||||
/// Return path to a temporary test directory
|
||||
pub fn tmp_dir() -> PathBuf {
|
||||
testdir!()
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
/// Return path to a temporary test file
|
||||
pub fn tmp_file() -> PathBuf {
|
||||
let mut path = tmp_dir();
|
||||
path.push(format!(
|
||||
"file_{}",
|
||||
Alphanumeric.sample_string(&mut thread_rng(), 8)
|
||||
));
|
||||
fs::File::create(&path)
|
||||
.unwrap_or_else(|_| panic!("Failed to create tmpfile {}", path.display()));
|
||||
path
|
||||
}
|
|
@ -170,120 +170,153 @@ fn fmt_count(input: &str, count: &Option<usize>) -> String {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::{fixture, rstest};
|
||||
|
||||
#[test]
|
||||
fn test_fmt_8601() {
|
||||
let dt = NaiveDateTime::parse_from_str("2023-04-03 02:01:01", "%Y-%m-%d %H:%M:%S").ok();
|
||||
let raw = "%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x";
|
||||
let out = fmt_8601(&raw, &dt);
|
||||
let exp = "2023/230403*i/230403_020101*c.*x";
|
||||
assert_eq!(&out, exp);
|
||||
#[fixture]
|
||||
/// Fixture providing DateTime of *2022-01-02 03:04:05*
|
||||
fn datetime1() -> NaiveDateTime {
|
||||
NaiveDateTime::parse_from_str("2022-01-02 03:04:05", "%Y-%m-%d %H:%M:%S").unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_start_end_datetime() {
|
||||
let start_dt =
|
||||
NaiveDateTime::parse_from_str("2023-04-03 02:01:01", "%Y-%m-%d %H:%M:%S").ok();
|
||||
let end_dt = NaiveDateTime::parse_from_str("2023-05-11 21:42:07", "%Y-%m-%d %H:%M:%S").ok();
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x";
|
||||
let out = fmt_start_end_datetime(&raw, &start_dt, &end_dt);
|
||||
let exp = "%Y/230403_230511*i/%y%m%d_%H%M%S*c.*x";
|
||||
assert_eq!(&out, exp);
|
||||
#[fixture]
|
||||
/// Fixture providing DateTime of *2023-11-12 13:14:15*
|
||||
fn datetime2() -> NaiveDateTime {
|
||||
NaiveDateTime::parse_from_str("2023-11-12 13:14:15", "%Y-%m-%d %H:%M:%S").unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_start_end_datetime_no_start() {
|
||||
let start_dt = None;
|
||||
let end_dt = NaiveDateTime::parse_from_str("2023-05-11 21:42:07", "%Y-%m-%d %H:%M:%S").ok();
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x";
|
||||
let out = fmt_start_end_datetime(&raw, &start_dt, &end_dt);
|
||||
let exp = "%Y/_230511*i/%y%m%d_%H%M%S*c.*x";
|
||||
assert_eq!(&out, exp);
|
||||
#[rstest]
|
||||
#[case(
|
||||
String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("2022/220102*i/220102_030405*c.*x")
|
||||
)]
|
||||
fn test_fmt_8601(datetime1: NaiveDateTime, #[case] raw: String, #[case] expected: String) {
|
||||
let out = fmt_8601(&raw, &Some(datetime1));
|
||||
assert_eq!(out, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_start_end_datetime_no_end() {
|
||||
let start_dt =
|
||||
NaiveDateTime::parse_from_str("2023-04-03 02:01:01", "%Y-%m-%d %H:%M:%S").ok();
|
||||
let end_dt = None;
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x";
|
||||
let out = fmt_start_end_datetime(&raw, &start_dt, &end_dt);
|
||||
let exp = "%Y/230403_*i/%y%m%d_%H%M%S*c.*x";
|
||||
assert_eq!(&out, exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_start_end_datetime_no_start_and_end() {
|
||||
let start_dt = None;
|
||||
let end_dt = None;
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x";
|
||||
let out = fmt_start_end_datetime(&raw, &start_dt, &end_dt);
|
||||
let exp = "%Y/_*i/%y%m%d_%H%M%S*c.*x";
|
||||
assert_eq!(&out, exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_identifier() {
|
||||
let identifier = Some(String::from("test"));
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x";
|
||||
#[rstest]
|
||||
#[case(
|
||||
Some(String::from("test")),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed-test/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
#[case(
|
||||
None,
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
#[case(
|
||||
Some(String::from("test")),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*i*c.*x"),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed-test/%y%m%d_%H%M%S-test*c.*x")
|
||||
)]
|
||||
fn test_fmt_identifier(
|
||||
#[case] identifier: Option<String>,
|
||||
#[case] raw: String,
|
||||
#[case] expected: String,
|
||||
) {
|
||||
let out = fmt_identifier(&raw, &identifier);
|
||||
let exp = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed-test/%y%m%d_%H%M%S*c.*x";
|
||||
assert_eq!(&out, exp);
|
||||
assert_eq!(out, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_identifier_no() {
|
||||
let identifier = None;
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x";
|
||||
let out = fmt_identifier(&raw, &identifier);
|
||||
let exp = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed/%y%m%d_%H%M%S*c.*x";
|
||||
assert_eq!(&out, exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_identifier_multiple() {
|
||||
let identifier = Some(String::from("test"));
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/bla*i/%y%m%d_%H%M%S*c.*x";
|
||||
let out = fmt_identifier(&raw, &identifier);
|
||||
let exp = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed-test/bla-test/%y%m%d_%H%M%S*c.*x";
|
||||
assert_eq!(&out, exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_extension_small() {
|
||||
let extension = Some(String::from("cr2"));
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x";
|
||||
#[rstest]
|
||||
#[case(
|
||||
Some(String::from("cr2")),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.cr2")
|
||||
)]
|
||||
#[case(
|
||||
Some(String::from("cr2")),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*X"),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.CR2")
|
||||
)]
|
||||
#[case(
|
||||
None,
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.")
|
||||
)]
|
||||
#[case(
|
||||
None,
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*X"),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.")
|
||||
)]
|
||||
fn test_fmt_extension_small(
|
||||
#[case] extension: Option<String>,
|
||||
#[case] raw: String,
|
||||
#[case] expected: String,
|
||||
) {
|
||||
let out = fmt_extension(&raw, &extension);
|
||||
let exp = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.cr2";
|
||||
assert_eq!(&out, exp);
|
||||
assert_eq!(out, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_extension_large() {
|
||||
let extension = Some(String::from("cr2"));
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*X";
|
||||
let out = fmt_extension(&raw, &extension);
|
||||
let exp = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.CR2";
|
||||
assert_eq!(&out, exp);
|
||||
#[rstest]
|
||||
#[case(
|
||||
Some(datetime1()),
|
||||
Some(datetime2()),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/220102_231112*i/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
#[case(
|
||||
Some(datetime1()),
|
||||
Some(datetime2()),
|
||||
String::from("*Ey*Em*Ed*EH*EM*ES"),
|
||||
String::from("231112131415")
|
||||
)]
|
||||
#[case(
|
||||
Some(datetime1()),
|
||||
Some(datetime2()),
|
||||
String::from("%Y/*Sy*Sm*Sd*SH*SM*SS_*Ey*Em*Ed*EH*EM*ES*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/220102030405_231112131415*i/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
#[case(
|
||||
Some(datetime1()),
|
||||
None,
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/220102_*i/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
#[case(
|
||||
None,
|
||||
Some(datetime2()),
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/_231112*i/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
#[case(
|
||||
None,
|
||||
None,
|
||||
String::from("%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/_*i/%y%m%d_%H%M%S*c.*x")
|
||||
)]
|
||||
fn test_fmt_start_end_datetime(
|
||||
#[case] start_dt: Option<NaiveDateTime>,
|
||||
#[case] end_dt: Option<NaiveDateTime>,
|
||||
#[case] raw: String,
|
||||
#[case] expected: String,
|
||||
) {
|
||||
let out = fmt_start_end_datetime(&raw, &start_dt, &end_dt);
|
||||
assert_eq!(out, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_extension_small_no() {
|
||||
let extension = None;
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*x";
|
||||
let out = fmt_extension(&raw, &extension);
|
||||
let exp = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.";
|
||||
assert_eq!(&out, exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt_custom_extension_large_no() {
|
||||
let extension = None;
|
||||
let raw = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.*X";
|
||||
let out = fmt_extension(&raw, &extension);
|
||||
let exp = "%Y/*Sy*Sm*Sd_*Ey*Em*Ed*i/%y%m%d_%H%M%S*c.";
|
||||
assert_eq!(&out, exp);
|
||||
#[rstest]
|
||||
#[case(
|
||||
Some(1),
|
||||
String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S-1.*x")
|
||||
)]
|
||||
#[case(
|
||||
Some(10),
|
||||
String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S-10.*x")
|
||||
)]
|
||||
#[case(
|
||||
None,
|
||||
String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S*c.*x"),
|
||||
String::from("%Y/%y%m%d*i/%y%m%d_%H%M%S.*x")
|
||||
)]
|
||||
fn test_fmt_count(#[case] count: Option<usize>, #[case] raw: String, #[case] expected: String) {
|
||||
let out = fmt_count(&raw, &count);
|
||||
assert_eq!(out, expected);
|
||||
}
|
||||
}
|
||||
|
|
277
src/git.rs
277
src/git.rs
|
@ -18,13 +18,15 @@ pub fn get_root() -> Result<PathBuf, GitError> {
|
|||
let ceiling_dir = Path::new("/");
|
||||
// TODO: Improve error type of `discover_path` to indicate if no repo found or other error
|
||||
let repo = Repository::discover_path(cwd, ceiling_dir)?;
|
||||
Ok(repo)
|
||||
let repo = repo.parent().expect("There should always be a parent");
|
||||
|
||||
Ok(PathBuf::from(repo))
|
||||
}
|
||||
|
||||
/// Convenience wrapper to switch to a specific branch.
|
||||
///
|
||||
/// Branch `branch_name` must exists.
|
||||
pub fn switch_branch(repo: &Repository, branch_name: &String) -> Result<(), GitError> {
|
||||
pub fn switch_branch(repo: &Repository, branch_name: &str) -> Result<(), GitError> {
|
||||
// No need to change branch, if we are already on the right branch
|
||||
if let Ok(branch) = get_current_branch(repo) && &branch == branch_name {
|
||||
println!("Your are already on the right target. No need to switch.");
|
||||
|
@ -76,9 +78,22 @@ pub fn exists_branch(repo: &Repository, branch_name: &str) -> bool {
|
|||
repo.find_branch(branch_name, BranchType::Local).is_ok()
|
||||
}
|
||||
|
||||
/// Indicate if the repository is dirty.
|
||||
///
|
||||
/// Dirty is interpreted as having uncommitted changes and/or having untracked files.
|
||||
/// TODO: use git2 library
|
||||
pub fn is_dirty(repository: &PathBuf) -> Result<bool, GitError> {
|
||||
let args = vec![String::from("status"), String::from("--porcelain")];
|
||||
let out = run(repository, args)?;
|
||||
Ok(!out.is_empty())
|
||||
}
|
||||
|
||||
/// Run git command
|
||||
pub fn run(args: Vec<String>) -> Result<String, GitError> {
|
||||
let out = Command::new("git").args(&args).output()?;
|
||||
pub fn run(repository: &PathBuf, args: Vec<String>) -> Result<String, GitError> {
|
||||
let out = Command::new("git")
|
||||
.args(&args)
|
||||
.current_dir(repository)
|
||||
.output()?;
|
||||
|
||||
if out.status.success() {
|
||||
Ok(String::from_utf8_lossy(&out.stdout).trim().to_string())
|
||||
|
@ -94,21 +109,251 @@ pub fn run(args: Vec<String>) -> Result<String, GitError> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Indicate if the repository is dirty.
|
||||
///
|
||||
/// Dirty is interpreted as having uncommitted changes and/or having untracked files.
|
||||
/// TODO: use git2 library
|
||||
pub fn is_dirty(_repo: &Repository) -> Result<bool, GitError> {
|
||||
let args = vec![String::from("status"), String::from("--porcelain")];
|
||||
let out = run(args)?;
|
||||
Ok(!out.is_empty())
|
||||
}
|
||||
|
||||
/// Run `git show ARGS` command.
|
||||
///
|
||||
/// TODO: use git2 library
|
||||
pub fn show(args: Vec<String>) -> Result<String, GitError> {
|
||||
pub fn show(repository: &PathBuf, args: Vec<String>) -> Result<String, GitError> {
|
||||
let mut args_complete = args.to_owned();
|
||||
args_complete.insert(0, String::from("show"));
|
||||
run(args_complete)
|
||||
run(repository, args_complete)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::conftest::tmp_dir;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::{fixture, rstest};
|
||||
use std::env::set_current_dir;
|
||||
use std::fs;
|
||||
|
||||
/// Get name of current branch.
|
||||
fn get_current_branch2(repo: &PathBuf) -> String {
|
||||
let out = Command::new("git")
|
||||
.arg("rev-parse")
|
||||
.arg("--abbrev-ref")
|
||||
.arg("HEAD")
|
||||
.current_dir(repo)
|
||||
.output()
|
||||
.expect("Failed to run command");
|
||||
String::from_utf8_lossy(&out.stdout).trim().to_string()
|
||||
}
|
||||
|
||||
/// Switch branch.
|
||||
fn switch_branch2(repo: &PathBuf, branch: &str) -> () {
|
||||
Command::new("git")
|
||||
.arg("switch")
|
||||
.arg(branch)
|
||||
.current_dir(repo)
|
||||
.output()
|
||||
.expect("Failed to run command");
|
||||
}
|
||||
|
||||
/// Creates three branches.
|
||||
fn create_branches(repo: &PathBuf) -> () {
|
||||
Command::new("git")
|
||||
.arg("branch")
|
||||
.arg("branch1")
|
||||
.arg("main")
|
||||
.current_dir(repo)
|
||||
.output()
|
||||
.expect("Failed to run command");
|
||||
Command::new("git")
|
||||
.arg("branch")
|
||||
.arg("branch2")
|
||||
.arg("main")
|
||||
.current_dir(repo)
|
||||
.output()
|
||||
.expect("Failed to run command");
|
||||
Command::new("git")
|
||||
.arg("branch")
|
||||
.arg("branch3")
|
||||
.arg("main")
|
||||
.current_dir(repo)
|
||||
.output()
|
||||
.expect("Failed to run command");
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
/// Initialize new git repository at temporary path.
|
||||
///
|
||||
/// Changes working directory into the repo's root.
|
||||
fn repository(tmp_dir: PathBuf) -> (Repository, PathBuf) {
|
||||
set_current_dir(&tmp_dir).expect("Failed to change dir");
|
||||
let repo = Repository::init(&tmp_dir).unwrap();
|
||||
|
||||
let _ = Command::new("git")
|
||||
.arg("commit")
|
||||
.arg("--allow-empty")
|
||||
.arg("--message")
|
||||
.arg("INITIAL COMMIT")
|
||||
.current_dir(&tmp_dir)
|
||||
.output()
|
||||
.expect("Failed to run command");
|
||||
(repo, tmp_dir)
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(String::from(""))]
|
||||
#[case(String::from("2023"))]
|
||||
#[case(String::from("2023/230913"))]
|
||||
#[case(String::from(".git"))]
|
||||
fn test_get_root(repository: (Repository, PathBuf), #[case] relative_path: String) {
|
||||
let mut repo = repository.1;
|
||||
let repo_root = repo.to_owned();
|
||||
repo.push(relative_path);
|
||||
fs::create_dir_all(&repo).expect("Failed to create dir");
|
||||
set_current_dir(&repo).expect("Failed to change dir");
|
||||
let root = get_root().unwrap();
|
||||
assert_eq!(root, repo_root);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_switch_branch(repository: (Repository, PathBuf)) {
|
||||
create_branches(&repository.1);
|
||||
|
||||
assert_eq!(get_current_branch2(&repository.1), String::from("main"));
|
||||
|
||||
assert!(switch_branch(&repository.0, "branch1").is_ok());
|
||||
assert_eq!(get_current_branch2(&repository.1), String::from("branch1"));
|
||||
|
||||
assert!(switch_branch(&repository.0, "main").is_ok());
|
||||
assert_eq!(get_current_branch2(&repository.1), String::from("main"));
|
||||
|
||||
assert!(switch_branch(&repository.0, "main").is_ok());
|
||||
assert_eq!(get_current_branch2(&repository.1), String::from("main"));
|
||||
|
||||
assert!(switch_branch(&repository.0, "branch1").is_ok());
|
||||
assert_eq!(get_current_branch2(&repository.1), String::from("branch1"));
|
||||
|
||||
assert!(switch_branch(&repository.0, "branch3").is_ok());
|
||||
assert_eq!(get_current_branch2(&repository.1), String::from("branch3"));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_get_current_branch(repository: (Repository, PathBuf)) {
|
||||
create_branches(&repository.1);
|
||||
assert_eq!(
|
||||
get_current_branch(&repository.0).unwrap(),
|
||||
String::from("main")
|
||||
);
|
||||
|
||||
switch_branch2(&repository.1, "branch1");
|
||||
assert_eq!(
|
||||
get_current_branch(&repository.0).unwrap(),
|
||||
String::from("branch1")
|
||||
);
|
||||
|
||||
switch_branch2(&repository.1, "main");
|
||||
assert_eq!(
|
||||
get_current_branch(&repository.0).unwrap(),
|
||||
String::from("main")
|
||||
);
|
||||
|
||||
switch_branch2(&repository.1, "branch1");
|
||||
assert_eq!(
|
||||
get_current_branch(&repository.0).unwrap(),
|
||||
String::from("branch1")
|
||||
);
|
||||
|
||||
switch_branch2(&repository.1, "branch3");
|
||||
assert_eq!(
|
||||
get_current_branch(&repository.0).unwrap(),
|
||||
String::from("branch3")
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_branch(repository: (Repository, PathBuf)) {
|
||||
create_branches(&repository.1);
|
||||
|
||||
let mut branches = branch(&repository.0)
|
||||
.unwrap()
|
||||
.filter_map(|b| b.ok())
|
||||
.map(|(branch, _)| branch.name().unwrap().unwrap().to_string())
|
||||
.collect::<Vec<String>>();
|
||||
branches.sort();
|
||||
|
||||
let expected = vec![
|
||||
String::from("branch1"),
|
||||
String::from("branch2"),
|
||||
String::from("branch3"),
|
||||
String::from("main"),
|
||||
];
|
||||
|
||||
assert_eq!(branches, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case("main", true)]
|
||||
#[case("branch1", true)]
|
||||
#[case("branch3", true)]
|
||||
#[case("master", false)]
|
||||
#[case("invalid", false)]
|
||||
fn test_exists_branch(
|
||||
repository: (Repository, PathBuf),
|
||||
#[case] branch: &str,
|
||||
#[case] expected: bool,
|
||||
) {
|
||||
create_branches(&repository.1);
|
||||
assert_eq!(exists_branch(&repository.0, branch), expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_is_dirty(repository: (Repository, PathBuf)) {
|
||||
// Clean Repo
|
||||
assert!(!is_dirty(&repository.1).unwrap());
|
||||
|
||||
// Untracked file
|
||||
let mut file = repository.1.to_owned();
|
||||
file.push("FILE1");
|
||||
fs::write(&file, "bla").unwrap();
|
||||
assert!(is_dirty(&repository.1).unwrap());
|
||||
|
||||
// Staged file
|
||||
Command::new("git")
|
||||
.arg("add")
|
||||
.arg("FILE1")
|
||||
.current_dir(&repository.1)
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(is_dirty(&repository.1).unwrap());
|
||||
|
||||
// Clean Repo
|
||||
Command::new("git")
|
||||
.arg("commit")
|
||||
.arg("--message")
|
||||
.arg("Add FILE1")
|
||||
.current_dir(&repository.1)
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(!is_dirty(&repository.1).unwrap());
|
||||
|
||||
// Unstaged Changes
|
||||
fs::write(&file, "new bla").unwrap();
|
||||
assert!(is_dirty(&repository.1).unwrap());
|
||||
|
||||
// Staged changes
|
||||
Command::new("git")
|
||||
.arg("add")
|
||||
.arg("FILE1")
|
||||
.current_dir(&repository.1)
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(is_dirty(&repository.1).unwrap());
|
||||
|
||||
// Clean Repo
|
||||
Command::new("git")
|
||||
.arg("commit")
|
||||
.arg("--message")
|
||||
.arg("Update FILE1")
|
||||
.current_dir(&repository.1)
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(!is_dirty(&repository.1).unwrap());
|
||||
}
|
||||
|
||||
// fn test_run() {}
|
||||
|
||||
// fn test_show() {}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![feature(absolute_path)]
|
||||
#![feature(let_chains)] // git::switch_branch
|
||||
#![feature(assert_matches)] // replaces `assert!(matches!(x, y))` in tests
|
||||
mod archive;
|
||||
mod commands;
|
||||
mod config;
|
||||
|
@ -8,6 +9,9 @@ mod format_string;
|
|||
mod git;
|
||||
mod metadata;
|
||||
|
||||
#[cfg(test)]
|
||||
mod conftest;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
|
||||
|
|
Loading…
Reference in New Issue