diff --git a/CHANGELOG.md b/CHANGELOG.md index c5261a30325..3ccd6aaca6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### v0.4.1 + +* fix installation via `cargo install` + ### v0.4 * add `remote-ref-list` and `pack-receive` subcommands to **gixp** diff --git a/Cargo.lock b/Cargo.lock index c5458f8258c..2da56a0c4ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "async-io" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c629684e697f58c0e99e5e2d84a840e3b336afbcfdbac7b44c3b1e222c2fd8" +checksum = "33be191d05a54ec120e4667375e2ad49fe506b846463df384460ab801c7ae5dc" dependencies = [ "concurrent-queue", "fastrand", @@ -228,9 +228,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "clap" -version = "3.0.0-beta.1" +version = "3.0.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "860643c53f980f0d38a5e25dfab6c3c93b2cb3aa1fe192643d17a293c6c41936" +checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" dependencies = [ "atty", "bitflags", @@ -247,9 +247,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.0.0-beta.1" +version = "3.0.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb51c9e75b94452505acd21d929323f5a5c6c4735a852adbd39ef5fb1b014f30" +checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" dependencies = [ "heck", "proc-macro-error", @@ -332,6 +332,20 @@ dependencies = [ "build_const", ] +[[package]] +name = "crossbeam" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.4.4" @@ -342,6 +356,43 @@ dependencies = [ "maybe-uninit", ] +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "maybe-uninit", +] + [[package]] name = "crossbeam-utils" version = "0.7.2" @@ -398,9 +449,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39858aa5bac06462d4dd4b9164848eb81ffc4aa5c479746393598fd193afa227" +checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484" dependencies = [ "quote", "syn", @@ -478,6 +529,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + [[package]] name = "env_logger" version = "0.7.1" @@ -492,9 +549,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.4.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cd41440ae7e4734bbd42302f63eaba892afc93a3912dad84006247f0dedb0e" +checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" [[package]] name = "fastrand" @@ -512,6 +569,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "futures-channel" version = "0.3.5" @@ -536,9 +599,9 @@ checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" [[package]] name = "futures-lite" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fcd36beea698b82db5b66b6a6a3053632be70d8455123150b4713e85349618" +checksum = "0db18c5f58083b54b0c416638ea73066722c2815c1e54dd8ba85ee3def593c3a" dependencies = [ "fastrand", "futures-core", @@ -615,10 +678,12 @@ dependencies = [ "crossbeam-channel", "crossbeam-utils", "ctrlc", + "jwalk", "num_cpus", "prodash", "sha-1", "sha1", + "walkdir", ] [[package]] @@ -643,7 +708,7 @@ dependencies = [ [[package]] name = "git-odb" -version = "0.4.0" +version = "0.4.1" dependencies = [ "bstr", "btoi", @@ -658,9 +723,9 @@ dependencies = [ "miniz_oxide", "parking_lot 0.11.0", "pretty_assertions", - "quick-error 2.0.0", "serde", "smallvec", + "tempdir", "tempfile", "thiserror", "uluru", @@ -740,7 +805,7 @@ dependencies = [ [[package]] name = "gitoxide" -version = "0.4.0" +version = "0.4.3" dependencies = [ "anyhow", "argh", @@ -757,7 +822,7 @@ dependencies = [ [[package]] name = "gitoxide-core" -version = "0.4.0" +version = "0.4.1" dependencies = [ "anyhow", "bytesize", @@ -788,9 +853,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151" dependencies = [ "libc", ] @@ -854,9 +919,12 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485" +checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" +dependencies = [ + "cfg-if", +] [[package]] name = "itoa" @@ -864,6 +932,16 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +[[package]] +name = "jwalk" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88746778a47f54f83bc0d3d8ba40ce83808024405356b4d521c2bf93c1273cd4" +dependencies = [ + "crossbeam", + "rayon", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -933,6 +1011,15 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg", +] + [[package]] name = "miniz_oxide" version = "0.4.2" @@ -992,9 +1079,9 @@ dependencies = [ [[package]] name = "nom" -version = "6.0.0-alpha1" +version = "6.0.0-alpha2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25020779544bf717b917323b42f23c9dbef1bd2b97b576df6484a0c8709705c6" +checksum = "5bd3285fb63b4f8b6f48411c2dd483e2fef0188cd00a1397c106b6f7b35077b9" dependencies = [ "memchr", "version_check", @@ -1054,9 +1141,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-src" -version = "111.10.2+1.1.1g" +version = "111.11.0+1.1.1h" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a287fdb22e32b5b60624d4a5a7a02dbe82777f730ec0dbc42a0554326fef5a70" +checksum = "380fe324132bea01f45239fadfec9343adb044615f29930d039bec1ae7b9fa5b" dependencies = [ "cc", ] @@ -1154,18 +1241,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa" +checksum = "f48fad7cfbff853437be7cf54d7b993af21f53be7f0988cbfe4a51535aa77205" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" +checksum = "24c6d293bdd3ca5a1697997854c6cf7855e43fb6a0ba1c47af57a5bcafd158ae" dependencies = [ "proc-macro2", "quote", @@ -1174,9 +1261,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" +checksum = "71f349a4f0e70676ffb2dbafe16d0c992382d02f0a952e3ddf584fc289dac6b3" [[package]] name = "pin-utils" @@ -1192,9 +1279,9 @@ checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" [[package]] name = "polling" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0307b8c7f438902536321f63c28cab0362f6ee89f1c7da47e3642ff956641c8b" +checksum = "e0720e0b9ea9d52451cf29d3413ba8a9303f8815d9d9653ef70e03ff73e65566" dependencies = [ "cfg-if", "libc", @@ -1223,9 +1310,9 @@ dependencies = [ [[package]] name = "proc-macro-error" -version = "0.4.12" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2", @@ -1236,14 +1323,12 @@ dependencies = [ [[package]] name = "proc-macro-error-attr" -version = "0.4.12" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", - "syn", - "syn-mid", "version_check", ] @@ -1255,9 +1340,9 @@ checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "51ef7cd2518ead700af67bf9d1a658d90b6037d77110fd9c0445429d0ba1c6c9" dependencies = [ "unicode-xid", ] @@ -1306,6 +1391,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.7.3" @@ -1315,7 +1413,7 @@ dependencies = [ "getrandom", "libc", "rand_chacha", - "rand_core", + "rand_core 0.5.1", "rand_hc", ] @@ -1326,9 +1424,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.5.1" @@ -1344,7 +1457,41 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rayon" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", ] [[package]] @@ -1584,9 +1731,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228" dependencies = [ "proc-macro2", "quote", @@ -1594,14 +1741,13 @@ dependencies = [ ] [[package]] -name = "syn-mid" -version = "0.5.0" +name = "tempdir" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" dependencies = [ - "proc-macro2", - "quote", - "syn", + "rand 0.4.6", + "remove_dir_all", ] [[package]] @@ -1612,7 +1758,7 @@ checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ "cfg-if", "libc", - "rand", + "rand 0.7.3", "redox_syscall", "remove_dir_all", "winapi", @@ -1641,9 +1787,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" dependencies = [ "unicode-width", ] @@ -1670,9 +1816,9 @@ dependencies = [ [[package]] name = "time" -version = "0.2.20" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4953c513c9bf1b97e9cdd83f11d60c4b0a83462880a360d80d96953a953fee" +checksum = "55b7151c9065e80917fbf285d9a5d1432f60db41d170ccafc749a136b41a93af" dependencies = [ "const_fn", "libc", diff --git a/Cargo.toml b/Cargo.toml index 48144ab18bf..153198026c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/Byron/git-oxide" authors = ["Sebastian Thiel "] edition = "2018" license = "MIT OR Apache-2.0" -version = "0.4.0" +version = "0.4.3" default-run = "gix" include = ["src/**/*", "LICENSE-*", "README.md", "CHANGELOG.md"] @@ -64,7 +64,7 @@ git-features = { version = "^0.6.0", path = "git-features" } # just for feature configuration git-transport = { optional = true, version = "^0.2.0", path = "git-transport" } -clap = { version = "3.0.0-beta.1", optional = true } +clap = { version = "=3.0.0-beta.2", optional = true } argh = { version = "0.1.3", optional = true, default-features = false } prodash = { version = "10.0.0", optional = true, default-features = false } atty = { version = "0.2.14", optional = true, default-features = false } diff --git a/README.md b/README.md index 32e06636efc..8f25b7605bd 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,13 @@ Please see _'Development Status'_ for a listing of all crates and their capabili ## Development Status +**Please note** that from 2020-09-17, the development speed will be reduced greatly. I will do my best to create at least +one commit per day ramp it up from there to eventually arrive at a new baseline velocity. It will be lower than what it was before, and +I hope 1/2 to 2/3 of that will be realistic. + +This is entirely unrelated to the project and I still can't wait to use `gitoxide` on a daily basis once the first high-level commands +become available. + ### gitoxide _(CLI)_ * please note that all functionality comes from the `gitoxide-core` library, which mirrors these capabilities and itself relies on all `git-*` crates. @@ -84,9 +91,9 @@ Please see _'Development Status'_ for a listing of all crates and their capabili * **sink** * [x] write objects and obtain id * **alternates** - * [ ] _database that act as link to other known ODB types on disk_ - * [ ] handles cycles - * [ ] handles recursive configurations + * _database that act as link to other known git ODBs on disk_ + * [x] safe with cycles and recursive configurations + * [x] multi-line with comments and quotes * **multi-odb** * [ ] _an ODB for object lookup from multiple lower level ODB at once_ * **promisor** @@ -164,17 +171,24 @@ Please see _'Development Status'_ for a listing of all crates and their capabili * handle git index files for primary use by the git-repository while crafting new commits * [ ] API documentation with examples +### git-bundle + * [ ] create a bundle from an archive + * [ ] extract a branch from a bundle into a repository + ### git-repository * [x] initialize * [ ] Proper configuration depending on platform (e.g. ignorecase, filemode, …) * [ ] [Signed commits and tags](https://github.com/Byron/gitoxide/issues/12) * [ ] clone * [ ] shallow + * [ ] namespaces support * [ ] sparse checkout support + * [ ] execute hooks * [ ] .gitignore handling * [ ] checkout/stage conversions clean + smudge as in .gitattributes * [ ] read and write all data types * [ ] rev-parsing and ref history + * [ ] worktree * [ ] remotes with push and pull * [ ] configuration * [ ] merging diff --git a/etc/check-package-size.sh b/etc/check-package-size.sh index bb4bb341663..4e67264adec 100755 --- a/etc/check-package-size.sh +++ b/etc/check-package-size.sh @@ -20,7 +20,7 @@ indent cargo diet -n --package-size-limit 25KB (enter git-ref && indent cargo diet -n --package-size-limit 4KB) (enter git-url && indent cargo diet -n --package-size-limit 6KB) (enter git-object && indent cargo diet -n --package-size-limit 15KB) -(enter git-odb && indent cargo diet -n --package-size-limit 50KB) +(enter git-odb && indent cargo diet -n --package-size-limit 55KB) (enter git-protocol && indent cargo diet -n --package-size-limit 20KB) (enter git-packetline && indent cargo diet -n --package-size-limit 7KB) (enter git-repository && indent cargo diet -n --package-size-limit 10KB) diff --git a/git-features/Cargo.toml b/git-features/Cargo.toml index a33a98f8438..e95e6995228 100644 --- a/git-features/Cargo.toml +++ b/git-features/Cargo.toml @@ -12,7 +12,7 @@ doctest = false test = false [features] -parallel = ["crossbeam-utils", "crossbeam-channel", "num_cpus"] +parallel = ["crossbeam-utils", "crossbeam-channel", "num_cpus", "jwalk"] fast-sha1 = ["fastsha1"] interrupt-handler = ["ctrlc"] disable-interrupts = [] @@ -34,6 +34,9 @@ crossbeam-utils = { version = "0.7.2", optional = true } crossbeam-channel = { version = "0.4.2", optional = true } num_cpus = { version = "1.13.0", optional = true } +jwalk = { version = "0.5.1", optional = true } +walkdir = { version = "2.3.1" } # used when parallel is off + # hashing and 'fast-sha1' feature sha1 = "0.6.0" crc = "1.8.1" diff --git a/git-features/src/fs.rs b/git-features/src/fs.rs new file mode 100644 index 00000000000..9848ac64284 --- /dev/null +++ b/git-features/src/fs.rs @@ -0,0 +1,11 @@ +#[cfg(feature = "parallel")] +pub mod walkdir { + pub use jwalk::{Error, WalkDir}; +} + +#[cfg(not(feature = "parallel"))] +pub mod walkdir { + pub use walkdir::{Error, WalkDir}; +} + +pub use self::walkdir::WalkDir; diff --git a/git-features/src/lib.rs b/git-features/src/lib.rs index 20f3986933b..85b07041613 100644 --- a/git-features/src/lib.rs +++ b/git-features/src/lib.rs @@ -1,5 +1,6 @@ #![forbid(unsafe_code, rust_2018_idioms)] +pub mod fs; pub mod hash; pub mod interrupt; pub mod parallel; diff --git a/git-odb/Cargo.toml b/git-odb/Cargo.toml index 85fcc94864b..77f17f0d0eb 100644 --- a/git-odb/Cargo.toml +++ b/git-odb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "git-odb" -version = "0.4.0" +version = "0.4.1" repository = "https://github.com/Byron/git-oxide" authors = ["Sebastian Thiel "] license = "MIT/Apache-2.0" @@ -21,7 +21,6 @@ all-features = true git-object = { version = "^0.4.0", path = "../git-object" } git-features = { version = "^0.6.0", path = "../git-features" } -quick-error = "2.0.0" walkdir = "2.1.4" miniz_oxide = "0.4.1" smallvec = "1.3.0" @@ -41,3 +40,4 @@ pretty_assertions = "0.6.1" bstr = { version = "0.2.13", default-features = false, features = ["std"] } hex = "0.4.2" common_macros = "0.1.1" +tempdir = "0.3.7" diff --git a/git-odb/src/alternate/mod.rs b/git-odb/src/alternate/mod.rs new file mode 100644 index 00000000000..38b3fd5d2f1 --- /dev/null +++ b/git-odb/src/alternate/mod.rs @@ -0,0 +1,52 @@ +use crate::compound; +use std::{fs, io, path::PathBuf}; + +pub mod parse; +pub mod unquote; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Io(#[from] io::Error), + #[error(transparent)] + Parse(#[from] parse::Error), + #[error(transparent)] + Init(#[from] compound::init::Error), + #[error("Alternates form a cycle: {} -> {}", .0.iter().map(|p| format!("'{}'", p.display())).collect::>().join(" -> "), .0.first().expect("more than one directories").display())] + Cycle(Vec), +} + +pub fn resolve(objects_directory: impl Into) -> Result, Error> { + let relative_base = objects_directory.into(); + let mut dirs = vec![(0, relative_base.clone())]; + let mut out = Vec::new(); + let mut seen = vec![relative_base.canonicalize()?]; + while let Some((depth, dir)) = dirs.pop() { + match fs::read(dir.join("info").join("alternates")) { + Ok(input) => { + for path in parse::content(&input)?.into_iter() { + let path = relative_base.join(path); + let path_canonicalized = path.canonicalize()?; + if seen.contains(&path_canonicalized) { + continue; + } + seen.push(path_canonicalized); + dirs.push((depth + 1, path)); + } + } + Err(err) if err.kind() == io::ErrorKind::NotFound => { + // Only resolve for repositories with at least one link, otherwise the line below causes infinite recursion + if depth != 0 { + // The tail of a chain doesn't have alternates, and thus is the real deal + out.push(compound::Db::at(dir)?); + } + } + Err(err) => return Err(err.into()), + }; + } + + if out.is_empty() && seen.len() > 1 { + return Err(Error::Cycle(seen)); + } + Ok(out) +} diff --git a/git-odb/src/alternate/parse.rs b/git-odb/src/alternate/parse.rs new file mode 100644 index 00000000000..0cbe0e70380 --- /dev/null +++ b/git-odb/src/alternate/parse.rs @@ -0,0 +1,32 @@ +use crate::alternate::unquote; +use git_object::bstr::ByteSlice; +use std::{borrow::Cow, path::PathBuf}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Could not obtain an object path for the alternate directory '{}'", String::from_utf8_lossy(&.0))] + PathConversion(Vec), + #[error("Could not unquote alternate path")] + Unquote(#[from] unquote::Error), +} + +pub(crate) fn content(input: &[u8]) -> Result, Error> { + let mut out = Vec::new(); + for line in input.split(|b| *b == b'\n') { + let line = line.as_bstr(); + if line.is_empty() || line.starts_with(b"#") { + continue; + } + out.push( + if line.starts_with(b"\"") { + unquote::ansi_c(line)? + } else { + Cow::Borrowed(line) + } + .to_path() + .map(ToOwned::to_owned) + .map_err(|_| Error::PathConversion(line.to_vec()))?, + ) + } + Ok(out) +} diff --git a/git-odb/src/alternate/unquote.rs b/git-odb/src/alternate/unquote.rs new file mode 100644 index 00000000000..a8a3d523c8c --- /dev/null +++ b/git-odb/src/alternate/unquote.rs @@ -0,0 +1,120 @@ +use git_object::bstr::{BStr, BString, ByteSlice}; +use std::borrow::Cow; +use std::io::Read; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("{message}: {:?}", String::from_utf8_lossy(&.input))] + InvalidInput { message: String, input: Vec }, + #[error("Invalid escaped value {byte} in input {:?}", String::from_utf8_lossy(&.input))] + UnsupportedEscapeByte { byte: u8, input: Vec }, +} + +impl Error { + fn new(message: impl ToString, input: &BStr) -> Error { + Error::InvalidInput { + message: message.to_string(), + input: input.to_vec(), + } + } +} + +pub fn ansi_c(input: &BStr) -> Result, Error> { + if !input.starts_with(b"\"") { + return Ok(input.into()); + } + if input.len() < 2 { + return Err(Error::new("Input must be surrounded by double quotes", input)); + } + let original = input.as_bstr(); + let mut input = &input[1..]; + let mut out = BString::default(); + fn consume_one_past(input: &mut &BStr, position: usize) -> Result { + *input = input + .get(position + 1..) + .ok_or_else(|| Error::new("Unexpected end of input", input))? + .as_bstr(); + let next = input[0]; + *input = input.get(1..).unwrap_or_default().as_bstr(); + Ok(next) + } + loop { + match input.find_byteset(b"\"\\") { + Some(position) => { + out.extend_from_slice(&input[..position]); + match input[position] { + b'"' => break, + b'\\' => { + let next = consume_one_past(&mut input, position)?; + match next { + b'n' => out.push(b'\n'), + b'r' => out.push(b'\r'), + b't' => out.push(b'\t'), + b'a' => out.push(7), + b'b' => out.push(8), + b'v' => out.push(0xb), + b'f' => out.push(0xc), + b'"' => out.push(b'"'), + b'\\' => out.push(b'\\'), + b'0' | b'1' | b'2' | b'3' => { + let mut buf = [next; 3]; + input + .get(..2) + .ok_or_else(|| { + Error::new("Unexpected end of input when fetching two more octal bytes", input) + })? + .read_exact(&mut buf[1..]) + .expect("impossible to fail as numbers match"); + let byte = btoi::btou_radix(&buf, 8).map_err(|e| Error::new(e, original))?; + out.push(byte); + input = &input[2..]; + } + _ => { + return Err(Error::UnsupportedEscapeByte { + byte: next, + input: original.to_vec(), + }) + } + } + } + _ => unreachable!("cannot find character that we didn't search for"), + } + } + None => { + out.extend_from_slice(input); + break; + } + } + } + Ok(out.into()) +} + +#[cfg(test)] +mod tests { + use super::*; + use git_object::bstr::ByteSlice; + + macro_rules! test { + ($name:ident, $input:literal, $expected:literal) => { + #[test] + fn $name() { + assert_eq!( + ansi_c($input.as_bytes().as_bstr()).expect("valid input"), + std::borrow::Cow::Borrowed($expected.as_bytes().as_bstr()) + ); + } + }; + } + + test!(unquoted_remains_unchanged, "hello", "hello"); + test!(empty_surrounded_by_quotes, "\"\"", ""); + test!(surrounded_only_by_quotes, "\"hello\"", "hello"); + test!(typical_escapes, r#""\n\r\t""#, b"\n\r\t"); + test!(untypical_escapes, r#""\a\b\f\v""#, b"\x07\x08\x0c\x0b"); + test!(literal_escape_and_double_quote, r#""\"\\""#, br#""\"#); + test!( + unicode_byte_escapes_by_number, + r#""\346\277\261\351\207\216\t\347\264\224""#, + "濱野\t純" + ); +} diff --git a/git-odb/src/compound/init.rs b/git-odb/src/compound/init.rs index 96b797e1691..3f49904160c 100644 --- a/git-odb/src/compound/init.rs +++ b/git-odb/src/compound/init.rs @@ -1,22 +1,23 @@ use crate::{compound, loose, pack}; -use quick_error::quick_error; use std::path::PathBuf; -quick_error! { - #[derive(Debug)] - pub enum Error { - Pack(err: pack::bundle::Error) { - display("Failed to instantiate a pack bundle") - source(err) - from() - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("The objects directory at '{0}' is not an accessible directory")] + Inaccessible(PathBuf), + #[error(transparent)] + Pack(#[from] pack::bundle::Error), + #[error(transparent)] + Alternate(#[from] Box), } /// Instantiation impl compound::Db { pub fn at(objects_directory: impl Into) -> Result { let loose_objects = objects_directory.into(); + if !loose_objects.is_dir() { + return Err(Error::Inaccessible(loose_objects)); + } let packs = if let Ok(entries) = std::fs::read_dir(loose_objects.join("packs")) { let mut packs_and_sizes = entries .filter_map(Result::ok) @@ -32,8 +33,9 @@ impl compound::Db { }; Ok(compound::Db { - loose: loose::Db::at(loose_objects), + loose: loose::Db::at(loose_objects.clone()), packs, + alternates: crate::alternate::resolve(loose_objects).map_err(Box::new)?, }) } } diff --git a/git-odb/src/compound/locate.rs b/git-odb/src/compound/locate.rs index 001982f8ec0..8fff2967c19 100644 --- a/git-odb/src/compound/locate.rs +++ b/git-odb/src/compound/locate.rs @@ -1,21 +1,12 @@ use crate::{compound, loose, pack}; use git_object::borrowed; -use quick_error::quick_error; -quick_error! { - #[derive(Debug)] - pub enum Error { - Loose(err: loose::db::locate::Error) { - display("An error occurred while obtaining an object from the loose object store") - source(err) - from() - } - Pack(err: pack::bundle::locate::Error) { - display("An error occurred while obtaining an object from the packed object store") - source(err) - from() - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("An error occurred while obtaining an object from the loose object store")] + Loose(#[from] loose::db::locate::Error), + #[error("An error occurred while obtaining an object from the packed object store")] + Pack(#[from] pack::bundle::locate::Error), } impl compound::Db { @@ -24,6 +15,14 @@ impl compound::Db { id: borrowed::Id<'_>, buffer: &'a mut Vec, ) -> Option, Error>> { + for alternate in &self.alternates { + // See 8c5bd095539042d7db0e611460803cdbf172beb0 for a commit that adds polonius and makes the proper version compile. + // See https://stackoverflow.com/questions/63906425/nll-limitation-how-to-work-around-cannot-borrow-buf-as-mutable-more-than?noredirect=1#comment113007288_63906425 + // More see below! Of course we don't want to do the lookup twice… but have to until this is fixed or we compile nightly. + if alternate.locate(id, buffer).is_some() { + return alternate.locate(id, buffer); + } + } for pack in &self.packs { // See 8c5bd095539042d7db0e611460803cdbf172beb0 for a commit that adds polonius and makes the proper version compile. // See https://stackoverflow.com/questions/63906425/nll-limitation-how-to-work-around-cannot-borrow-buf-as-mutable-more-than?noredirect=1#comment113007288_63906425 diff --git a/git-odb/src/compound/mod.rs b/git-odb/src/compound/mod.rs index b1f0986ac05..6420e80f112 100644 --- a/git-odb/src/compound/mod.rs +++ b/git-odb/src/compound/mod.rs @@ -3,6 +3,7 @@ use crate::{loose, pack}; pub struct Db { pub loose: loose::Db, pub packs: Vec, + pub alternates: Vec, } pub mod object { @@ -90,6 +91,6 @@ pub mod object { } pub use object::Object; -mod init; -mod locate; +pub mod init; +pub mod locate; mod write; diff --git a/git-odb/src/lib.rs b/git-odb/src/lib.rs index 8ff53570621..4f9b6473450 100644 --- a/git-odb/src/lib.rs +++ b/git-odb/src/lib.rs @@ -2,6 +2,7 @@ mod zlib; +pub mod alternate; pub mod compound; pub mod loose; pub mod pack; diff --git a/git-odb/src/loose/db/iter.rs b/git-odb/src/loose/db/iter.rs index 4baa2bcea62..41fc9df1cd4 100644 --- a/git-odb/src/loose/db/iter.rs +++ b/git-odb/src/loose/db/iter.rs @@ -1,22 +1,17 @@ use crate::loose::Db; +use git_features::fs::WalkDir; use git_object::owned; -use quick_error::quick_error; -use walkdir::WalkDir; -quick_error! { - #[derive(Debug)] - pub enum Error { - WalkDir(err: walkdir::Error) { - source(err) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + WalkDir(#[from] git_features::fs::walkdir::Error), } /// Iteration and traversal impl Db { pub fn iter(&self) -> impl Iterator> { use std::path::Component::Normal; - // TODO: Put this behind a feature flag in git-features and allow iterating with jwalk WalkDir::new(&self.path) .min_depth(2) .max_depth(3) diff --git a/git-odb/src/loose/db/write.rs b/git-odb/src/loose/db/write.rs index fc742af4077..2e97e5c5c44 100644 --- a/git-odb/src/loose/db/write.rs +++ b/git-odb/src/loose/db/write.rs @@ -1,27 +1,24 @@ use super::Db; use crate::{hash, loose, zlib::stream::DeflateWriter}; use git_object::{owned, HashKind}; -use quick_error::quick_error; use std::{fs, io, io::Write, path::PathBuf}; use tempfile::NamedTempFile; -quick_error! { - #[derive(Debug)] - pub enum Error { - Io(err: io::Error, msg: &'static str, path: PathBuf) { - display("Could not {} '{}'", msg, path.display()) - source(err) - } - IoRaw(err: io::Error) { - display("An IO error occurred while writing an object") - source(err) - from() - } - Persist(err: tempfile::PersistError, target: PathBuf) { - display("Could not turn temporary file into persisted file at '{}'", target.display()) - source(err) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Could not {message} '{path}'")] + Io { + source: io::Error, + message: &'static str, + path: PathBuf, + }, + #[error("An IO error occurred while writing an object")] + IoRaw(#[from] io::Error), + #[error("Could not turn temporary file into persisted file at '{target}'")] + Persist { + source: tempfile::PersistError, + target: PathBuf, + }, } impl crate::Write for Db { @@ -31,8 +28,11 @@ impl crate::Write for Db { match hash { HashKind::Sha1 => { let mut to = self.write_header(kind, from.len() as u64, hash)?; - to.write_all(from) - .map_err(|err| Error::Io(err, "stream all data into tempfile in", self.path.to_owned()))?; + to.write_all(from).map_err(|err| Error::Io { + source: err, + message: "stream all data into tempfile in", + path: self.path.to_owned(), + })?; to.flush()?; self.finalize_object(to) } @@ -49,8 +49,11 @@ impl crate::Write for Db { match hash { HashKind::Sha1 => { let mut to = self.write_header(kind, size, hash)?; - io::copy(&mut from, &mut to) - .map_err(|err| Error::Io(err, "stream all data into tempfile in", self.path.to_owned()))?; + io::copy(&mut from, &mut to).map_err(|err| Error::Io { + source: err, + message: "stream all data into tempfile in", + path: self.path.to_owned(), + })?; to.flush()?; self.finalize_object(to) } @@ -68,15 +71,19 @@ impl Db { hash: HashKind, ) -> Result, Error> { let mut to = hash::Write::new( - DeflateWriter::new( - NamedTempFile::new_in(&self.path) - .map_err(|err| Error::Io(err, "create named temp file in", self.path.to_owned()))?, - ), + DeflateWriter::new(NamedTempFile::new_in(&self.path).map_err(|err| Error::Io { + source: err, + message: "create named temp file in", + path: self.path.to_owned(), + })?), hash, ); - loose::object::header::encode(kind, size, &mut to) - .map_err(|err| Error::Io(err, "write header to tempfile in", self.path.to_owned()))?; + loose::object::header::encode(kind, size, &mut to).map_err(|err| Error::Io { + source: err, + message: "write header to tempfile in", + path: self.path.to_owned(), + })?; Ok(to) } @@ -96,8 +103,10 @@ impl Db { } } let file = file.into_inner(); - file.persist(&object_path) - .map_err(|err| Error::Persist(err, object_path))?; + file.persist(&object_path).map_err(|err| Error::Persist { + source: err, + target: object_path, + })?; Ok(id) } } diff --git a/git-odb/src/loose/object/decode.rs b/git-odb/src/loose/object/decode.rs index df517adcab1..f77325869a6 100644 --- a/git-odb/src/loose/object/decode.rs +++ b/git-odb/src/loose/object/decode.rs @@ -3,28 +3,21 @@ use crate::{loose, zlib}; use git_object as object; use miniz_oxide::inflate::decompress_to_vec_zlib; use object::borrowed; -use quick_error::quick_error; use smallvec::SmallVec; use std::{io::Read, path::PathBuf}; -quick_error! { - #[derive(Debug)] - pub enum Error { - Decompress(err: zlib::Error) { - display("decompression of object data failed") - from() - source(err) - } - Parse(err: borrowed::Error) { - display("Could not parse object object") - from() - source(err) - } - Io(err: std::io::Error, action: &'static str, path: PathBuf) { - display("Could not {} data at '{}'", action, path.display()) - source(err) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("decompression of object data failed")] + Decompress(#[from] zlib::Error), + #[error(transparent)] + Parse(#[from] borrowed::Error), + #[error("Could not {action} data at '{path}'")] + Io { + source: std::io::Error, + action: &'static str, + path: PathBuf, + }, } impl loose::Object { @@ -40,7 +33,11 @@ impl loose::Object { match &self.path { Some(path) => Ok(stream::Reader::from_read( self.header_size, - std::fs::File::open(path).map_err(|e| Error::Io(e, "open", path.to_owned()))?, + std::fs::File::open(path).map_err(|source| Error::Io { + source, + action: "open", + path: path.to_owned(), + })?, )), None => { self.decompress_all()?; @@ -64,13 +61,25 @@ impl loose::Object { if let Some(path) = self.path.take() { // NOTE: For now we just re-read everything from the beginning without seeking, as our buffer // is small so the seek might be more expensive than just reading everything. - let mut file = std::fs::File::open(&path).map_err(|e| Error::Io(e, "open", path.clone()))?; + let mut file = std::fs::File::open(&path).map_err(|source| Error::Io { + source, + action: "open", + path: path.clone(), + })?; let file_size = file .metadata() - .map_err(|e| Error::Io(e, "read metadata", path.clone()))? + .map_err(|source| Error::Io { + source, + action: "read metadata", + path: path.clone(), + })? .len() as usize; let mut buf = Vec::with_capacity(file_size); - file.read_to_end(&mut buf).map_err(|e| Error::Io(e, "read", path))?; + file.read_to_end(&mut buf).map_err(|source| Error::Io { + source, + action: "read", + path, + })?; self.compressed_data = SmallVec::from(buf); } self.decompressed_data = SmallVec::from(decompress_to_vec_zlib(&self.compressed_data[..]).unwrap()); diff --git a/git-odb/src/loose/object/header.rs b/git-odb/src/loose/object/header.rs index c012eb7b661..22b6eb77ae7 100644 --- a/git-odb/src/loose/object/header.rs +++ b/git-odb/src/loose/object/header.rs @@ -1,23 +1,18 @@ use byteorder::WriteBytesExt; use git_object as object; -use quick_error::quick_error; -quick_error! { - #[derive(Debug)] - pub enum Error { - ParseIntegerError(msg: &'static str, number: Vec, err: btoi::ParseIntegerError) { - display("{}: {:?}", msg, std::str::from_utf8(number)) - source(err) - } - InvalidHeader(msg: &'static str) { - display("{}", msg) - } - ObjectHeader(err: object::Error) { - display("Could not parse object kind") - from() - source(err) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("{message}: {:?}", std::str::from_utf8(.number))] + ParseIntegerError { + source: btoi::ParseIntegerError, + message: &'static str, + number: Vec, + }, + #[error("{0}")] + InvalidHeader(&'static str), + #[error(transparent)] + ObjectHeader(#[from] object::Error), } pub fn decode(input: &[u8]) -> Result<(object::Kind, u64, usize), Error> { @@ -30,8 +25,10 @@ pub fn decode(input: &[u8]) -> Result<(object::Kind, u64, usize), Error> { match (split.next(), split.next()) { (Some(kind), Some(size)) => Ok(( object::Kind::from_bytes(kind)?, - btoi::btoi(size).map_err(|e| { - Error::ParseIntegerError("Object size in header could not be parsed", size.to_owned(), e) + btoi::btoi(size).map_err(|source| Error::ParseIntegerError { + message: "Object size in header could not be parsed", + number: size.to_owned(), + source, })?, header_end + 1, // account for 0 byte )), diff --git a/git-odb/src/loose/object/verify.rs b/git-odb/src/loose/object/verify.rs index 23c0fc24c2f..4e2f74fd1f0 100644 --- a/git-odb/src/loose/object/verify.rs +++ b/git-odb/src/loose/object/verify.rs @@ -1,25 +1,15 @@ use crate::{hash::Write as HashWrite, loose}; use git_object::{borrowed, owned}; -use quick_error::quick_error; use std::io; -quick_error! { - #[derive(Debug)] - pub enum Error { - Io(err: io::Error) { - display("reading of object failed") - from() - source(err) - } - Decode(err: super::decode::Error) { - display("Decoding of object failed") - from() - source(err) - } - ChecksumMismatch(desired: owned::Id, actual: owned::Id) { - display("Object expected to have id {}, but actual id was {}", desired, actual) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("reading of object failed")] + Io(#[from] io::Error), + #[error("Decoding of object failed")] + Decode(#[from] super::decode::Error), + #[error("Object expected to have id {desired}, but actual id was {actual}")] + ChecksumMismatch { desired: owned::Id, actual: owned::Id }, } impl loose::Object { @@ -31,9 +21,12 @@ impl loose::Object { loose::object::header::encode(kind, size as u64, &mut sink).expect("hash to always work"); io::copy(&mut reader, &mut sink)?; - let actual_id = owned::Id::from(sink.hash.digest()); - if desired != actual_id.to_borrowed() { - return Err(Error::ChecksumMismatch(desired.into(), actual_id)); + let actual = owned::Id::from(sink.hash.digest()); + if desired != actual.to_borrowed() { + return Err(Error::ChecksumMismatch { + desired: desired.into(), + actual, + }); } Ok(()) } diff --git a/git-odb/src/pack/bundle/locate.rs b/git-odb/src/pack/bundle/locate.rs index ac8aed6ffe6..2c8dce59812 100644 --- a/git-odb/src/pack/bundle/locate.rs +++ b/git-odb/src/pack/bundle/locate.rs @@ -1,14 +1,10 @@ use crate::pack; use git_object::borrowed; -use quick_error::quick_error; -quick_error! { - #[derive(Debug)] - pub enum Error { - Decode(err: pack::data::decode::Error) { - display("Could not decode object") - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Decode(pack::data::decode::Error), } impl pack::Bundle { diff --git a/git-odb/src/pack/bundle/mod.rs b/git-odb/src/pack/bundle/mod.rs index 45047afd425..fb3922cd559 100644 --- a/git-odb/src/pack/bundle/mod.rs +++ b/git-odb/src/pack/bundle/mod.rs @@ -1,5 +1,4 @@ use crate::pack; -use quick_error::quick_error; use std::{ convert::TryFrom, path::{Path, PathBuf}, @@ -8,23 +7,14 @@ use std::{ pub mod locate; pub mod write; -quick_error! { - #[derive(Debug)] - pub enum Error { - InvalidPath(path: PathBuf) { - display("An 'idx' extension is expected of an index file: '{}'", path.display()) - } - Pack(err: pack::data::parse::Error) { - display("Could not instantiate pack") - from() - source(err) - } - Index(err: pack::index::init::Error) { - display("Could not instantiate pack index") - from() - source(err) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("An 'idx' extension is expected of an index file: '{0}'")] + InvalidPath(PathBuf), + #[error(transparent)] + Pack(#[from] pack::data::parse::Error), + #[error(transparent)] + Index(#[from] pack::index::init::Error), } /// A packfile with an index diff --git a/git-odb/src/pack/bundle/write/error.rs b/git-odb/src/pack/bundle/write/error.rs index f59416e2ae8..5be254a7770 100644 --- a/git-odb/src/pack/bundle/write/error.rs +++ b/git-odb/src/pack/bundle/write/error.rs @@ -1,29 +1,14 @@ use crate::pack; -use quick_error::quick_error; use std::io; -quick_error! { - #[derive(Debug)] - pub enum Error { - Io(err: io::Error) { - display("An IO error occurred when reading the pack or creating a temporary file") - from() - source(err) - } - PackIter(err: pack::data::iter::Error) { - display("Pack iteration failed") - from() - source(err) - } - PeristError(err: tempfile::PersistError) { - display("Could not move a temporary file into its desired place") - from() - source(err) - } - IndexWrite(err: pack::index::write::Error) { - display("The index file could not be written") - from() - source(err) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("An IO error occurred when reading the pack or creating a temporary file")] + Io(#[from] io::Error), + #[error(transparent)] + PackIter(#[from] pack::data::iter::Error), + #[error("Could not move a temporary file into its desired place")] + PeristError(#[from] tempfile::PersistError), + #[error(transparent)] + IndexWrite(#[from] pack::index::write::Error), } diff --git a/git-odb/src/pack/data/verify.rs b/git-odb/src/pack/data/verify.rs index b1ad3cd8617..26cd1f3b276 100644 --- a/git-odb/src/pack/data/verify.rs +++ b/git-odb/src/pack/data/verify.rs @@ -1,20 +1,13 @@ use crate::pack::data::File; use git_features::progress::Progress; use git_object::{owned, SHA1_SIZE}; -use quick_error::quick_error; -quick_error! { - #[derive(Debug)] - pub enum Error { - Mismatch { expected: owned::Id, actual: owned::Id } { - display("pack checksum mismatch: expected {}, got {}", expected, actual) - } - Io(err: std::io::Error) { - display("could not read pack file") - from() - source(err) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("pack checksum mismatch: expected {expected}, got {actual}")] + Mismatch { expected: owned::Id, actual: owned::Id }, + #[error("could not read pack file")] + Io(#[from] std::io::Error), } /// Checksums and verify checksums diff --git a/git-odb/src/pack/index/init.rs b/git-odb/src/pack/index/init.rs index da98eb399bd..3b0dc7c1b37 100644 --- a/git-odb/src/pack/index/init.rs +++ b/git-odb/src/pack/index/init.rs @@ -2,23 +2,19 @@ use crate::pack::index::{self, Kind, FAN_LEN, V2_SIGNATURE}; use byteorder::{BigEndian, ByteOrder}; use filebuffer::FileBuffer; use git_object::SHA1_SIZE; -use quick_error::quick_error; use std::{convert::TryFrom, mem::size_of, path::Path}; -quick_error! { - #[derive(Debug)] - pub enum Error { - Io(err: std::io::Error, path: std::path::PathBuf) { - display("Could not open pack index file at '{}'", path.display()) - source(err) - } - Corrupt(msg: String) { - display("{}", msg) - } - UnsupportedVersion(version: u32) { - display("Unsupported index version: {}", version) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Could not open pack index file at '{path}'")] + Io { + source: std::io::Error, + path: std::path::PathBuf, + }, + #[error("{message}")] + Corrupt { message: String }, + #[error("Unsupported index version: {version})")] + UnsupportedVersion { version: u32 }, } const N32_SIZE: usize = size_of::(); @@ -35,13 +31,15 @@ impl TryFrom<&Path> for index::File { type Error = Error; fn try_from(path: &Path) -> Result { - let data = FileBuffer::open(&path).map_err(|e| Error::Io(e, path.to_owned()))?; + let data = FileBuffer::open(&path).map_err(|e| Error::Io { + source: e, + path: path.to_owned(), + })?; let idx_len = data.len(); if idx_len < FAN_LEN * N32_SIZE + FOOTER_SIZE { - return Err(Error::Corrupt(format!( - "Pack index of size {} is too small for even an empty index", - idx_len - ))); + return Err(Error::Corrupt { + message: format!("Pack index of size {} is too small for even an empty index", idx_len), + }); } let (kind, version, fan, num_objects) = { let (kind, d) = { @@ -53,16 +51,16 @@ impl TryFrom<&Path> for index::File { } }; let (version, d) = { - let (mut v, mut d) = (1, d); + let (mut version, mut d) = (1, d); if let Kind::V2 = kind { let (vd, dr) = d.split_at(N32_SIZE); d = dr; - v = BigEndian::read_u32(vd); - if v != Kind::V2 as u32 { - return Err(Error::UnsupportedVersion(v)); + version = BigEndian::read_u32(vd); + if version != Kind::V2 as u32 { + return Err(Error::UnsupportedVersion { version }); } } - (v, d) + (version, d) }; let (fan, bytes_read) = read_fan(d); let (_, _d) = d.split_at(bytes_read); diff --git a/git-odb/src/pack/index/write/error.rs b/git-odb/src/pack/index/write/error.rs index 64f4e643d73..a80ff12cdf8 100644 --- a/git-odb/src/pack/index/write/error.rs +++ b/git-odb/src/pack/index/write/error.rs @@ -1,47 +1,26 @@ use crate::pack; -use quick_error::quick_error; use std::io; -quick_error! { - #[derive(Debug)] - pub enum Error { - Io(err: io::Error) { - display("An IO error occurred when reading the pack or creating a temporary file") - from() - source(err) - } - PackEntryDecode(err: pack::data::iter::Error) { - display("A pack entry could not be extracted") - from() - source(err) - } - Unsupported(kind: pack::index::Kind) { - display("Indices of type {} cannot be written, only {} are supported", *kind as usize, pack::index::Kind::default() as usize) - } - IteratorInvariantNoRefDelta { - display("Ref delta objects are not supported as there is no way to look them up. Resolve them beforehand.") - } - IteratorInvariantTrailer { - display("The iterator failed to set a trailing hash over all prior pack entries in the last provided entry") - } - IteratorInvariantBasesPresent { - display("Did not encounter a single base") - } - IteratorInvariantTooManyObjects(num_objects: usize) { - display("Only u32::MAX objects can be stored in a pack, found {}", num_objects) - } - IteratorInvariantBaseOffset(pack_offset: u64, distance: u64) { - display("{} is not a valid offset for pack offset {}", distance, pack_offset) - } - Tree(err: pack::tree::Error) { - display("An invariant regarding the delta tree did not hold") - source(err) - from() - } - TreeTraversal(err: pack::tree::traverse::Error) { - display("Tree traversal failed") - source(err) - from() - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("An IO error occurred when reading the pack or creating a temporary file")] + Io(#[from] io::Error), + #[error("A pack entry could not be extracted")] + PackEntryDecode(#[from] pack::data::iter::Error), + #[error("Indices of type {} cannot be written, only {} are supported", *.0 as usize, pack::index::Kind::default() as usize)] + Unsupported(pack::index::Kind), + #[error("Ref delta objects are not supported as there is no way to look them up. Resolve them beforehand.")] + IteratorInvariantNoRefDelta, + #[error("The iterator failed to set a trailing hash over all prior pack entries in the last provided entry")] + IteratorInvariantTrailer, + #[error("Did not encounter a single base")] + IteratorInvariantBasesPresent, + #[error("Only u32::MAX objects can be stored in a pack, found {0}")] + IteratorInvariantTooManyObjects(usize), + #[error("{pack_offset} is not a valid offset for pack offset {distance}")] + IteratorInvariantBaseOffset { pack_offset: u64, distance: u64 }, + #[error(transparent)] + Tree(#[from] pack::tree::Error), + #[error(transparent)] + TreeTraversal(#[from] pack::tree::traverse::Error), } diff --git a/git-odb/src/pack/index/write/mod.rs b/git-odb/src/pack/index/write/mod.rs index dd67d02805a..2b5ac6873e8 100644 --- a/git-odb/src/pack/index/write/mod.rs +++ b/git-odb/src/pack/index/write/mod.rs @@ -105,7 +105,10 @@ impl pack::index::File { RefDelta { .. } => return Err(Error::IteratorInvariantNoRefDelta), OfsDelta { base_distance } => { let base_pack_offset = pack::data::Header::verified_base_pack_offset(pack_offset, base_distance) - .ok_or_else(|| Error::IteratorInvariantBaseOffset(pack_offset, base_distance))?; + .ok_or_else(|| Error::IteratorInvariantBaseOffset { + pack_offset, + distance: base_distance, + })?; tree.add_child( base_pack_offset, pack_offset, diff --git a/git-odb/src/pack/tree/from_offsets.rs b/git-odb/src/pack/tree/from_offsets.rs index 3f6f3a6a961..9d34e7674ed 100644 --- a/git-odb/src/pack/tree/from_offsets.rs +++ b/git-odb/src/pack/tree/from_offsets.rs @@ -3,36 +3,24 @@ use git_features::{ interrupt::is_triggered, progress::{self, Progress}, }; -use quick_error::quick_error; use std::{ fs, io, io::{BufRead, Read}, time::Instant, }; -quick_error! { - #[derive(Debug)] - pub enum Error { - Io(err: io::Error, msg: &'static str) { - display("{}", msg) - source(err) - } - Header(err: pack::data::parse::Error) { - source(err) - from() - } - UnresolvedRefDelta(id: git_object::owned::Id) { - display("Could find object with id {} in this pack. Thin packs are not supported", id) - } - Tree(err: pack::tree::Error) { - display("An error occurred when handling the delta tree") - source(err) - from() - } - Interrupted { - display("Interrupted") - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("{message}")] + Io { source: io::Error, message: &'static str }, + #[error(transparent)] + Header(#[from] pack::data::parse::Error), + #[error("Could find object with id {id} in this pack. Thin packs are not supported")] + UnresolvedRefDelta { id: git_object::owned::Id }, + #[error(transparent)] + Tree(#[from] pack::tree::Error), + #[error("Interrupted")] + Interrupted, } const PACK_HEADER_LEN: usize = 12; @@ -49,7 +37,10 @@ impl Tree { ) -> Result { let mut r = io::BufReader::with_capacity( 8192 * 8, // this value directly corresponds to performance, 8k (default) is about 4x slower than 64k - fs::File::open(pack_path).map_err(|err| Error::Io(err, "open pack path"))?, + fs::File::open(pack_path).map_err(|err| Error::Io { + source: err, + message: "open pack path", + })?, ); let anticpiated_num_objects = if let Some(num_objects) = data_sorted_by_offsets.size_hint().1 { @@ -63,11 +54,9 @@ impl Tree { { // safety check - assure ourselves it's a pack we can handle let mut buf = [0u8; PACK_HEADER_LEN]; - r.read_exact(&mut buf).map_err(|err| { - Error::Io( - err, - "reading header buffer with at least 12 bytes failed - pack file truncated?", - ) + r.read_exact(&mut buf).map_err(|err| Error::Io { + source: err, + message: "reading header buffer with at least 12 bytes failed - pack file truncated?", })?; pack::data::parse::header(&buf)?; } @@ -81,8 +70,10 @@ impl Tree { if let Some(previous_offset) = previous_cursor_position { Self::advance_cursor_to_pack_offset(&mut r, pack_offset, previous_offset)?; }; - let entry = pack::data::Entry::from_read(&mut r, pack_offset) - .map_err(|err| Error::Io(err, "EOF while parsing header"))?; + let entry = pack::data::Entry::from_read(&mut r, pack_offset).map_err(|err| Error::Io { + source: err, + message: "EOF while parsing header", + })?; previous_cursor_position = Some(pack_offset + entry.header_size() as u64); use pack::data::Header::*; @@ -92,7 +83,7 @@ impl Tree { } RefDelta { base_id } => { resolve_in_pack_id(base_id.to_borrowed()) - .ok_or_else(|| Error::UnresolvedRefDelta(base_id)) + .ok_or_else(|| Error::UnresolvedRefDelta { id: base_id }) .and_then(|base_pack_offset| { tree.add_child(base_pack_offset, pack_offset, data).map_err(Into::into) })?; @@ -123,17 +114,20 @@ impl Tree { .checked_sub(previous_offset) .expect("continuously ascending pack offets") as usize; while bytes_to_skip != 0 { - let buf = r.fill_buf().map_err(|err| Error::Io(err, "skip bytes"))?; + let buf = r.fill_buf().map_err(|err| Error::Io { + source: err, + message: "skip bytes", + })?; if buf.is_empty() { // This means we have reached the end of file and can't make progress anymore, before we have satisfied our need // for more - return Err(Error::Io( - io::Error::new( + return Err(Error::Io { + source: io::Error::new( io::ErrorKind::UnexpectedEof, "ran out of bytes before reading desired amount of bytes", ), - "index file is damaged or corrupt", - )); + message: "index file is damaged or corrupt", + }); } let bytes = buf.len().min(bytes_to_skip); r.consume(bytes); diff --git a/git-odb/src/pack/tree/traverse/mod.rs b/git-odb/src/pack/tree/traverse/mod.rs index c398c5dc0b9..2b66abc24c3 100644 --- a/git-odb/src/pack/tree/traverse/mod.rs +++ b/git-odb/src/pack/tree/traverse/mod.rs @@ -9,29 +9,22 @@ use git_features::{ parallel::in_parallel_if, progress::{self, Progress}, }; -use quick_error::quick_error; mod resolve; -quick_error! { - #[derive(Debug)] - pub enum Error { - ZlibInflate(err: crate::zlib::Error, msg: &'static str) { - display("{}", msg) - source(err) - } - ResolveFailed(pack_offset: u64) { - display("The resolver failed to obtain the pack entry bytes for the entry at {}", pack_offset) - } - Inspect(err: Box) { - display("One of the object inspectors failed") - source(&**err) - from() - } - Interrupted { - display("Interrupted") - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("{message}")] + ZlibInflate { + source: crate::zlib::Error, + message: &'static str, + }, + #[error("The resolver failed to obtain the pack entry bytes for the entry at {pack_offset}")] + ResolveFailed { pack_offset: u64 }, + #[error("One of the object inspectors failed")] + Inspect(#[from] Box), + #[error("Interrupted")] + Interrupted, } pub struct Context<'a, S> { diff --git a/git-odb/src/pack/tree/traverse/resolve.rs b/git-odb/src/pack/tree/traverse/resolve.rs index a50d2f49a72..cb3fc8043b8 100644 --- a/git-odb/src/pack/tree/traverse/resolve.rs +++ b/git-odb/src/pack/tree/traverse/resolve.rs @@ -25,7 +25,9 @@ where let decompress_from_resolver = |slice: EntrySlice| -> Result<(pack::data::Entry, u64, Vec), Error> { let mut bytes_buf = bytes_buf.borrow_mut(); bytes_buf.resize((slice.end - slice.start) as usize, 0); - resolve(slice.clone(), &mut bytes_buf).ok_or_else(|| Error::ResolveFailed(slice.start))?; + resolve(slice.clone(), &mut bytes_buf).ok_or_else(|| Error::ResolveFailed { + pack_offset: slice.start, + })?; let entry = pack::data::Entry::from_bytes(&bytes_buf, slice.start); let compressed = &bytes_buf[entry.header_size() as usize..]; let decompressed_len = entry.decompressed_size as usize; @@ -104,6 +106,9 @@ fn decompress_all_at_once(b: &[u8], decompressed_len: usize) -> Result, out.resize(decompressed_len, 0); zlib::Inflate::default() .once(&b, &mut out, true) - .map_err(|err| Error::ZlibInflate(err, "Failed to decompress entry"))?; + .map_err(|err| Error::ZlibInflate { + source: err, + message: "Failed to decompress entry", + })?; Ok(out) } diff --git a/git-odb/src/zlib/stream/deflate.rs b/git-odb/src/zlib/stream/deflate.rs index 8667e36a263..3f23da9fc07 100644 --- a/git-odb/src/zlib/stream/deflate.rs +++ b/git-odb/src/zlib/stream/deflate.rs @@ -1,21 +1,13 @@ use super::Status; use miniz_oxide::{deflate, deflate::core::CompressorOxide, MZError, MZFlush, MZStatus}; -use quick_error::quick_error; use std::io; -quick_error! { - #[derive(Debug)] - pub enum Error { - Compression { - display("The compression failed due to an unknown error") - } - ZLibNeedDict { - display("Need dictionary") - } - Error(err: MZError) { - display("A compression error occurred: {:?}", err) - } - } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Need dictionary")] + ZLibNeedDict, + #[error("A compression error occurred: {0:?}")] + Error(MZError), } pub struct Deflate { diff --git a/git-odb/tests/alternate/mod.rs b/git-odb/tests/alternate/mod.rs new file mode 100644 index 00000000000..bd975b4193d --- /dev/null +++ b/git-odb/tests/alternate/mod.rs @@ -0,0 +1,72 @@ +use git_odb::alternate; +use std::{ + fs, io, + path::{Path, PathBuf}, +}; + +fn alternate(objects_at: impl Into, objects_to: impl Into) -> Result<(PathBuf, PathBuf), io::Error> { + alternate_with(objects_at, objects_to, None) +} + +fn alternate_with( + objects_at: impl Into, + objects_to: impl Into, + content_before_to: Option<&str>, +) -> Result<(PathBuf, PathBuf), io::Error> { + let at = objects_at.into(); + let to = objects_to.into(); + let at_info = at.join("info"); + fs::create_dir_all(&at_info)?; + fs::create_dir_all(&to)?; + let contents = if let Some(content) = content_before_to { + let mut c = vec![b'\n']; + c.extend(content.as_bytes()); + c.extend(to.to_string_lossy().as_bytes()); + c + } else { + to.to_string_lossy().as_bytes().to_owned() + }; + fs::write(at_info.join("alternates"), contents)?; + Ok((at, to)) +} + +#[test] +fn circular_alternates_are_detected_with_relative_paths() -> crate::Result { + let tmp = tempdir::TempDir::new("alternates")?; + let (from, _) = alternate(tmp.path().join("a"), tmp.path().join("b"))?; + alternate(tmp.path().join("b"), Path::new("..").join("a"))?; + + match alternate::resolve(&from) { + Err(alternate::Error::Cycle(chain)) => { + assert_eq!( + chain + .into_iter() + .map(|p| p.file_name().expect("non-root").to_str().expect("utf8").to_owned()) + .collect::>(), + vec!["a", "b"] + ); + } + _ => unreachable!("should be a specific kind of error"), + } + Ok(()) +} + +#[test] +fn single_link_with_comment_before_path_and_ansi_c_escape() -> crate::Result { + let tmp = tempdir::TempDir::new("alternates")?; + let non_alternate = tmp.path().join("actual"); + + // let (from, to) = alternate_with(tmp.path().join("a"), non_alternate, Some("# comment\n\"../a\"\n"))?; + let (from, to) = alternate_with(tmp.path().join("a"), non_alternate, Some("# comment\n"))?; + let alternates = alternate::resolve(from)?; + assert_eq!(alternates.len(), 1); + assert_eq!(alternates[0].loose.path, to); + Ok(()) +} + +#[test] +fn no_alternate_in_first_objects_dir() -> crate::Result { + let tmp = tempdir::TempDir::new("alternates")?; + assert!(alternate::resolve(tmp.path())?.is_empty()); + Ok(()) +} diff --git a/git-odb/tests/odb.rs b/git-odb/tests/odb.rs index a09f272ab81..152481eb835 100644 --- a/git-odb/tests/odb.rs +++ b/git-odb/tests/odb.rs @@ -1,6 +1,8 @@ use git_object::owned; use std::path::PathBuf; +type Result = std::result::Result<(), Box>; + #[cfg(not(windows))] fn fixup(v: Vec) -> Vec { v @@ -22,6 +24,7 @@ pub fn fixture_path(path: &str) -> PathBuf { PathBuf::from("tests").join("fixtures").join(path) } +mod alternate; mod loose; mod pack; mod sink; diff --git a/gitoxide-core/Cargo.toml b/gitoxide-core/Cargo.toml index 0e3e30ae697..5edeb2434da 100644 --- a/gitoxide-core/Cargo.toml +++ b/gitoxide-core/Cargo.toml @@ -2,7 +2,7 @@ name = "gitoxide-core" description = "The library implementating all capabilities of the gitoxide CLI" repository = "https://github.com/Byron/git-oxide" -version = "0.4.0" +version = "0.4.1" authors = ["Sebastian Thiel "] license = "MIT/Apache-2.0" edition = "2018" diff --git a/performance-tasks.md b/performance-tasks.md index 9abf83b6c7c..98c008e3dc5 100644 --- a/performance-tasks.md +++ b/performance-tasks.md @@ -1,6 +1,6 @@ ## Potential for improving performance -### NLL/Borrowcheck limitation in git-odb +### NLL/Borrowcheck limitation git-odb::CompoundDb cause half-of-possible performance during object lookup * Once polonius is available with production-ready performance, we have to [make this code less wasteful](https://github.com/Byron/gitoxide/blob/b125c763c5d628c397dce9a5d085fbf123ce1f29/git-odb/src/compound.rs#L42) * See https://github.com/rust-lang/rust/issues/45402 for a discussion and more links diff --git a/src/plumbing/pretty/options.rs b/src/plumbing/pretty/options.rs index 67d75e15427..1c18e591155 100644 --- a/src/plumbing/pretty/options.rs +++ b/src/plumbing/pretty/options.rs @@ -7,14 +7,14 @@ use std::path::PathBuf; #[clap(setting = AppSettings::SubcommandRequired)] #[clap(setting = AppSettings::ColoredHelp)] pub struct Args { - #[clap(long, short = "t")] + #[clap(long, short = 't')] /// The amount of threads to use for some operations. /// /// If unset, or the value is 0, there is no limit and all logical cores can be used. pub threads: Option, /// Display verbose messages and progress information - #[clap(long, short = "v")] + #[clap(long, short = 'v')] pub verbose: bool, /// Bring up a terminal user interface displaying progress visually @@ -30,7 +30,7 @@ pub struct Args { /// Determine the format to use when outputting statistics. #[clap( long, - short = "f", + short = 'f', default_value = "human", possible_values(core::OutputFormat::variants()) )] @@ -46,13 +46,13 @@ pub enum Subcommands { #[clap(setting = AppSettings::DisableVersion)] PackReceive { /// The protocol version to use. Valid values are 1 and 2 - #[clap(long, short = "p")] + #[clap(long, short = 'p')] protocol: Option, /// the directory into which to write references. Existing files will be overwritten. /// /// Note that the directory will be created if needed. - #[clap(long, short = "r")] + #[clap(long, short = 'r')] refs_directory: Option, /// The URLs or path from which to receive the pack. @@ -73,7 +73,7 @@ pub enum Subcommands { #[clap(setting = AppSettings::DisableVersion)] RemoteRefList { /// The protocol version to use. Valid values are 1 and 2 - #[clap(long, short = "p")] + #[clap(long, short = 'p')] protocol: Option, /// the URLs or path from which to receive references @@ -93,7 +93,7 @@ pub enum Subcommands { /// **restore** hash the input ourselves and ignore failing entries, instead finish the pack with the hash we computed #[clap( long, - short = "i", + short = 'i', default_value = "verify", possible_values(core::pack::index::IterationMode::variants()) )] @@ -102,7 +102,7 @@ pub enum Subcommands { /// Path to the pack file to read (with .pack extension). /// /// If unset, the pack file is expected on stdin. - #[clap(long, short = "p")] + #[clap(long, short = 'p')] pack_path: Option, /// The folder into which to place the pack and the generated index file @@ -128,7 +128,7 @@ pub enum Subcommands { /// The amount of checks to run #[clap( long, - short = "c", + short = 'c', default_value = "all", possible_values(core::pack::explode::SafetyCheck::variants()) )] @@ -155,12 +155,12 @@ pub enum Subcommands { #[clap(setting = AppSettings::DisableVersion)] PackVerify { /// output statistical information about the pack - #[clap(long, short = "s")] + #[clap(long, short = 's')] statistics: bool, /// The algorithm used to verify the pack. They differ in costs. #[clap( long, - short = "a", + short = 'a', default_value = "less-time", possible_values(core::pack::verify::Algorithm::variants()) )] diff --git a/tasks.md b/tasks.md index 978daf9f07d..68a3a980bed 100644 --- a/tasks.md +++ b/tasks.md @@ -7,9 +7,17 @@ * [x] make NLL issue work * [x] Nice access to compound::Object * [x] Add #![deny(rust_2018_idioms)] everywhere - * [ ] Where 'thiserror' is available, use it for all Errors. It is more powerful, and if we paid for it already, let's use it. - * [ ] alternate DB (location - it's really must following the chain until a compound DB can be created) - * [ ] loose upgrade: jwalk powered iteration behind a feature flag + * [x] Where 'thiserror' is available, use it for all Errors. It is more powerful, and if we paid for it already, let's use it. + * [x] alternate DB (location - it's really must following the chain until a compound DB can be created) + * [x] circular dependencies test + * [x] basic test + * [x] multiple alternates in a single file + * [x] comments + * [x] quotes + * [x] support for relative directories + * [x] lookup uses alternates + * [x] loose upgrade: jwalk powered iteration behind a feature flag + * [ ] full docs * **git-config** * A complete implementation, writing a the git remote configuration is needed for finalizing the clone * **git-ref** @@ -43,7 +51,7 @@ To be picked in any order…. * [ ] finish transitioning to futures-lite to get rid of futures-util dependency to reduce compile times * **criner** * [x] upgrade to prodash 9.0 - * [ ] switch to `isahc` + * [ ] switch to `isahc` or `ureq` (blocking, but could use unblock for that) seems to allow async-reading of bodies, allowing to get rid of reqwest and tokio. Redirect is configurable. [josh-aug-12]: https://github.com/Byron/gitoxide/issues/1#issuecomment-672566602