diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9DYXJnby5sb2Nr..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9DYXJnby5sb2Nr 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1,4 +1,9 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "aho-corasick" @@ -4,5 +9,5 @@ name = "aho-corasick" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -13,7 +18,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -21,10 +26,10 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" @@ -27,8 +32,8 @@ ] [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -42,9 +47,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "cc" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clap" @@ -45,10 +58,10 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clap" -version = "2.33.1" +version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -56,8 +69,8 @@ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -65,10 +78,10 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -70,10 +83,18 @@ "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "crossbeam" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -75,8 +96,8 @@ name = "crossbeam" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -81,8 +102,8 @@ "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-channel" @@ -84,9 +105,9 @@ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-channel" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -108,8 +129,8 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -112,10 +133,10 @@ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-queue" @@ -117,10 +138,10 @@ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-queue" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -123,7 +144,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -131,10 +153,10 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ctor" @@ -135,9 +157,9 @@ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ctor" -version = "0.1.13" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -142,7 +164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -152,7 +174,7 @@ [[package]] name = "either" -version = "1.5.3" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -162,9 +184,9 @@ dependencies = [ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -166,10 +188,10 @@ "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "getrandom" -version = "0.1.14" +name = "flate2" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -173,8 +195,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getrandom" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -177,5 +221,10 @@ "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "hermit-abi" @@ -181,4 +230,4 @@ name = "hermit-abi" -version = "0.1.8" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -183,6 +232,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -195,5 +244,5 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -199,3 +248,4 @@ "crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -200,5 +250,5 @@ "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -203,7 +253,7 @@ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "micro-timer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -206,6 +256,6 @@ "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -211,4 +261,5 @@ "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -212,6 +263,7 @@ "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -221,8 +273,8 @@ "cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "hg-core 0.1.0", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -234,9 +286,25 @@ ] [[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" @@ -237,10 +305,10 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.67" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -244,4 +312,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "libz-sys" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "log" @@ -247,5 +325,5 @@ name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -266,9 +344,9 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memoffset" @@ -271,7 +349,7 @@ ] [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -276,7 +354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "micro-timer" @@ -279,7 +357,7 @@ ] [[package]] name = "micro-timer" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -284,8 +362,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "micro-timer-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "micro-timer-macros" @@ -287,8 +365,8 @@ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "micro-timer-macros" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -293,5 +371,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -297,6 +375,15 @@ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" @@ -299,7 +386,7 @@ ] [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -304,7 +391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num_cpus" @@ -307,7 +394,7 @@ ] [[package]] name = "num_cpus" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -312,7 +399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -320,7 +407,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -324,4 +411,9 @@ ] [[package]] +name = "pkg-config" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "ppv-lite86" @@ -327,5 +419,5 @@ name = "ppv-lite86" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -334,10 +426,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ctor 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" @@ -338,9 +430,9 @@ "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" -version = "1.0.9" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -345,6 +437,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -352,7 +444,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -361,7 +453,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -372,6 +464,14 @@ [[package]] name = "quote" -version = "1.0.3" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -376,6 +476,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -383,8 +496,8 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -395,9 +508,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" @@ -399,8 +512,21 @@ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -404,7 +530,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -433,6 +559,6 @@ [[package]] name = "rayon" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -437,3 +563,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -439,7 +566,7 @@ "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" @@ -442,7 +569,7 @@ ] [[package]] name = "rayon-core" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -447,3 +574,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -449,4 +577,3 @@ "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -451,7 +578,15 @@ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" @@ -454,8 +589,8 @@ ] [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -463,7 +598,7 @@ version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -476,6 +611,6 @@ [[package]] name = "remove_dir_all" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -480,9 +615,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rhg" version = "0.1.0" dependencies = [ @@ -483,8 +618,9 @@ ] [[package]] name = "rhg" version = "0.1.0" dependencies = [ - "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "hg-core 0.1.0", @@ -490,4 +626,6 @@ "hg-core 0.1.0", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -491,7 +629,7 @@ ] [[package]] -name = "rustc_version" -version = "0.2.3" +name = "rust-crypto" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -496,6 +634,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -499,7 +641,12 @@ ] [[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -502,8 +649,8 @@ name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -512,22 +659,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" @@ -528,9 +662,9 @@ name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.16" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -535,8 +669,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -545,5 +679,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -549,7 +683,7 @@ "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -557,7 +691,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -565,7 +699,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -586,8 +720,8 @@ [[package]] name = "unicode-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" @@ -590,9 +724,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vcpkg" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vec_map" @@ -595,8 +734,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vec_map" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -606,7 +745,7 @@ [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -620,6 +759,6 @@ [[package]] name = "winapi-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -624,6 +763,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -631,4 +770,32 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "zstd" +version = "0.5.3+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zstd-safe" +version = "2.0.5+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", + "zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zstd-sys" +version = "1.4.17+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] @@ -634,4 +801,5 @@ [metadata] -"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +"checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" @@ -636,5 +804,5 @@ "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" @@ -639,3 +807,4 @@ "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +"checksum cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)" = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" @@ -641,3 +810,3 @@ "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" "checksum cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95" @@ -643,2 +812,3 @@ "checksum cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" @@ -644,4 +814,4 @@ "checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" -"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" +"checksum crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" @@ -646,4 +816,4 @@ "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" +"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" @@ -649,3 +819,3 @@ "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum ctor 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "47c5e5ac752e18207b12e16b10631ae5f7f68f8805f335f9b817ead83d9ffce1" +"checksum ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" @@ -651,3 +821,3 @@ "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" @@ -653,5 +823,9 @@ "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +"checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +"checksum hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151" "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" @@ -656,3 +830,5 @@ "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +"checksum jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" @@ -658,6 +834,7 @@ "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +"checksum libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" +"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" @@ -661,9 +838,10 @@ "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" -"checksum micro-timer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25b31d6cb9112984323d05d7a353f272ae5d7a307074f9ab9b25c00121b8c947" -"checksum micro-timer-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5694085dd384bb9e824207facc040c248d9df653f55e28c3ad0686958b448504" -"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +"checksum memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +"checksum micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2620153e1d903d26b72b89f0e9c48d8c4756cba941c185461dddc234980c298c" +"checksum micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e28a3473e6abd6e9aab36aaeef32ad22ae0bd34e79f376643594c2b152ec1c5d" +"checksum miniz_oxide 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9" +"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" @@ -669,3 +847,4 @@ "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" +"checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" @@ -671,5 +850,5 @@ "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" -"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" "checksum python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c" "checksum python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" @@ -673,6 +852,8 @@ "checksum python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c" "checksum python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" @@ -677,6 +858,8 @@ "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" @@ -679,9 +862,10 @@ "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" -"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270" +"checksum rayon-core 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" @@ -686,6 +870,7 @@ "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" @@ -690,5 +875,3 @@ "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" @@ -694,7 +877,7 @@ "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" +"checksum syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" @@ -696,9 +879,10 @@ "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" -"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +"checksum vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" +"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" @@ -704,3 +888,3 @@ "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" @@ -706,3 +890,3 @@ "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" +"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" @@ -708,1 +892,4 @@ "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8" +"checksum zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055" +"checksum zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b" diff --git a/rust/hg-core/Cargo.toml b/rust/hg-core/Cargo.toml index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9oZy1jb3JlL0NhcmdvLnRvbWw=..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL0NhcmdvLnRvbWw= 100644 --- a/rust/hg-core/Cargo.toml +++ b/rust/hg-core/Cargo.toml @@ -23,6 +23,18 @@ crossbeam = "0.7.3" micro-timer = "0.3.0" log = "0.4.8" +memmap = "0.7.0" +zstd = "0.5.3" +rust-crypto = "0.2.36" + +# We don't use the `miniz-oxide` backend because its minimum Rust version is +# `1.36`. However, this PR (https://github.com/Frommi/miniz_oxide/pull/84/files) +# introduces a flag `no_extern_crate_alloc` to bring the requirement back down +# to `1.34`. +[dependencies.flate2] +version = "1.0.16" +features = ["zlib"] +default-features = false [dev-dependencies] clap = "*" @@ -26,6 +38,5 @@ [dev-dependencies] clap = "*" -memmap = "0.7.0" pretty_assertions = "0.6.1" tempfile = "3.1.0" diff --git a/rust/hg-core/src/dirstate/dirstate_map.rs b/rust/hg-core/src/dirstate/dirstate_map.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9oZy1jb3JlL3NyYy9kaXJzdGF0ZS9kaXJzdGF0ZV9tYXAucnM=..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9kaXJzdGF0ZS9kaXJzdGF0ZV9tYXAucnM= 100644 --- a/rust/hg-core/src/dirstate/dirstate_map.rs +++ b/rust/hg-core/src/dirstate/dirstate_map.rs @@ -5,6 +5,7 @@ // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. +use crate::revlog::node::NULL_NODE_ID; use crate::{ dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT}, pack_dirstate, parse_dirstate, @@ -24,7 +25,6 @@ pub type FileFoldMap = FastHashMap; -const NULL_ID: [u8; 20] = [0; 20]; const MTIME_UNSET: i32 = -1; #[derive(Default)] @@ -72,8 +72,8 @@ self.non_normal_set = None; self.other_parent_set = None; self.set_parents(&DirstateParents { - p1: NULL_ID, - p2: NULL_ID, + p1: NULL_NODE_ID, + p2: NULL_NODE_ID, }) } @@ -340,8 +340,8 @@ }; } else if file_contents.is_empty() { parents = DirstateParents { - p1: NULL_ID, - p2: NULL_ID, + p1: NULL_NODE_ID, + p2: NULL_NODE_ID, }; } else { return Err(DirstateError::Parse(DirstateParseError::Damaged)); diff --git a/rust/hg-core/src/operations/cat.rs b/rust/hg-core/src/operations/cat.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9vcGVyYXRpb25zL2NhdC5ycw== --- /dev/null +++ b/rust/hg-core/src/operations/cat.rs @@ -0,0 +1,145 @@ +// list_tracked_files.rs +// +// Copyright 2020 Antoine Cezar +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +use std::convert::From; +use std::path::PathBuf; + +use crate::revlog::changelog::Changelog; +use crate::revlog::manifest::{Manifest, ManifestEntry}; +use crate::revlog::path_encode::path_encode; +use crate::revlog::revlog::Revlog; +use crate::revlog::revlog::RevlogError; +use crate::revlog::Revision; +use crate::utils::hg_path::HgPathBuf; + +/// Kind of error encountered by `CatRev` +#[derive(Debug)] +pub enum CatRevErrorKind { + /// Error when reading a `revlog` file. + IoError(std::io::Error), + /// The revision has not been found. + InvalidRevision, + /// A `revlog` file is corrupted. + CorruptedRevlog, + /// The `revlog` format version is not supported. + UnsuportedRevlogVersion(u16), + /// The `revlog` data format is not supported. + UnknowRevlogDataFormat(u8), +} + +/// A `CatRev` error +#[derive(Debug)] +pub struct CatRevError { + /// Kind of error encountered by `CatRev` + pub kind: CatRevErrorKind, +} + +impl From for CatRevError { + fn from(kind: CatRevErrorKind) -> Self { + CatRevError { kind } + } +} + +impl From for CatRevError { + fn from(err: RevlogError) -> Self { + match err { + RevlogError::IoError(err) => CatRevErrorKind::IoError(err), + RevlogError::UnsuportedVersion(version) => { + CatRevErrorKind::UnsuportedRevlogVersion(version) + } + RevlogError::InvalidRevision => CatRevErrorKind::InvalidRevision, + RevlogError::Corrupted => CatRevErrorKind::CorruptedRevlog, + RevlogError::UnknowDataFormat(format) => { + CatRevErrorKind::UnknowRevlogDataFormat(format) + } + } + .into() + } +} + +/// List files under Mercurial control at a given revision. +pub struct CatRev<'a> { + root: &'a PathBuf, + /// The revision to cat the files from. + rev: &'a str, + /// The files to output. + files: &'a [HgPathBuf], + /// The changelog file + changelog: Changelog, + /// The manifest file + manifest: Manifest, + /// The manifest entry corresponding to the revision. + /// + /// Used to hold the owner of the returned references. + manifest_entry: Option, +} + +impl<'a> CatRev<'a> { + pub fn new( + root: &'a PathBuf, + rev: &'a str, + files: &'a [HgPathBuf], + ) -> Result { + let changelog = Changelog::open(&root)?; + let manifest = Manifest::open(&root)?; + let manifest_entry = None; + + Ok(Self { + root, + rev, + files, + changelog, + manifest, + manifest_entry, + }) + } + + pub fn run(&mut self) -> Result, CatRevError> { + let changelog_entry = match self.rev.parse::() { + Ok(rev) => self.changelog.get_rev(rev)?, + _ => { + let changelog_node = hex::decode(&self.rev) + .map_err(|_| CatRevErrorKind::InvalidRevision)?; + self.changelog.get_node(&changelog_node)? + } + }; + let manifest_node = hex::decode(&changelog_entry.manifest_node()?) + .map_err(|_| CatRevErrorKind::CorruptedRevlog)?; + + self.manifest_entry = Some(self.manifest.get_node(&manifest_node)?); + if let Some(ref manifest_entry) = self.manifest_entry { + let mut bytes = vec![]; + + for (manifest_file, node_bytes) in + manifest_entry.files_with_nodes() + { + for cat_file in self.files.iter() { + if cat_file.as_bytes() == manifest_file.as_bytes() { + let encoded_bytes = + path_encode(manifest_file.as_bytes()); + let revlog_index_string = format!( + ".hg/store/data/{}.i", + String::from_utf8_lossy(&encoded_bytes), + ); + let revlog_index_path = + self.root.join(&revlog_index_string); + let file_log = Revlog::open(&revlog_index_path)?; + let file_node = hex::decode(&node_bytes) + .map_err(|_| CatRevErrorKind::CorruptedRevlog)?; + let file_rev = file_log.get_node_rev(&file_node)?; + let data = file_log.get_rev_data(file_rev)?; + bytes.extend(data); + } + } + } + + Ok(bytes) + } else { + unreachable!("manifest_entry should have been stored"); + } + } +} diff --git a/rust/hg-core/src/operations/debugdata.rs b/rust/hg-core/src/operations/debugdata.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9vcGVyYXRpb25zL2RlYnVnZGF0YS5ycw== --- /dev/null +++ b/rust/hg-core/src/operations/debugdata.rs @@ -0,0 +1,110 @@ +// debugdata.rs +// +// Copyright 2020 Antoine Cezar +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +use super::find_root; +use crate::revlog::revlog::{Revlog, RevlogError}; +use crate::revlog::Revision; + +/// Kind of data to debug +#[derive(Debug, Copy, Clone)] +pub enum DebugDataKind { + Changelog, + Manifest, +} + +/// Kind of error encountered by DebugData +#[derive(Debug)] +pub enum DebugDataErrorKind { + FindRootError(find_root::FindRootError), + /// Error when reading a `revlog` file. + IoError(std::io::Error), + /// The revision has not been found. + InvalidRevision, + /// A `revlog` file is corrupted. + CorruptedRevlog, + /// The `revlog` format version is not supported. + UnsuportedRevlogVersion(u16), + /// The `revlog` data format is not supported. + UnknowRevlogDataFormat(u8), +} + +/// A DebugData error +#[derive(Debug)] +pub struct DebugDataError { + /// Kind of error encountered by DebugData + pub kind: DebugDataErrorKind, +} + +impl From for DebugDataError { + fn from(kind: DebugDataErrorKind) -> Self { + DebugDataError { kind } + } +} + +impl From for DebugDataError { + fn from(err: find_root::FindRootError) -> Self { + let kind = DebugDataErrorKind::FindRootError(err); + DebugDataError { kind } + } +} + +impl From for DebugDataError { + fn from(err: std::io::Error) -> Self { + let kind = DebugDataErrorKind::IoError(err); + DebugDataError { kind } + } +} + +impl From for DebugDataError { + fn from(err: RevlogError) -> Self { + match err { + RevlogError::IoError(err) => DebugDataErrorKind::IoError(err), + RevlogError::UnsuportedVersion(version) => { + DebugDataErrorKind::UnsuportedRevlogVersion(version) + } + RevlogError::InvalidRevision => { + DebugDataErrorKind::InvalidRevision + } + RevlogError::Corrupted => DebugDataErrorKind::CorruptedRevlog, + RevlogError::UnknowDataFormat(format) => { + DebugDataErrorKind::UnknowRevlogDataFormat(format) + } + } + .into() + } +} + +/// Dump the contents data of a revision. +pub struct DebugData<'a> { + /// Revision or hash of the revision. + rev: &'a str, + /// Kind of data to debug. + kind: DebugDataKind, +} + +impl<'a> DebugData<'a> { + pub fn new(rev: &'a str, kind: DebugDataKind) -> Self { + DebugData { rev, kind } + } + + pub fn run(&mut self) -> Result, DebugDataError> { + let rev = self + .rev + .parse::() + .or(Err(DebugDataErrorKind::InvalidRevision))?; + + let root = find_root::FindRoot::new().run()?; + let index_file = match self.kind { + DebugDataKind::Changelog => root.join(".hg/store/00changelog.i"), + DebugDataKind::Manifest => root.join(".hg/store/00manifest.i"), + }; + let revlog = Revlog::open(&index_file)?; + let data = revlog.get_rev_data(rev)?; + + Ok(data) + } +} diff --git a/rust/hg-core/src/operations/list_tracked_files.rs b/rust/hg-core/src/operations/list_tracked_files.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9oZy1jb3JlL3NyYy9vcGVyYXRpb25zL2xpc3RfdHJhY2tlZF9maWxlcy5ycw==..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9vcGVyYXRpb25zL2xpc3RfdHJhY2tlZF9maWxlcy5ycw== 100644 --- a/rust/hg-core/src/operations/list_tracked_files.rs +++ b/rust/hg-core/src/operations/list_tracked_files.rs @@ -5,5 +5,4 @@ // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. -use super::find_root; use crate::dirstate::parsers::parse_dirstate; @@ -9,5 +8,9 @@ use crate::dirstate::parsers::parse_dirstate; +use crate::revlog::changelog::Changelog; +use crate::revlog::manifest::{Manifest, ManifestEntry}; +use crate::revlog::revlog::RevlogError; +use crate::revlog::Revision; use crate::utils::hg_path::HgPath; use crate::{DirstateParseError, EntryState}; use rayon::prelude::*; use std::convert::From; @@ -10,6 +13,5 @@ use crate::utils::hg_path::HgPath; use crate::{DirstateParseError, EntryState}; use rayon::prelude::*; use std::convert::From; -use std::fmt; use std::fs; @@ -15,4 +17,3 @@ use std::fs; -use std::io; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; @@ -18,3 +19,3 @@ -/// Kind of error encoutered by ListTrackedFiles +/// Kind of error encountered by `ListDirstateTrackedFiles` #[derive(Debug)] @@ -20,5 +21,8 @@ #[derive(Debug)] -pub enum ListTrackedFilesErrorKind { +pub enum ListDirstateTrackedFilesErrorKind { + /// Error when reading the `dirstate` file + IoError(std::io::Error), + /// Error when parsing the `dirstate` file ParseError(DirstateParseError), } @@ -22,5 +26,5 @@ ParseError(DirstateParseError), } -/// A ListTrackedFiles error +/// A `ListDirstateTrackedFiles` error #[derive(Debug)] @@ -26,6 +30,6 @@ #[derive(Debug)] -pub struct ListTrackedFilesError { - /// Kind of error encoutered by ListTrackedFiles - pub kind: ListTrackedFilesErrorKind, +pub struct ListDirstateTrackedFilesError { + /// Kind of error encountered by `ListDirstateTrackedFiles` + pub kind: ListDirstateTrackedFilesErrorKind, } @@ -30,10 +34,10 @@ } -impl std::error::Error for ListTrackedFilesError {} - -impl fmt::Display for ListTrackedFilesError { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() +impl From + for ListDirstateTrackedFilesError +{ + fn from(kind: ListDirstateTrackedFilesErrorKind) -> Self { + ListDirstateTrackedFilesError { kind } } } @@ -37,40 +41,13 @@ } } -impl From for ListTrackedFilesError { - fn from(kind: ListTrackedFilesErrorKind) -> Self { - ListTrackedFilesError { kind } - } -} - -/// List files under Mercurial control in the working directory -pub struct ListTrackedFiles { - root: PathBuf, -} - -impl ListTrackedFiles { - pub fn new() -> Result { - let root = find_root::FindRoot::new().run()?; - Ok(ListTrackedFiles { root }) - } - - /// Load the tracked files data from disk - pub fn load(&self) -> Result { - let dirstate = &self.root.join(".hg/dirstate"); - let content = fs::read(&dirstate)?; - Ok(ListDirstateTrackedFiles { content }) - } - - /// Returns the repository root directory - /// TODO I think this is a crutch that creates a dependency that should not - /// be there. Operations that need the root of the repository should get - /// it themselves, probably in a lazy fashion. But this would make the - /// current series even larger, so this is simplified for now. - pub fn get_root(&self) -> &Path { - &self.root +impl From for ListDirstateTrackedFilesError { + fn from(err: std::io::Error) -> Self { + let kind = ListDirstateTrackedFilesErrorKind::IoError(err); + ListDirstateTrackedFilesError { kind } } } /// List files under Mercurial control in the working directory /// by reading the dirstate pub struct ListDirstateTrackedFiles { @@ -71,10 +48,11 @@ } } /// List files under Mercurial control in the working directory /// by reading the dirstate pub struct ListDirstateTrackedFiles { + /// The `dirstate` content. content: Vec, } impl ListDirstateTrackedFiles { @@ -77,6 +55,14 @@ content: Vec, } impl ListDirstateTrackedFiles { - pub fn run(&self) -> Result, ListTrackedFilesError> { + pub fn new(root: &PathBuf) -> Result { + let dirstate = root.join(".hg/dirstate"); + let content = fs::read(&dirstate)?; + Ok(Self { content }) + } + + pub fn run( + &mut self, + ) -> Result, ListDirstateTrackedFilesError> { let (_, entries, _) = parse_dirstate(&self.content) @@ -82,5 +68,5 @@ let (_, entries, _) = parse_dirstate(&self.content) - .map_err(ListTrackedFilesErrorKind::ParseError)?; + .map_err(ListDirstateTrackedFilesErrorKind::ParseError)?; let mut files: Vec<&HgPath> = entries .into_iter() .filter_map(|(path, entry)| match entry.state { @@ -92,3 +78,111 @@ Ok(files) } } + +/// Kind of error encountered by `ListRevTrackedFiles` +#[derive(Debug)] +pub enum ListRevTrackedFilesErrorKind { + /// Error when reading a `revlog` file. + IoError(std::io::Error), + /// The revision has not been found. + InvalidRevision, + /// A `revlog` file is corrupted. + CorruptedRevlog, + /// The `revlog` format version is not supported. + UnsuportedRevlogVersion(u16), + /// The `revlog` data format is not supported. + UnknowRevlogDataFormat(u8), +} + +/// A `ListRevTrackedFiles` error +#[derive(Debug)] +pub struct ListRevTrackedFilesError { + /// Kind of error encountered by `ListRevTrackedFiles` + pub kind: ListRevTrackedFilesErrorKind, +} + +impl From for ListRevTrackedFilesError { + fn from(kind: ListRevTrackedFilesErrorKind) -> Self { + ListRevTrackedFilesError { kind } + } +} + +impl From for ListRevTrackedFilesError { + fn from(err: RevlogError) -> Self { + match err { + RevlogError::IoError(err) => { + ListRevTrackedFilesErrorKind::IoError(err) + } + RevlogError::UnsuportedVersion(version) => { + ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) + } + RevlogError::InvalidRevision => { + ListRevTrackedFilesErrorKind::InvalidRevision + } + RevlogError::Corrupted => { + ListRevTrackedFilesErrorKind::CorruptedRevlog + } + RevlogError::UnknowDataFormat(format) => { + ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) + } + } + .into() + } +} + +/// List files under Mercurial control at a given revision. +pub struct ListRevTrackedFiles<'a> { + /// The revision to list the files from. + rev: &'a str, + /// The changelog file + changelog: Changelog, + /// The manifest file + manifest: Manifest, + /// The manifest entry corresponding to the revision. + /// + /// Used to hold the owner of the returned references. + manifest_entry: Option, +} + +impl<'a> ListRevTrackedFiles<'a> { + pub fn new( + root: &PathBuf, + rev: &'a str, + ) -> Result { + let changelog = Changelog::open(&root)?; + let manifest = Manifest::open(&root)?; + + Ok(Self { + rev, + changelog, + manifest, + manifest_entry: None, + }) + } + + pub fn run( + &mut self, + ) -> Result, ListRevTrackedFilesError> { + let changelog_entry = match self.rev.parse::() { + Ok(rev) => self.changelog.get_rev(rev)?, + _ => { + let changelog_node = hex::decode(&self.rev).map_err(|_| { + ListRevTrackedFilesErrorKind::InvalidRevision + })?; + self.changelog.get_node(&changelog_node)? + } + }; + let manifest_node = hex::decode(&changelog_entry.manifest_node()?) + .map_err(|_| ListRevTrackedFilesErrorKind::CorruptedRevlog)?; + + self.manifest_entry = Some(self.manifest.get_node(&manifest_node)?); + + if let Some(ref manifest_entry) = self.manifest_entry { + Ok(manifest_entry.files()) + } else { + panic!( + "manifest entry should have been stored in self.manifest_node to ensure its lifetime since references are returned from it" + ) + } + } +} diff --git a/rust/hg-core/src/operations/mod.rs b/rust/hg-core/src/operations/mod.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9oZy1jb3JlL3NyYy9vcGVyYXRpb25zL21vZC5ycw==..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9vcGVyYXRpb25zL21vZC5ycw== 100644 --- a/rust/hg-core/src/operations/mod.rs +++ b/rust/hg-core/src/operations/mod.rs @@ -2,6 +2,8 @@ //! An operation is what can be done whereas a command is what is exposed by //! the cli. A single command can use several operations to achieve its goal. +mod cat; +mod debugdata; mod dirstate_status; mod find_root; mod list_tracked_files; @@ -5,5 +7,9 @@ mod dirstate_status; mod find_root; mod list_tracked_files; +pub use cat::{CatRev, CatRevError, CatRevErrorKind}; +pub use debugdata::{ + DebugData, DebugDataError, DebugDataErrorKind, DebugDataKind, +}; pub use find_root::{FindRoot, FindRootError, FindRootErrorKind}; pub use list_tracked_files::{ @@ -8,6 +14,11 @@ pub use find_root::{FindRoot, FindRootError, FindRootErrorKind}; pub use list_tracked_files::{ - ListTrackedFiles, ListTrackedFilesError, ListTrackedFilesErrorKind, + ListDirstateTrackedFiles, ListDirstateTrackedFilesError, + ListDirstateTrackedFilesErrorKind, +}; +pub use list_tracked_files::{ + ListRevTrackedFiles, ListRevTrackedFilesError, + ListRevTrackedFilesErrorKind, }; // TODO add an `Operation` trait when GAT have landed (rust #44265): diff --git a/rust/hg-core/src/revlog.rs b/rust/hg-core/src/revlog.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cucnM=..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cucnM= 100644 --- a/rust/hg-core/src/revlog.rs +++ b/rust/hg-core/src/revlog.rs @@ -7,4 +7,5 @@ pub mod node; pub mod nodemap; +pub mod path_encode; pub use node::{Node, NodeError, NodePrefix, NodePrefixRef}; @@ -10,4 +11,9 @@ pub use node::{Node, NodeError, NodePrefix, NodePrefixRef}; +pub mod changelog; +pub mod index; +pub mod manifest; +pub mod patch; +pub mod revlog; /// Mercurial revision numbers /// diff --git a/rust/hg-core/src/revlog/changelog.rs b/rust/hg-core/src/revlog/changelog.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvY2hhbmdlbG9nLnJz --- /dev/null +++ b/rust/hg-core/src/revlog/changelog.rs @@ -0,0 +1,58 @@ +use crate::revlog::revlog::{Revlog, RevlogError}; +use crate::revlog::Revision; +use std::path::PathBuf; + +/// A specialized `Revlog` to work with `changelog` data format. +pub struct Changelog { + /// The generic `revlog` format. + revlog: Revlog, +} + +impl Changelog { + /// Open the `changelog` of a repository given by its root. + pub fn open(root: &PathBuf) -> Result { + let index_file = root.join(".hg/store/00changelog.i"); + let revlog = Revlog::open(&index_file)?; + Ok(Self { revlog }) + } + + /// Return the `ChangelogEntry` a given node id. + pub fn get_node( + &self, + node: &[u8], + ) -> Result { + let rev = self.revlog.get_node_rev(node)?; + self.get_rev(rev) + } + + /// Return the `ChangelogEntry` of a given node revision. + pub fn get_rev( + &self, + rev: Revision, + ) -> Result { + let bytes = self.revlog.get_rev_data(rev)?; + Ok(ChangelogEntry { bytes }) + } +} + +/// `Changelog` entry which knows how to interpret the `changelog` data bytes. +#[derive(Debug)] +pub struct ChangelogEntry { + /// The data bytes of the `changelog` entry. + bytes: Vec, +} + +impl ChangelogEntry { + /// Return an iterator over the lines of the entry. + pub fn lines(&self) -> impl Iterator { + self.bytes + .split(|b| b == &b'\n') + .filter(|line| !line.is_empty()) + } + + /// Return the node id of the `manifest` referenced by this `changelog` + /// entry. + pub fn manifest_node(&self) -> Result<&[u8], RevlogError> { + self.lines().next().ok_or(RevlogError::Corrupted) + } +} diff --git a/rust/hg-core/src/revlog/index.rs b/rust/hg-core/src/revlog/index.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvaW5kZXgucnM= --- /dev/null +++ b/rust/hg-core/src/revlog/index.rs @@ -0,0 +1,330 @@ +use byteorder::{BigEndian, ByteOrder}; + +use crate::revlog::{Revision, NULL_REVISION}; + +pub const INDEX_ENTRY_SIZE: usize = 64; + +/// A Revlog index +#[derive(Debug)] +pub struct Index<'a> { + bytes: &'a [u8], + /// Offsets of starts of index blocks. + /// Only needed when the index is interleaved with data. + offsets: Option>, +} + +impl<'a> Index<'a> { + /// Create an index from bytes. + /// Calculate the start of each entry when is_inline is true. + pub fn new(bytes: &'a [u8], is_inline: bool) -> Self { + if is_inline { + let mut offset: usize = 0; + let mut offsets = Vec::new(); + + while (bytes.len() - offset) >= INDEX_ENTRY_SIZE { + offsets.push(offset); + let end = offset + INDEX_ENTRY_SIZE; + let entry = IndexEntry { + bytes: &bytes[offset..end], + offset_override: None, + }; + + offset += INDEX_ENTRY_SIZE + entry.compressed_len(); + } + + Self { + bytes, + offsets: Some(offsets), + } + } else { + Self { + bytes, + offsets: None, + } + } + } + + /// Return number of entries of the revlog index. + pub fn len(&self) -> usize { + if let Some(offsets) = &self.offsets { + offsets.len() + } else { + self.bytes.len() / INDEX_ENTRY_SIZE + } + } + + /// Returns `true` if the `Index` has zero `entries`. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Return the index entry corresponding to the given revision if it + /// exists. + pub fn get_entry(&self, rev: Revision) -> Option { + if rev == NULL_REVISION { + return None; + } + if let Some(offsets) = &self.offsets { + self.get_entry_inline(rev, offsets) + } else { + self.get_entry_separated(rev) + } + } + + fn get_entry_inline( + &self, + rev: Revision, + offsets: &[usize], + ) -> Option { + let start = *offsets.get(rev as usize)?; + let end = start.checked_add(INDEX_ENTRY_SIZE)?; + let bytes = &self.bytes[start..end]; + + // See IndexEntry for an explanation of this override. + let offset_override = Some(end); + + Some(IndexEntry { + bytes, + offset_override, + }) + } + + fn get_entry_separated(&self, rev: Revision) -> Option { + let max_rev = self.bytes.len() / INDEX_ENTRY_SIZE; + if rev as usize >= max_rev { + return None; + } + let start = rev as usize * INDEX_ENTRY_SIZE; + let end = start + INDEX_ENTRY_SIZE; + let bytes = &self.bytes[start..end]; + + // See IndexEntry for an explanation of this override. + let offset_override = match rev { + 0 => Some(0), + _ => None, + }; + + Some(IndexEntry { + bytes, + offset_override, + }) + } +} + +#[derive(Debug)] +pub struct IndexEntry<'a> { + bytes: &'a [u8], + /// Allows to override the offset value of the entry. + /// + /// For interleaved index and data, the offset stored in the index + /// corresponds to the separated data offset. + /// It has to be overridden with the actual offset in the interleaved + /// index which is just after the index block. + /// + /// For separated index and data, the offset stored in the first index + /// entry is mixed with the index headers. + /// It has to be overridden with 0. + offset_override: Option, +} + +impl<'a> IndexEntry<'a> { + /// Return the offset of the data if not overridden by offset_override. + pub fn offset(&self) -> usize { + if let Some(offset_override) = self.offset_override { + offset_override + } else { + let mut bytes = [0; 8]; + bytes[2..8].copy_from_slice(&self.bytes[0..=5]); + BigEndian::read_u64(&bytes[..]) as usize + } + } + + /// Return the compressed length of the data. + pub fn compressed_len(&self) -> usize { + BigEndian::read_u32(&self.bytes[8..=11]) as usize + } + + /// Return the uncompressed length of the data. + pub fn uncompressed_len(&self) -> usize { + BigEndian::read_u32(&self.bytes[12..=15]) as usize + } + + /// Return the revision upon which the data has been derived. + pub fn base_revision(&self) -> Revision { + // TODO Maybe return an Option when base_revision == rev? + // Requires to add rev to IndexEntry + + BigEndian::read_i32(&self.bytes[16..]) + } + + pub fn p1(&self) -> Revision { + BigEndian::read_i32(&self.bytes[24..]) + } + + pub fn p2(&self) -> Revision { + BigEndian::read_i32(&self.bytes[28..]) + } + + /// Return the hash of revision's full text. + /// + /// Currently, SHA-1 is used and only the first 20 bytes of this field + /// are used. + pub fn hash(&self) -> &[u8] { + &self.bytes[32..52] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(test)] + #[derive(Debug, Copy, Clone)] + pub struct IndexEntryBuilder { + is_first: bool, + is_inline: bool, + is_general_delta: bool, + version: u16, + offset: usize, + compressed_len: usize, + uncompressed_len: usize, + base_revision: Revision, + } + + #[cfg(test)] + impl IndexEntryBuilder { + pub fn new() -> Self { + Self { + is_first: false, + is_inline: false, + is_general_delta: true, + version: 2, + offset: 0, + compressed_len: 0, + uncompressed_len: 0, + base_revision: 0, + } + } + + pub fn is_first(&mut self, value: bool) -> &mut Self { + self.is_first = value; + self + } + + pub fn with_inline(&mut self, value: bool) -> &mut Self { + self.is_inline = value; + self + } + + pub fn with_general_delta(&mut self, value: bool) -> &mut Self { + self.is_general_delta = value; + self + } + + pub fn with_version(&mut self, value: u16) -> &mut Self { + self.version = value; + self + } + + pub fn with_offset(&mut self, value: usize) -> &mut Self { + self.offset = value; + self + } + + pub fn with_compressed_len(&mut self, value: usize) -> &mut Self { + self.compressed_len = value; + self + } + + pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self { + self.uncompressed_len = value; + self + } + + pub fn with_base_revision(&mut self, value: Revision) -> &mut Self { + self.base_revision = value; + self + } + + pub fn build(&self) -> Vec { + let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE); + if self.is_first { + bytes.extend(&match (self.is_general_delta, self.is_inline) { + (false, false) => [0u8, 0], + (false, true) => [0u8, 1], + (true, false) => [0u8, 2], + (true, true) => [0u8, 3], + }); + bytes.extend(&self.version.to_be_bytes()); + // Remaining offset bytes. + bytes.extend(&[0u8; 2]); + } else { + // Offset is only 6 bytes will usize is 8. + bytes.extend(&self.offset.to_be_bytes()[2..]); + } + bytes.extend(&[0u8; 2]); // Revision flags. + bytes.extend(&self.compressed_len.to_be_bytes()[4..]); + bytes.extend(&self.uncompressed_len.to_be_bytes()[4..]); + bytes.extend(&self.base_revision.to_be_bytes()); + bytes + } + } + + #[test] + fn test_offset() { + let bytes = IndexEntryBuilder::new().with_offset(1).build(); + let entry = IndexEntry { + bytes: &bytes, + offset_override: None, + }; + + assert_eq!(entry.offset(), 1) + } + + #[test] + fn test_with_overridden_offset() { + let bytes = IndexEntryBuilder::new().with_offset(1).build(); + let entry = IndexEntry { + bytes: &bytes, + offset_override: Some(2), + }; + + assert_eq!(entry.offset(), 2) + } + + #[test] + fn test_compressed_len() { + let bytes = IndexEntryBuilder::new().with_compressed_len(1).build(); + let entry = IndexEntry { + bytes: &bytes, + offset_override: None, + }; + + assert_eq!(entry.compressed_len(), 1) + } + + #[test] + fn test_uncompressed_len() { + let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build(); + let entry = IndexEntry { + bytes: &bytes, + offset_override: None, + }; + + assert_eq!(entry.uncompressed_len(), 1) + } + + #[test] + fn test_base_revision() { + let bytes = IndexEntryBuilder::new().with_base_revision(1).build(); + let entry = IndexEntry { + bytes: &bytes, + offset_override: None, + }; + + assert_eq!(entry.base_revision(), 1) + } +} + +#[cfg(test)] +pub use tests::IndexEntryBuilder; diff --git a/rust/hg-core/src/revlog/manifest.rs b/rust/hg-core/src/revlog/manifest.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvbWFuaWZlc3QucnM= --- /dev/null +++ b/rust/hg-core/src/revlog/manifest.rs @@ -0,0 +1,73 @@ +use crate::revlog::revlog::{Revlog, RevlogError}; +use crate::revlog::Revision; +use crate::utils::hg_path::HgPath; +use std::path::PathBuf; + +/// A specialized `Revlog` to work with `manifest` data format. +pub struct Manifest { + /// The generic `revlog` format. + revlog: Revlog, +} + +impl Manifest { + /// Open the `manifest` of a repository given by its root. + pub fn open(root: &PathBuf) -> Result { + let index_file = root.join(".hg/store/00manifest.i"); + let revlog = Revlog::open(&index_file)?; + Ok(Self { revlog }) + } + + /// Return the `ManifestEntry` of a given node id. + pub fn get_node(&self, node: &[u8]) -> Result { + let rev = self.revlog.get_node_rev(node)?; + self.get_rev(rev) + } + + /// Return the `ManifestEntry` of a given node revision. + pub fn get_rev( + &self, + rev: Revision, + ) -> Result { + let bytes = self.revlog.get_rev_data(rev)?; + Ok(ManifestEntry { bytes }) + } +} + +/// `Manifest` entry which knows how to interpret the `manifest` data bytes. +#[derive(Debug)] +pub struct ManifestEntry { + bytes: Vec, +} + +impl ManifestEntry { + /// Return an iterator over the lines of the entry. + pub fn lines(&self) -> impl Iterator { + self.bytes + .split(|b| b == &b'\n') + .filter(|line| !line.is_empty()) + } + + /// Return an iterator over the files of the entry. + pub fn files(&self) -> impl Iterator { + self.lines().filter(|line| !line.is_empty()).map(|line| { + let pos = line + .iter() + .position(|x| x == &b'\0') + .expect("manifest line should contain \\0"); + HgPath::new(&line[..pos]) + }) + } + + /// Return an iterator over the files of the entry. + pub fn files_with_nodes(&self) -> impl Iterator { + self.lines().filter(|line| !line.is_empty()).map(|line| { + let pos = line + .iter() + .position(|x| x == &b'\0') + .expect("manifest line should contain \\0"); + let hash_start = pos + 1; + let hash_end = hash_start + 40; + (HgPath::new(&line[..pos]), &line[hash_start..hash_end]) + }) + } +} diff --git a/rust/hg-core/src/revlog/node.rs b/rust/hg-core/src/revlog/node.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvbm9kZS5ycw==..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvbm9kZS5ycw== 100644 --- a/rust/hg-core/src/revlog/node.rs +++ b/rust/hg-core/src/revlog/node.rs @@ -16,7 +16,12 @@ /// are private so that calling code does not expect all nodes have /// the same size, should we support several formats concurrently in /// the future. -const NODE_BYTES_LENGTH: usize = 20; +pub const NODE_BYTES_LENGTH: usize = 20; + +/// Id of the null node. +/// +/// Used to indicate the absence of node. +pub const NULL_NODE_ID: [u8; NODE_BYTES_LENGTH] = [0u8; NODE_BYTES_LENGTH]; /// The length in bytes of a `Node` /// diff --git a/rust/hg-core/src/revlog/patch.rs b/rust/hg-core/src/revlog/patch.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvcGF0Y2gucnM= --- /dev/null +++ b/rust/hg-core/src/revlog/patch.rs @@ -0,0 +1,367 @@ +use byteorder::{BigEndian, ByteOrder}; + +/// A chunk of data to insert, delete or replace in a patch +/// +/// A chunk is: +/// - an insertion when `!data.is_empty() && start == end` +/// - an deletion when `data.is_empty() && start < end` +/// - a replacement when `!data.is_empty() && start < end` +/// - not doing anything when `data.is_empty() && start == end` +#[derive(Debug, Clone)] +struct PatchFrag<'a> { + /// The start position of the chunk of data to replace + start: i32, + /// The end position of the chunk of data to replace (open end interval) + end: i32, + /// The data replacing the chunk + data: &'a [u8], +} + +impl<'a> PatchFrag<'a> { + /// Adjusted start of the chunk to replace. + /// + /// Offset allow to take into account the growth/shrinkage of data + /// induced by previously applied chunks. + fn start_offseted_by(&self, offset: i32) -> i32 { + self.start + offset + } + + /// Adjusted end of the chunk to replace. + /// + /// Offset allow to take into account the growth/shrinkage of data + /// induced by previously applied chunks. + fn end_offseted_by(&self, offset: i32) -> i32 { + self.start_offseted_by(offset) + (self.data.len() as i32) + } + + /// Length of the replaced chunk. + fn replaced_len(&self) -> i32 { + self.end - self.start + } + + /// Length difference between the replacing data and the replaced data. + fn len_diff(&self) -> i32 { + (self.data.len() as i32) - self.replaced_len() + } +} + +/// The delta between two revisions data. +#[derive(Debug, Clone)] +pub struct PatchList<'a> { + /// A collection of chunks to apply. + /// + /// Those chunks are: + /// - ordered from the left-most replacement to the right-most replacement + /// - non-overlapping, meaning that two chucks can not change the same + /// chunk of the patched data + frags: Vec>, +} + +impl<'a> PatchList<'a> { + /// Create a `PatchList` from bytes. + pub fn new(data: &'a [u8]) -> Self { + let mut frags = vec![]; + let mut data = data; + while !data.is_empty() { + let start = BigEndian::read_i32(&data[0..]); + let end = BigEndian::read_i32(&data[4..]); + let len = BigEndian::read_i32(&data[8..]); + assert!(0 <= start && start <= end && len >= 0); + frags.push(PatchFrag { + start, + end, + data: &data[12..12 + (len as usize)], + }); + data = &data[12 + (len as usize)..]; + } + PatchList { frags } + } + + /// Return the final length of data after patching + /// given its initial length . + fn size(&self, initial_size: i32) -> i32 { + self.frags + .iter() + .fold(initial_size, |acc, frag| acc + frag.len_diff()) + } + + /// Apply the patch to some data. + pub fn apply(&self, initial: &[u8]) -> Vec { + let mut last: usize = 0; + let mut vec = + Vec::with_capacity(self.size(initial.len() as i32) as usize); + for PatchFrag { start, end, data } in self.frags.iter() { + vec.extend(&initial[last..(*start as usize)]); + vec.extend(data.iter()); + last = *end as usize; + } + vec.extend(&initial[last..]); + vec + } + + /// Combine two patch lists into a single patch list. + /// + /// Applying consecutive patches can lead to waste of time and memory + /// as the changes introduced by one patch can be overridden by the next. + /// Combining patches optimizes the whole patching sequence. + fn combine(&mut self, other: &mut Self) -> Self { + let mut frags = vec![]; + + // Keep track of each growth/shrinkage resulting from applying a chunk + // in order to adjust the start/end of subsequent chunks. + let mut offset = 0i32; + + // Keep track of the chunk of self.chunks to process. + let mut pos = 0; + + // For each chunk of `other`, chunks of `self` are processed + // until they start after the end of the current chunk. + for PatchFrag { start, end, data } in other.frags.iter() { + // Add chunks of `self` that start before this chunk of `other` + // without overlap. + while pos < self.frags.len() + && self.frags[pos].end_offseted_by(offset) <= *start + { + let first = self.frags[pos].clone(); + offset += first.len_diff(); + frags.push(first); + pos += 1; + } + + // The current chunk of `self` starts before this chunk of `other` + // with overlap. + // The left-most part of data is added as an insertion chunk. + // The right-most part data is kept in the chunk. + if pos < self.frags.len() + && self.frags[pos].start_offseted_by(offset) < *start + { + let first = &mut self.frags[pos]; + + let (data_left, data_right) = first.data.split_at( + (*start - first.start_offseted_by(offset)) as usize, + ); + let left = PatchFrag { + start: first.start, + end: first.start, + data: data_left, + }; + + first.data = data_right; + + offset += left.len_diff(); + + frags.push(left); + + // There is no index incrementation because the right-most part + // needs further examination. + } + + // At this point remaining chunks of `self` starts after + // the current chunk of `other`. + + // `start_offset` will be used to adjust the start of the current + // chunk of `other`. + // Offset tracking continues with `end_offset` to adjust the end + // of the current chunk of `other`. + let mut next_offset = offset; + + // Discard the chunks of `self` that are totally overridden + // by the current chunk of `other` + while pos < self.frags.len() + && self.frags[pos].end_offseted_by(next_offset) <= *end + { + let first = &self.frags[pos]; + next_offset += first.len_diff(); + pos += 1; + } + + // Truncate the left-most part of chunk of `self` that overlaps + // the current chunk of `other`. + if pos < self.frags.len() + && self.frags[pos].start_offseted_by(next_offset) < *end + { + let first = &mut self.frags[pos]; + + let how_much_to_discard = + *end - first.start_offseted_by(next_offset); + + first.data = &first.data[(how_much_to_discard as usize)..]; + + next_offset += how_much_to_discard; + } + + // Add the chunk of `other` with adjusted position. + frags.push(PatchFrag { + start: *start - offset, + end: *end - next_offset, + data, + }); + + // Go back to normal offset tracking for the next `o` chunk + offset = next_offset; + } + + // Add remaining chunks of `self`. + for elt in &self.frags[pos..] { + frags.push(elt.clone()); + } + PatchList { frags } + } +} + +/// Combine a list of patch list into a single patch optimized patch list. +pub fn fold_patch_lists<'a>(lists: &[PatchList<'a>]) -> PatchList<'a> { + if lists.len() <= 1 { + if lists.is_empty() { + PatchList { frags: vec![] } + } else { + lists[0].clone() + } + } else { + let (left, right) = lists.split_at(lists.len() / 2); + let mut left_res = fold_patch_lists(left); + let mut right_res = fold_patch_lists(right); + left_res.combine(&mut right_res) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + struct PatchDataBuilder { + data: Vec, + } + + impl PatchDataBuilder { + pub fn new() -> Self { + Self { data: vec![] } + } + + pub fn replace( + &mut self, + start: usize, + end: usize, + data: &[u8], + ) -> &mut Self { + assert!(start <= end); + self.data.extend(&(start as i32).to_be_bytes()); + self.data.extend(&(end as i32).to_be_bytes()); + self.data.extend(&(data.len() as i32).to_be_bytes()); + self.data.extend(data.iter()); + self + } + + pub fn get(&mut self) -> &[u8] { + &self.data[..] + } + } + + #[test] + fn test_ends_before() { + let data = vec![0u8, 0u8, 0u8]; + let mut patch1_data = PatchDataBuilder::new(); + patch1_data.replace(0, 1, &[1, 2]); + let mut patch1 = PatchList::new(patch1_data.get()); + + let mut patch2_data = PatchDataBuilder::new(); + patch2_data.replace(2, 4, &[3, 4]); + let mut patch2 = PatchList::new(patch2_data.get()); + + let patch = patch1.combine(&mut patch2); + + let result = patch.apply(&data); + + assert_eq!(result, vec![1u8, 2, 3, 4]); + } + + #[test] + fn test_starts_after() { + let data = vec![0u8, 0u8, 0u8]; + let mut patch1_data = PatchDataBuilder::new(); + patch1_data.replace(2, 3, &[3]); + let mut patch1 = PatchList::new(patch1_data.get()); + + let mut patch2_data = PatchDataBuilder::new(); + patch2_data.replace(1, 2, &[1, 2]); + let mut patch2 = PatchList::new(patch2_data.get()); + + let patch = patch1.combine(&mut patch2); + + let result = patch.apply(&data); + + assert_eq!(result, vec![0u8, 1, 2, 3]); + } + + #[test] + fn test_overridden() { + let data = vec![0u8, 0, 0]; + let mut patch1_data = PatchDataBuilder::new(); + patch1_data.replace(1, 2, &[3, 4]); + let mut patch1 = PatchList::new(patch1_data.get()); + + let mut patch2_data = PatchDataBuilder::new(); + patch2_data.replace(1, 4, &[1, 2, 3]); + let mut patch2 = PatchList::new(patch2_data.get()); + + let patch = patch1.combine(&mut patch2); + + let result = patch.apply(&data); + + assert_eq!(result, vec![0u8, 1, 2, 3]); + } + + #[test] + fn test_right_most_part_is_overridden() { + let data = vec![0u8, 0, 0]; + let mut patch1_data = PatchDataBuilder::new(); + patch1_data.replace(0, 1, &[1, 3]); + let mut patch1 = PatchList::new(patch1_data.get()); + + let mut patch2_data = PatchDataBuilder::new(); + patch2_data.replace(1, 4, &[2, 3, 4]); + let mut patch2 = PatchList::new(patch2_data.get()); + + let patch = patch1.combine(&mut patch2); + + let result = patch.apply(&data); + + assert_eq!(result, vec![1u8, 2, 3, 4]); + } + + #[test] + fn test_left_most_part_is_overridden() { + let data = vec![0u8, 0, 0]; + let mut patch1_data = PatchDataBuilder::new(); + patch1_data.replace(1, 3, &[1, 3, 4]); + let mut patch1 = PatchList::new(patch1_data.get()); + + let mut patch2_data = PatchDataBuilder::new(); + patch2_data.replace(0, 2, &[1, 2]); + let mut patch2 = PatchList::new(patch2_data.get()); + + let patch = patch1.combine(&mut patch2); + + let result = patch.apply(&data); + + assert_eq!(result, vec![1u8, 2, 3, 4]); + } + + #[test] + fn test_mid_is_overridden() { + let data = vec![0u8, 0, 0]; + let mut patch1_data = PatchDataBuilder::new(); + patch1_data.replace(0, 3, &[1, 3, 3, 4]); + let mut patch1 = PatchList::new(patch1_data.get()); + + let mut patch2_data = PatchDataBuilder::new(); + patch2_data.replace(1, 3, &[2, 3]); + let mut patch2 = PatchList::new(patch2_data.get()); + + let patch = patch1.combine(&mut patch2); + + let result = patch.apply(&data); + + assert_eq!(result, vec![1u8, 2, 3, 4]); + } +} diff --git a/rust/hg-core/src/revlog/path_encode.rs b/rust/hg-core/src/revlog/path_encode.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvcGF0aF9lbmNvZGUucnM= --- /dev/null +++ b/rust/hg-core/src/revlog/path_encode.rs @@ -0,0 +1,653 @@ +use crypto::digest::Digest; +use crypto::sha1::Sha1; + +#[derive(PartialEq, Debug)] +#[allow(non_camel_case_types)] +enum path_state { + START, /* first byte of a path component */ + A, /* "AUX" */ + AU, + THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */ + C, /* "CON" or "COMn" */ + CO, + COMLPT, /* "COM" or "LPT" */ + COMLPTn, + L, + LP, + N, + NU, + P, /* "PRN" */ + PR, + LDOT, /* leading '.' */ + DOT, /* '.' in a non-leading position */ + H, /* ".h" */ + HGDI, /* ".hg", ".d", or ".i" */ + SPACE, + DEFAULT, /* byte of a path component after the first */ +} + +/* state machine for dir-encoding */ +#[allow(non_camel_case_types)] +enum dir_state { + DDOT, + DH, + DHGDI, + DDEFAULT, +} + +fn inset(bitset: &[u32; 8], c: u8) -> bool { + bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0 +} + +fn charcopy(dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) { + if let Some(slice) = dest { + slice[*destlen] = c + } + *destlen += 1 +} + +fn memcopy(dest: Option<&mut [u8]>, destlen: &mut usize, src: &[u8]) { + if let Some(slice) = dest { + slice[*destlen..*destlen + src.len()].copy_from_slice(src) + } + *destlen += src.len(); +} + +fn rewrap_option<'a, 'b: 'a>( + x: &'a mut Option<&'b mut [u8]>, +) -> Option<&'a mut [u8]> { + match x { + None => None, + Some(y) => Some(y), + } +} + +fn hexencode<'a>(mut dest: Option<&'a mut [u8]>, destlen: &mut usize, c: u8) { + let hexdigit = b"0123456789abcdef"; + charcopy( + rewrap_option(&mut dest), + destlen, + hexdigit[(c as usize) >> 4], + ); + charcopy(dest, destlen, hexdigit[(c as usize) & 15]); +} + +/* 3-byte escape: tilde followed by two hex digits */ +fn escape3(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) { + charcopy(rewrap_option(&mut dest), destlen, b'~'); + hexencode(dest, destlen, c); +} + +fn encode_dir(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize { + let mut state = dir_state::DDEFAULT; + let mut i = 0; + let mut destlen = 0; + + while i < src.len() { + match state { + dir_state::DDOT => match src[i] { + b'd' | b'i' => { + state = dir_state::DHGDI; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'h' => { + state = dir_state::DH; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + _ => { + state = dir_state::DDEFAULT; + } + }, + dir_state::DH => { + if src[i] == b'g' { + state = dir_state::DHGDI; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } else { + state = dir_state::DDEFAULT; + } + } + dir_state::DHGDI => { + if src[i] == b'/' { + memcopy(rewrap_option(&mut dest), &mut destlen, b".hg"); + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + state = dir_state::DDEFAULT; + } + dir_state::DDEFAULT => { + if src[i] == b'.' { + state = dir_state::DDOT + } + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + } + } + destlen +} + +fn _encode( + twobytes: &[u32; 8], + onebyte: &[u32; 8], + mut dest: Option<&mut [u8]>, + src: &[u8], + encodedir: bool, +) -> usize { + let mut state = path_state::START; + let mut i = 0; + let mut destlen = 0; + let len = src.len(); + + while i < len { + match state { + path_state::START => match src[i] { + b'/' => { + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'.' => { + state = path_state::LDOT; + escape3(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b' ' => { + state = path_state::DEFAULT; + escape3(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'a' => { + state = path_state::A; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'c' => { + state = path_state::C; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'l' => { + state = path_state::L; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'n' => { + state = path_state::N; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'p' => { + state = path_state::P; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + _ => { + state = path_state::DEFAULT; + } + }, + path_state::A => { + if src[i] == b'u' { + state = path_state::AU; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::AU => { + if src[i] == b'x' { + state = path_state::THIRD; + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::THIRD => { + state = path_state::DEFAULT; + match src[i] { + b'.' | b'/' | b'\0' => escape3( + rewrap_option(&mut dest), + &mut destlen, + src[i - 1], + ), + _ => i -= 1, + } + } + path_state::C => { + if src[i] == b'o' { + state = path_state::CO; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::CO => { + if src[i] == b'm' { + state = path_state::COMLPT; + i += 1; + } else if src[i] == b'n' { + state = path_state::THIRD; + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::COMLPT => { + if src[i] >= b'1' && src[i] <= b'9' { + state = path_state::COMLPTn; + i += 1; + } else { + state = path_state::DEFAULT; + charcopy( + rewrap_option(&mut dest), + &mut destlen, + src[i - 1], + ); + } + } + path_state::COMLPTn => { + state = path_state::DEFAULT; + match src[i] { + b'.' | b'/' | b'\0' => { + escape3( + rewrap_option(&mut dest), + &mut destlen, + src[i - 2], + ); + charcopy( + rewrap_option(&mut dest), + &mut destlen, + src[i - 1], + ); + } + _ => { + memcopy( + rewrap_option(&mut dest), + &mut destlen, + &src[i - 2..i], + ); + } + } + } + path_state::L => { + if src[i] == b'p' { + state = path_state::LP; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::LP => { + if src[i] == b't' { + state = path_state::COMLPT; + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::N => { + if src[i] == b'u' { + state = path_state::NU; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::NU => { + if src[i] == b'l' { + state = path_state::THIRD; + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::P => { + if src[i] == b'r' { + state = path_state::PR; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::PR => { + if src[i] == b'n' { + state = path_state::THIRD; + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::LDOT => match src[i] { + b'd' | b'i' => { + state = path_state::HGDI; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'h' => { + state = path_state::H; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + _ => { + state = path_state::DEFAULT; + } + }, + path_state::DOT => match src[i] { + b'/' | b'\0' => { + state = path_state::START; + memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e"); + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'd' | b'i' => { + state = path_state::HGDI; + charcopy(rewrap_option(&mut dest), &mut destlen, b'.'); + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + b'h' => { + state = path_state::H; + memcopy(rewrap_option(&mut dest), &mut destlen, b".h"); + i += 1; + } + _ => { + state = path_state::DEFAULT; + charcopy(rewrap_option(&mut dest), &mut destlen, b'.'); + } + }, + path_state::H => { + if src[i] == b'g' { + state = path_state::HGDI; + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } else { + state = path_state::DEFAULT; + } + } + path_state::HGDI => { + if src[i] == b'/' { + state = path_state::START; + if encodedir { + memcopy( + rewrap_option(&mut dest), + &mut destlen, + b".hg", + ); + } + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1 + } else { + state = path_state::DEFAULT; + } + } + path_state::SPACE => match src[i] { + b'/' | b'\0' => { + state = path_state::START; + memcopy(rewrap_option(&mut dest), &mut destlen, b"~20"); + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + _ => { + state = path_state::DEFAULT; + charcopy(rewrap_option(&mut dest), &mut destlen, b' '); + } + }, + path_state::DEFAULT => { + while i != len && inset(onebyte, src[i]) { + charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); + i += 1; + } + if i == len { + break; + } + match src[i] { + b'.' => { + state = path_state::DOT; + i += 1 + } + b' ' => { + state = path_state::SPACE; + i += 1 + } + b'/' => { + state = path_state::START; + charcopy(rewrap_option(&mut dest), &mut destlen, b'/'); + i += 1; + } + _ => { + if inset(onebyte, src[i]) { + loop { + charcopy( + rewrap_option(&mut dest), + &mut destlen, + src[i], + ); + i += 1; + if !(i < len && inset(onebyte, src[i])) { + break; + } + } + } else if inset(twobytes, src[i]) { + let c = src[i]; + i += 1; + charcopy( + rewrap_option(&mut dest), + &mut destlen, + b'_', + ); + charcopy( + rewrap_option(&mut dest), + &mut destlen, + if c == b'_' { b'_' } else { c + 32 }, + ); + } else { + escape3( + rewrap_option(&mut dest), + &mut destlen, + src[i], + ); + i += 1; + } + } + } + } + } + } + match state { + path_state::START => (), + path_state::A => (), + path_state::AU => (), + path_state::THIRD => { + escape3(rewrap_option(&mut dest), &mut destlen, src[i - 1]) + } + path_state::C => (), + path_state::CO => (), + path_state::COMLPT => { + charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1]) + } + path_state::COMLPTn => { + escape3(rewrap_option(&mut dest), &mut destlen, src[i - 2]); + charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1]); + } + path_state::L => (), + path_state::LP => (), + path_state::N => (), + path_state::NU => (), + path_state::P => (), + path_state::PR => (), + path_state::LDOT => (), + path_state::DOT => { + memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e"); + } + path_state::H => (), + path_state::HGDI => (), + path_state::SPACE => { + memcopy(rewrap_option(&mut dest), &mut destlen, b"~20"); + } + path_state::DEFAULT => (), + }; + destlen +} + +fn basic_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize { + let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0]; + let onebyte: [u32; 8] = + [1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0]; + _encode(&twobytes, &onebyte, dest, src, true) +} + +const MAXSTOREPATHLEN: usize = 120; + +fn lower_encode(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize { + let onebyte: [u32; 8] = + [1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0]; + let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0]; + let mut destlen = 0; + for c in src { + if inset(&onebyte, *c) { + charcopy(rewrap_option(&mut dest), &mut destlen, *c) + } else if inset(&lower, *c) { + charcopy(rewrap_option(&mut dest), &mut destlen, *c + 32) + } else { + escape3(rewrap_option(&mut dest), &mut destlen, *c) + } + } + destlen +} + +fn aux_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize { + let twobytes = [0; 8]; + let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0]; + _encode(&twobytes, &onebyte, dest, src, false) +} + +fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec { + let dirprefixlen = 8; + let maxshortdirslen = 68; + let mut destlen = 0; + + let last_slash = src.iter().rposition(|b| *b == b'/'); + let last_dot: Option = { + let s = last_slash.unwrap_or(0); + src[s..] + .iter() + .rposition(|b| *b == b'.') + .and_then(|i| Some(i + s)) + }; + + let mut dest = vec![0; MAXSTOREPATHLEN]; + memcopy(Some(&mut dest), &mut destlen, b"dh/"); + + { + let mut first = true; + for slice in src[..last_slash.unwrap_or_else(|| src.len())] + .split(|b| *b == b'/') + { + let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)]; + if destlen + (slice.len() + if first { 0 } else { 1 }) + > maxshortdirslen + 3 + { + break; + } else { + if !first { + charcopy(Some(&mut dest), &mut destlen, b'/') + }; + memcopy(Some(&mut dest), &mut destlen, slice); + if dest[destlen - 1] == b'.' || dest[destlen - 1] == b' ' { + dest[destlen - 1] = b'_' + } + } + first = false; + } + if !first { + charcopy(Some(&mut dest), &mut destlen, b'/'); + } + } + + let used = destlen + 40 + { + if let Some(l) = last_dot { + src.len() - l + } else { + 0 + } + }; + + if MAXSTOREPATHLEN > used { + let slop = MAXSTOREPATHLEN - used; + let basenamelen = match last_slash { + Some(l) => src.len() - l - 1, + None => src.len(), + }; + let basenamelen = std::cmp::min(basenamelen, slop); + if basenamelen > 0 { + let start = match last_slash { + Some(l) => l + 1, + None => 0, + }; + memcopy( + Some(&mut dest), + &mut destlen, + &src[start..][..basenamelen], + ) + } + } + for c in sha { + hexencode(Some(&mut dest), &mut destlen, *c); + } + if let Some(l) = last_dot { + memcopy(Some(&mut dest), &mut destlen, &src[l..]); + } + if destlen == dest.len() { + dest + } else { + // sometimes the path are shorter than MAXSTOREPATHLEN + dest[..destlen].to_vec() + } +} + +const MAXENCODE: usize = 4096 * 4; +fn hash_encode(src: &[u8]) -> Vec { + let dired = &mut [0; MAXENCODE]; + let lowered = &mut [0; MAXENCODE]; + let auxed = &mut [0; MAXENCODE]; + let baselen = (src.len() - 5) * 3; + if baselen >= MAXENCODE { + panic!("path_encode::hash_encore: string too long: {}", baselen) + }; + let dirlen = encode_dir(Some(&mut dired[..]), src); + let sha = { + let mut hasher = Sha1::new(); + hasher.input(&dired[..dirlen]); + let mut hash = vec![0; 20]; + hasher.result(&mut hash); + hash + }; + let lowerlen = lower_encode(Some(&mut lowered[..]), &dired[..dirlen][5..]); + let auxlen = aux_encode(Some(&mut auxed[..]), &lowered[..lowerlen]); + hash_mangle(&auxed[..auxlen], &sha) +} + +pub fn path_encode(path: &[u8]) -> Vec { + let newlen = if path.len() <= MAXSTOREPATHLEN { + basic_encode(None, path) + } else { + MAXSTOREPATHLEN + 1 + }; + if newlen <= MAXSTOREPATHLEN { + if newlen == path.len() { + path.to_vec() + } else { + let mut res = vec![0; newlen]; + basic_encode(Some(&mut res), path); + res + } + } else { + hash_encode(&path) + } +} diff --git a/rust/hg-core/src/revlog/revlog.rs b/rust/hg-core/src/revlog/revlog.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvcmV2bG9nLnJz --- /dev/null +++ b/rust/hg-core/src/revlog/revlog.rs @@ -0,0 +1,438 @@ +use std::borrow::Cow; +use std::fs::File; +use std::io::Read; +use std::ops::Deref; +use std::path::Path; + +use byteorder::{BigEndian, ByteOrder}; +use crypto::digest::Digest; +use crypto::sha1::Sha1; +use flate2::read::ZlibDecoder; +use memmap::{Mmap, MmapOptions}; +use micro_timer::timed; +use zstd; + +use super::index::Index; +use super::node::{NODE_BYTES_LENGTH, NULL_NODE_ID}; +use super::patch; +use crate::revlog::Revision; + +pub enum RevlogError { + IoError(std::io::Error), + UnsuportedVersion(u16), + InvalidRevision, + Corrupted, + UnknowDataFormat(u8), +} + +fn mmap_open(path: &Path) -> Result { + let file = File::open(path)?; + let mmap = unsafe { MmapOptions::new().map(&file) }?; + Ok(mmap) +} + +/// Read only implementation of revlog. +pub struct Revlog { + /// When index and data are not interleaved: bytes of the revlog index. + /// When index and data are interleaved: bytes of the revlog index and + /// data. + index_bytes: Box + Send>, + /// When index and data are not interleaved: bytes of the revlog data + data_bytes: Option + Send>>, +} + +impl Revlog { + /// Open a revlog index file. + /// + /// It will also open the associated data file if index and data are not + /// interleaved. + #[timed] + pub fn open(index_path: &Path) -> Result { + let index_mmap = + mmap_open(&index_path).map_err(RevlogError::IoError)?; + + let version = get_version(&index_mmap); + if version != 1 { + return Err(RevlogError::UnsuportedVersion(version)); + } + + let is_inline = is_inline(&index_mmap); + + let index_bytes = Box::new(index_mmap); + + // TODO load data only when needed // + // type annotation required + // won't recognize Mmap as Deref + let data_bytes: Option + Send>> = + if is_inline { + None + } else { + let data_path = index_path.with_extension("d"); + let data_mmap = + mmap_open(&data_path).map_err(RevlogError::IoError)?; + Some(Box::new(data_mmap)) + }; + + Ok(Revlog { + index_bytes, + data_bytes, + }) + } + + /// Return number of entries of the `Revlog`. + pub fn len(&self) -> usize { + self.index().len() + } + + /// Returns `true` if the `Revlog` has zero `entries`. + pub fn is_empty(&self) -> bool { + self.index().is_empty() + } + + /// Return the full data associated to a node. + #[timed] + pub fn get_node_rev(&self, node: &[u8]) -> Result { + let index = self.index(); + // This is brute force. But it is fast enough for now. + // Optimization will come later. + for rev in (0..self.len() as Revision).rev() { + let index_entry = + index.get_entry(rev).ok_or(RevlogError::Corrupted)?; + if node == index_entry.hash() { + return Ok(rev); + } + } + Err(RevlogError::InvalidRevision) + } + + /// Return the full data associated to a revision. + /// + /// All entries required to build the final data out of deltas will be + /// retrieved as needed, and the deltas will be applied to the inital + /// snapshot to rebuild the final data. + #[timed] + pub fn get_rev_data(&self, rev: Revision) -> Result, RevlogError> { + // Todo return -> Cow + let mut entry = self.get_entry(rev)?; + let mut delta_chain = vec![]; + while let Some(base_rev) = entry.base_rev { + delta_chain.push(entry); + entry = self + .get_entry(base_rev) + .map_err(|_| RevlogError::Corrupted)?; + } + + // TODO do not look twice in the index + let index = self.index(); + let index_entry = + index.get_entry(rev).ok_or(RevlogError::InvalidRevision)?; + + let data: Vec = if delta_chain.is_empty() { + entry.data()?.into() + } else { + Revlog::build_data_from_deltas(entry, &delta_chain)? + }; + + if self.check_hash( + index_entry.p1(), + index_entry.p2(), + index_entry.hash(), + &data, + ) { + Ok(data) + } else { + Err(RevlogError::Corrupted) + } + } + + /// Check the hash of some given data against the recorded hash. + pub fn check_hash( + &self, + p1: Revision, + p2: Revision, + expected: &[u8], + data: &[u8], + ) -> bool { + let index = self.index(); + let e1 = index.get_entry(p1); + let h1 = match e1 { + Some(ref entry) => entry.hash(), + None => &NULL_NODE_ID, + }; + let e2 = index.get_entry(p2); + let h2 = match e2 { + Some(ref entry) => entry.hash(), + None => &NULL_NODE_ID, + }; + + hash(data, &h1, &h2).as_slice() == expected + } + + /// Build the full data of a revision out its snapshot + /// and its deltas. + #[timed] + fn build_data_from_deltas( + snapshot: RevlogEntry, + deltas: &[RevlogEntry], + ) -> Result, RevlogError> { + let snapshot = snapshot.data()?; + let deltas = deltas + .iter() + .rev() + .map(RevlogEntry::data) + .collect::>, RevlogError>>()?; + let patches: Vec<_> = + deltas.iter().map(|d| patch::PatchList::new(d)).collect(); + let patch = patch::fold_patch_lists(&patches); + Ok(patch.apply(&snapshot)) + } + + /// Return the revlog index. + pub fn index(&self) -> Index { + let is_inline = self.data_bytes.is_none(); + Index::new(&self.index_bytes, is_inline) + } + + /// Return the revlog data. + fn data(&self) -> &[u8] { + match self.data_bytes { + Some(ref data_bytes) => &data_bytes, + None => &self.index_bytes, + } + } + + /// Get an entry of the revlog. + fn get_entry(&self, rev: Revision) -> Result { + let index = self.index(); + let index_entry = + index.get_entry(rev).ok_or(RevlogError::InvalidRevision)?; + let start = index_entry.offset(); + let end = start + index_entry.compressed_len(); + let entry = RevlogEntry { + rev, + bytes: &self.data()[start..end], + compressed_len: index_entry.compressed_len(), + uncompressed_len: index_entry.uncompressed_len(), + base_rev: if index_entry.base_revision() == rev { + None + } else { + Some(index_entry.base_revision()) + }, + }; + Ok(entry) + } +} + +/// The revlog entry's bytes and the necessary informations to extract +/// the entry's data. +#[derive(Debug)] +pub struct RevlogEntry<'a> { + rev: Revision, + bytes: &'a [u8], + compressed_len: usize, + uncompressed_len: usize, + base_rev: Option, +} + +impl<'a> RevlogEntry<'a> { + /// Extract the data contained in the entry. + pub fn data(&self) -> Result, RevlogError> { + if self.bytes.is_empty() { + return Ok(Cow::Borrowed(&[])); + } + match self.bytes[0] { + // Revision data is the entirety of the entry, including this + // header. + b'\0' => Ok(Cow::Borrowed(self.bytes)), + // Raw revision data follows. + b'u' => Ok(Cow::Borrowed(&self.bytes[1..])), + // zlib (RFC 1950) data. + b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data())), + // zstd data. + b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data())), + format_type => Err(RevlogError::UnknowDataFormat(format_type)), + } + } + + fn uncompressed_zlib_data(&self) -> Vec { + let mut decoder = ZlibDecoder::new(self.bytes); + if self.is_delta() { + let mut buf = Vec::with_capacity(self.compressed_len); + decoder.read_to_end(&mut buf).expect("corrupted zlib data"); + buf + } else { + let mut buf = vec![0; self.uncompressed_len]; + decoder.read_exact(&mut buf).expect("corrupted zlib data"); + buf + } + } + + fn uncompressed_zstd_data(&self) -> Vec { + if self.is_delta() { + let mut buf = Vec::with_capacity(self.compressed_len); + zstd::stream::copy_decode(self.bytes, &mut buf) + .expect("corrupted zstd data"); + buf + } else { + let mut buf = vec![0; self.uncompressed_len]; + let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf) + .expect("corrupted zstd data"); + assert_eq!(len, self.uncompressed_len, "corrupted zstd data"); + buf + } + } + + /// Tell if the entry is a snapshot or a delta + /// (influences on decompression). + fn is_delta(&self) -> bool { + self.base_rev.is_some() + } +} + +/// Value of the inline flag. +pub fn is_inline(index_bytes: &[u8]) -> bool { + match &index_bytes[0..=1] { + [0, 0] | [0, 2] => false, + _ => true, + } +} + +/// Format version of the revlog. +pub fn get_version(index_bytes: &[u8]) -> u16 { + BigEndian::read_u16(&index_bytes[2..=3]) +} + +/// Calculate the hash of a revision given its data and its parents. +fn hash(data: &[u8], p1_hash: &[u8], p2_hash: &[u8]) -> Vec { + let mut hasher = Sha1::new(); + let (a, b) = (p1_hash, p2_hash); + if a > b { + hasher.input(b); + hasher.input(a); + } else { + hasher.input(a); + hasher.input(b); + } + hasher.input(data); + let mut hash = vec![0; NODE_BYTES_LENGTH]; + hasher.result(&mut hash); + hash +} + +#[cfg(test)] +mod tests { + use super::*; + + use super::super::index::IndexEntryBuilder; + + #[cfg(test)] + pub struct RevlogBuilder { + version: u16, + is_general_delta: bool, + is_inline: bool, + offset: usize, + index: Vec>, + data: Vec>, + } + + #[cfg(test)] + impl RevlogBuilder { + pub fn new() -> Self { + Self { + version: 2, + is_inline: false, + is_general_delta: true, + offset: 0, + index: vec![], + data: vec![], + } + } + + pub fn with_inline(&mut self, value: bool) -> &mut Self { + self.is_inline = value; + self + } + + pub fn with_general_delta(&mut self, value: bool) -> &mut Self { + self.is_general_delta = value; + self + } + + pub fn with_version(&mut self, value: u16) -> &mut Self { + self.version = value; + self + } + + pub fn push( + &mut self, + mut index: IndexEntryBuilder, + data: Vec, + ) -> &mut Self { + if self.index.is_empty() { + index.is_first(true); + index.with_general_delta(self.is_general_delta); + index.with_inline(self.is_inline); + index.with_version(self.version); + } else { + index.with_offset(self.offset); + } + self.index.push(index.build()); + self.offset += data.len(); + self.data.push(data); + self + } + + pub fn build_inline(&self) -> Vec { + let mut bytes = + Vec::with_capacity(self.index.len() + self.data.len()); + for (index, data) in self.index.iter().zip(self.data.iter()) { + bytes.extend(index); + bytes.extend(data); + } + bytes + } + } + + #[test] + fn is_not_inline_when_no_inline_flag_test() { + let bytes = RevlogBuilder::new() + .with_general_delta(false) + .with_inline(false) + .push(IndexEntryBuilder::new(), vec![]) + .build_inline(); + + assert_eq!(is_inline(&bytes), false) + } + + #[test] + fn is_inline_when_inline_flag_test() { + let bytes = RevlogBuilder::new() + .with_general_delta(false) + .with_inline(true) + .push(IndexEntryBuilder::new(), vec![]) + .build_inline(); + + assert_eq!(is_inline(&bytes), true) + } + + #[test] + fn is_inline_when_inline_and_generaldelta_flags_test() { + let bytes = RevlogBuilder::new() + .with_general_delta(true) + .with_inline(true) + .push(IndexEntryBuilder::new(), vec![]) + .build_inline(); + + assert_eq!(is_inline(&bytes), true) + } + + #[test] + fn version_test() { + let bytes = RevlogBuilder::new() + .with_version(1) + .push(IndexEntryBuilder::new(), vec![]) + .build_inline(); + + assert_eq!(get_version(&bytes), 1) + } +} diff --git a/rust/hg-core/src/utils/hg_path.rs b/rust/hg-core/src/utils/hg_path.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9oZy1jb3JlL3NyYy91dGlscy9oZ19wYXRoLnJz..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9oZy1jb3JlL3NyYy91dGlscy9oZ19wYXRoLnJz 100644 --- a/rust/hg-core/src/utils/hg_path.rs +++ b/rust/hg-core/src/utils/hg_path.rs @@ -6,6 +6,7 @@ // GNU General Public License version 2 or any later version. use std::borrow::Borrow; +use std::convert::TryFrom; use std::ffi::{OsStr, OsString}; use std::fmt; use std::ops::Deref; @@ -515,6 +516,13 @@ Ok(buf) } +impl TryFrom for HgPathBuf { + type Error = HgPathError; + fn try_from(path: PathBuf) -> Result { + path_to_hg_path_buf(path) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/rust/rhg/Cargo.toml b/rust/rhg/Cargo.toml index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9yaGcvQ2FyZ28udG9tbA==..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9yaGcvQ2FyZ28udG9tbA== 100644 --- a/rust/rhg/Cargo.toml +++ b/rust/rhg/Cargo.toml @@ -7,4 +7,6 @@ [dependencies] hg-core = { path = "../hg-core"} clap = "2.33.1" - +log = "0.4.11" +micro-timer = "0.3.1" +env_logger = "0.7.1" diff --git a/rust/rhg/src/commands.rs b/rust/rhg/src/commands.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9yaGcvc3JjL2NvbW1hbmRzLnJz..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9yaGcvc3JjL2NvbW1hbmRzLnJz 100644 --- a/rust/rhg/src/commands.rs +++ b/rust/rhg/src/commands.rs @@ -1,3 +1,5 @@ +pub mod cat; +pub mod debugdata; pub mod files; pub mod root; use crate::error::CommandError; diff --git a/rust/rhg/src/commands/cat.rs b/rust/rhg/src/commands/cat.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9yaGcvc3JjL2NvbW1hbmRzL2NhdC5ycw== --- /dev/null +++ b/rust/rhg/src/commands/cat.rs @@ -0,0 +1,99 @@ +use crate::commands::Command; +use crate::error::{CommandError, CommandErrorKind}; +use crate::ui::utf8_to_local; +use crate::ui::Ui; +use hg::operations::FindRoot; +use hg::operations::{CatRev, CatRevError, CatRevErrorKind}; +use hg::utils::hg_path::HgPathBuf; +use micro_timer::timed; +use std::convert::TryFrom; + +pub const HELP_TEXT: &str = " +Output the current or given revision of files +"; + +pub struct CatCommand<'a> { + rev: Option<&'a str>, + files: Vec<&'a str>, +} + +impl<'a> CatCommand<'a> { + pub fn new(rev: Option<&'a str>, files: Vec<&'a str>) -> Self { + Self { rev, files } + } + + fn display(&self, ui: &Ui, data: &[u8]) -> Result<(), CommandError> { + ui.write_stdout(data)?; + Ok(()) + } +} + +impl<'a> Command for CatCommand<'a> { + #[timed] + fn run(&self, ui: &Ui) -> Result<(), CommandError> { + let root = FindRoot::new().run()?; + let cwd = std::env::current_dir() + .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; + + let mut files = vec![]; + for file in self.files.iter() { + let normalized = cwd.join(&file); + let stripped = normalized + .strip_prefix(&root) + .map_err(|_| CommandErrorKind::Abort(None))?; + let hg_file = HgPathBuf::try_from(stripped.to_path_buf()) + .map_err(|_| CommandErrorKind::Abort(None))?; + files.push(hg_file); + } + + match self.rev { + Some(rev) => { + let mut operation = CatRev::new(&root, rev, &files) + .map_err(|e| map_rev_error(rev, e))?; + let data = + operation.run().map_err(|e| map_rev_error(rev, e))?; + self.display(ui, &data) + } + None => Err(CommandErrorKind::Unimplemented.into()), + } + } +} + +/// Convert `CatRevErrorKind` to `CommandError` +fn map_rev_error(rev: &str, err: CatRevError) -> CommandError { + CommandError { + kind: match err.kind { + CatRevErrorKind::IoError(err) => CommandErrorKind::Abort(Some( + utf8_to_local(&format!("abort: {}\n", err)).into(), + )), + CatRevErrorKind::InvalidRevision => CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: invalid revision identifier{}\n", + rev + )) + .into(), + )), + CatRevErrorKind::UnsuportedRevlogVersion(version) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unsupported revlog version {}\n", + version + )) + .into(), + )) + } + CatRevErrorKind::CorruptedRevlog => CommandErrorKind::Abort(Some( + "abort: corrupted revlog\n".into(), + )), + CatRevErrorKind::UnknowRevlogDataFormat(format) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unknow revlog dataformat {:?}\n", + format + )) + .into(), + )) + } + }, + } +} diff --git a/rust/rhg/src/commands/debugdata.rs b/rust/rhg/src/commands/debugdata.rs new file mode 100644 index 0000000000000000000000000000000000000000..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9yaGcvc3JjL2NvbW1hbmRzL2RlYnVnZGF0YS5ycw== --- /dev/null +++ b/rust/rhg/src/commands/debugdata.rs @@ -0,0 +1,82 @@ +use crate::commands::Command; +use crate::error::{CommandError, CommandErrorKind}; +use crate::ui::utf8_to_local; +use crate::ui::Ui; +use hg::operations::{ + DebugData, DebugDataError, DebugDataErrorKind, DebugDataKind, +}; +use micro_timer::timed; + +pub const HELP_TEXT: &str = " +Dump the contents of a data file revision +"; + +pub struct DebugDataCommand<'a> { + rev: &'a str, + kind: DebugDataKind, +} + +impl<'a> DebugDataCommand<'a> { + pub fn new(rev: &'a str, kind: DebugDataKind) -> Self { + DebugDataCommand { rev, kind } + } +} + +impl<'a> Command for DebugDataCommand<'a> { + #[timed] + fn run(&self, ui: &Ui) -> Result<(), CommandError> { + let mut operation = DebugData::new(self.rev, self.kind); + let data = + operation.run().map_err(|e| to_command_error(self.rev, e))?; + + let mut stdout = ui.stdout_buffer(); + stdout.write_all(&data)?; + stdout.flush()?; + + Ok(()) + } +} + +/// Convert operation errors to command errors +fn to_command_error(rev: &str, err: DebugDataError) -> CommandError { + match err.kind { + DebugDataErrorKind::FindRootError(err) => CommandError::from(err), + DebugDataErrorKind::IoError(err) => CommandError { + kind: CommandErrorKind::Abort(Some( + utf8_to_local(&format!("abort: {}\n", err)).into(), + )), + }, + DebugDataErrorKind::InvalidRevision => CommandError { + kind: CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: invalid revision identifier{}\n", + rev + )) + .into(), + )), + }, + DebugDataErrorKind::UnsuportedRevlogVersion(version) => CommandError { + kind: CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unsupported revlog version {}\n", + version + )) + .into(), + )), + }, + DebugDataErrorKind::CorruptedRevlog => CommandError { + kind: CommandErrorKind::Abort(Some( + "abort: corrupted revlog\n".into(), + )), + }, + DebugDataErrorKind::UnknowRevlogDataFormat(format) => CommandError { + kind: CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unknow revlog dataformat {:?}\n", + format + )) + .into(), + )), + }, + } +} diff --git a/rust/rhg/src/commands/files.rs b/rust/rhg/src/commands/files.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9yaGcvc3JjL2NvbW1hbmRzL2ZpbGVzLnJz..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9yaGcvc3JjL2NvbW1hbmRzL2ZpbGVzLnJz 100644 --- a/rust/rhg/src/commands/files.rs +++ b/rust/rhg/src/commands/files.rs @@ -1,3 +1,4 @@ use crate::commands::Command; use crate::error::{CommandError, CommandErrorKind}; +use crate::ui::utf8_to_local; use crate::ui::Ui; @@ -3,3 +4,11 @@ use crate::ui::Ui; -use hg::operations::{ListTrackedFiles, ListTrackedFilesErrorKind}; +use hg::operations::FindRoot; +use hg::operations::{ + ListDirstateTrackedFiles, ListDirstateTrackedFilesError, + ListDirstateTrackedFilesErrorKind, +}; +use hg::operations::{ + ListRevTrackedFiles, ListRevTrackedFilesError, + ListRevTrackedFilesErrorKind, +}; use hg::utils::files::{get_bytes_from_path, relativize_path}; @@ -5,5 +14,6 @@ use hg::utils::files::{get_bytes_from_path, relativize_path}; -use hg::utils::hg_path::HgPathBuf; +use hg::utils::hg_path::{HgPath, HgPathBuf}; +use std::path::PathBuf; pub const HELP_TEXT: &str = " List tracked files. @@ -11,11 +21,7 @@ Returns 0 on success. "; -pub struct FilesCommand {} - -impl FilesCommand { - pub fn new() -> Self { - FilesCommand {} - } +pub struct FilesCommand<'a> { + rev: Option<&'a str>, } @@ -20,21 +26,7 @@ } -impl Command for FilesCommand { - fn run(&self, ui: &Ui) -> Result<(), CommandError> { - let operation_builder = ListTrackedFiles::new()?; - let operation = operation_builder.load().map_err(|err| { - CommandErrorKind::Abort(Some( - [b"abort: ", err.to_string().as_bytes(), b"\n"] - .concat() - .to_vec(), - )) - })?; - let files = operation.run().map_err(|err| match err.kind { - ListTrackedFilesErrorKind::ParseError(_) => { - CommandErrorKind::Abort(Some( - // TODO find a better error message - b"abort: parse error\n".to_vec(), - )) - } - })?; +impl<'a> FilesCommand<'a> { + pub fn new(rev: Option<&'a str>) -> Self { + FilesCommand { rev } + } @@ -40,4 +32,10 @@ + fn display_files( + &self, + ui: &Ui, + root: &PathBuf, + files: impl IntoIterator, + ) -> Result<(), CommandError> { let cwd = std::env::current_dir() .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; let rooted_cwd = cwd @@ -41,7 +39,7 @@ let cwd = std::env::current_dir() .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; let rooted_cwd = cwd - .strip_prefix(operation_builder.get_root()) + .strip_prefix(&root) .expect("cwd was already checked within the repository"); let rooted_cwd = HgPathBuf::from(get_bytes_from_path(rooted_cwd)); @@ -52,7 +50,6 @@ stdout.write_all(b"\n")?; } stdout.flush()?; - Ok(()) } } @@ -56,3 +53,84 @@ Ok(()) } } + +impl<'a> Command for FilesCommand<'a> { + fn run(&self, ui: &Ui) -> Result<(), CommandError> { + let root = FindRoot::new().run()?; + if let Some(rev) = self.rev { + let mut operation = ListRevTrackedFiles::new(&root, rev) + .map_err(|e| map_rev_error(rev, e))?; + let files = operation.run().map_err(|e| map_rev_error(rev, e))?; + self.display_files(ui, &root, files) + } else { + let mut operation = ListDirstateTrackedFiles::new(&root) + .map_err(map_dirstate_error)?; + let files = operation.run().map_err(map_dirstate_error)?; + self.display_files(ui, &root, files) + } + } +} + +/// Convert `ListRevTrackedFilesErrorKind` to `CommandError` +fn map_rev_error(rev: &str, err: ListRevTrackedFilesError) -> CommandError { + CommandError { + kind: match err.kind { + ListRevTrackedFilesErrorKind::IoError(err) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!("abort: {}\n", err)).into(), + )) + } + ListRevTrackedFilesErrorKind::InvalidRevision => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: invalid revision identifier{}\n", + rev + )) + .into(), + )) + } + ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unsupported revlog version {}\n", + version + )) + .into(), + )) + } + ListRevTrackedFilesErrorKind::CorruptedRevlog => { + CommandErrorKind::Abort(Some( + "abort: corrupted revlog\n".into(), + )) + } + ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unknow revlog dataformat {:?}\n", + format + )) + .into(), + )) + } + }, + } +} + +/// Convert `ListDirstateTrackedFilesError` to `CommandError` +fn map_dirstate_error(err: ListDirstateTrackedFilesError) -> CommandError { + CommandError { + kind: match err.kind { + ListDirstateTrackedFilesErrorKind::IoError(err) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!("abort: {}\n", err)).into(), + )) + } + ListDirstateTrackedFilesErrorKind::ParseError(_) => { + CommandErrorKind::Abort(Some( + // TODO find a better error message + b"abort: parse error\n".to_vec(), + )) + } + }, + } +} diff --git a/rust/rhg/src/error.rs b/rust/rhg/src/error.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9yaGcvc3JjL2Vycm9yLnJz..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9yaGcvc3JjL2Vycm9yLnJz 100644 --- a/rust/rhg/src/error.rs +++ b/rust/rhg/src/error.rs @@ -18,6 +18,8 @@ StderrError, /// The command aborted Abort(Option>), + /// A mercurial capability as not been implemented. + Unimplemented, } impl CommandErrorKind { @@ -28,6 +30,7 @@ CommandErrorKind::StdoutError => exitcode::ABORT, CommandErrorKind::StderrError => exitcode::ABORT, CommandErrorKind::Abort(_) => exitcode::ABORT, + CommandErrorKind::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND, } } diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9yaGcvc3JjL21haW4ucnM=..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9yaGcvc3JjL21haW4ucnM= 100644 --- a/rust/rhg/src/main.rs +++ b/rust/rhg/src/main.rs @@ -1,2 +1,3 @@ +extern crate log; use clap::App; use clap::AppSettings; @@ -1,3 +2,6 @@ use clap::App; use clap::AppSettings; +use clap::Arg; +use clap::ArgGroup; +use clap::ArgMatches; use clap::SubCommand; @@ -3,7 +7,9 @@ use clap::SubCommand; +use hg::operations::DebugDataKind; +use std::convert::TryFrom; mod commands; mod error; mod exitcode; mod ui; use commands::Command; @@ -4,8 +10,9 @@ mod commands; mod error; mod exitcode; mod ui; use commands::Command; +use error::CommandError; fn main() { @@ -10,6 +17,7 @@ fn main() { - let mut app = App::new("rhg") + env_logger::init(); + let app = App::new("rhg") .setting(AppSettings::AllowInvalidUtf8) .setting(AppSettings::SubcommandRequired) .setting(AppSettings::VersionlessSubcommands) @@ -18,7 +26,63 @@ SubCommand::with_name("root").about(commands::root::HELP_TEXT), ) .subcommand( - SubCommand::with_name("files").about(commands::files::HELP_TEXT), + SubCommand::with_name("files") + .arg( + Arg::with_name("rev") + .help("search the repository as it is in REV") + .short("-r") + .long("--revision") + .value_name("REV") + .takes_value(true), + ) + .about(commands::files::HELP_TEXT), + ) + .subcommand( + SubCommand::with_name("cat") + .arg( + Arg::with_name("rev") + .help("search the repository as it is in REV") + .short("-r") + .long("--revision") + .value_name("REV") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("files") + .required(true) + .multiple(true) + .empty_values(false) + .value_name("FILE") + .help("Activity to start: activity@category"), + ) + .about(commands::cat::HELP_TEXT), + ) + .subcommand( + SubCommand::with_name("debugdata") + .about(commands::debugdata::HELP_TEXT) + .arg( + Arg::with_name("changelog") + .help("open changelog") + .short("-c") + .long("--changelog"), + ) + .arg( + Arg::with_name("manifest") + .help("open manifest") + .short("-m") + .long("--manifest"), + ) + .group( + ArgGroup::with_name("") + .args(&["changelog", "manifest"]) + .required(true), + ) + .arg( + Arg::with_name("rev") + .help("revision") + .required(true) + .value_name("REV"), + ), ); let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { @@ -28,19 +92,7 @@ let ui = ui::Ui::new(); - let command_result = match matches.subcommand_name() { - Some(name) => match name { - "root" => commands::root::RootCommand::new().run(&ui), - "files" => commands::files::FilesCommand::new().run(&ui), - _ => std::process::exit(exitcode::UNIMPLEMENTED_COMMAND), - }, - _ => { - match app.print_help() { - Ok(_) => std::process::exit(exitcode::OK), - Err(_) => std::process::exit(exitcode::ABORT), - }; - } - }; + let command_result = match_subcommand(matches, &ui); match command_result { Ok(_) => std::process::exit(exitcode::OK), @@ -56,3 +108,70 @@ } } } + +fn match_subcommand( + matches: ArgMatches, + ui: &ui::Ui, +) -> Result<(), CommandError> { + match matches.subcommand() { + ("root", _) => commands::root::RootCommand::new().run(&ui), + ("files", Some(matches)) => { + commands::files::FilesCommand::try_from(matches)?.run(&ui) + } + ("cat", Some(matches)) => { + commands::cat::CatCommand::try_from(matches)?.run(&ui) + } + ("debugdata", Some(matches)) => { + commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui) + } + _ => unreachable!(), // Because of AppSettings::SubcommandRequired, + } +} + +impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::files::FilesCommand<'a> { + type Error = CommandError; + + fn try_from(args: &'a ArgMatches) -> Result { + let rev = args.value_of("rev"); + Ok(commands::files::FilesCommand::new(rev)) + } +} + +impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::cat::CatCommand<'a> { + type Error = CommandError; + + fn try_from(args: &'a ArgMatches) -> Result { + let rev = args.value_of("rev"); + let files = match args.values_of("files") { + Some(files) => files.collect(), + None => vec![], + }; + Ok(commands::cat::CatCommand::new(rev, files)) + } +} + +impl<'a> TryFrom<&'a ArgMatches<'_>> + for commands::debugdata::DebugDataCommand<'a> +{ + type Error = CommandError; + + fn try_from(args: &'a ArgMatches) -> Result { + let rev = args + .value_of("rev") + .expect("rev should be a required argument"); + let kind = match ( + args.is_present("changelog"), + args.is_present("manifest"), + ) { + (true, false) => DebugDataKind::Changelog, + (false, true) => DebugDataKind::Manifest, + (true, true) => { + unreachable!("Should not happen since options are exclusive") + } + (false, false) => { + unreachable!("Should not happen since options are required") + } + }; + Ok(commands::debugdata::DebugDataCommand::new(rev, kind)) + } +} diff --git a/rust/rhg/src/ui.rs b/rust/rhg/src/ui.rs index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_cnVzdC9yaGcvc3JjL3VpLnJz..fadea21bb46e4890e745fae9616997c814a0ade4_cnVzdC9yaGcvc3JjL3VpLnJz 100644 --- a/rust/rhg/src/ui.rs +++ b/rust/rhg/src/ui.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::io; use std::io::{ErrorKind, Write}; @@ -103,3 +104,10 @@ } Err(UiError::StdoutError(error)) } + +/// Encode rust strings according to the user system. +pub fn utf8_to_local(s: &str) -> Cow<[u8]> { + // TODO encode for the user's system // + let bytes = s.as_bytes(); + Cow::Borrowed(bytes) +} diff --git a/tests/test-rhg.t b/tests/test-rhg.t index 2a68a5ec8dd032e0fce216b46f48c270d5af6c55_dGVzdHMvdGVzdC1yaGcudA==..fadea21bb46e4890e745fae9616997c814a0ade4_dGVzdHMvdGVzdC1yaGcudA== 100644 --- a/tests/test-rhg.t +++ b/tests/test-rhg.t @@ -68,3 +68,25 @@ Listing tracked files through broken pipe $ rhg files | head -n 1 ../../../file1 + +Debuging data in inline index + $ cd $TESTTMP + $ rm -rf repository + $ hg init repository + $ cd repository + $ for i in 1 2 3; do + > echo $i >> file$i + > hg add file$i + > hg commit -m "commit $i" -q + > done + $ rhg debugdata -c 2 + e36fa63d37a576b27a69057598351db6ee5746bd + test + 0 0 + file3 + + commit 3 (no-eol) + $ rhg debugdata -m 2 + file1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc) + file2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc) + file3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)