##// END OF EJS Templates
rhg: Add support for the blackbox extension...
Simon Sapin -
r47343:755c31a1 default
parent child Browse files
Show More
@@ -0,0 +1,161 b''
1 //! Logging for repository events, including commands run in the repository.
2
3 use crate::CliInvocation;
4 use format_bytes::format_bytes;
5 use hg::errors::HgError;
6 use hg::repo::Repo;
7 use hg::utils::{files::get_bytes_from_os_str, shell_quote};
8
9 const ONE_MEBIBYTE: u64 = 1 << 20;
10
11 // TODO: somehow keep defaults in sync with `configitem` in `hgext/blackbox.py`
12 const DEFAULT_MAX_SIZE: u64 = ONE_MEBIBYTE;
13 const DEFAULT_MAX_FILES: u32 = 7;
14
15 // Python does not support %.3f, only %f
16 const DEFAULT_DATE_FORMAT: &str = "%Y/%m/%d %H:%M:%S%.3f";
17
18 type DateTime = chrono::DateTime<chrono::Local>;
19
20 pub struct ProcessStartTime {
21 /// For measuring duration
22 monotonic_clock: std::time::Instant,
23 /// For formatting with year, month, day, etc.
24 calendar_based: DateTime,
25 }
26
27 impl ProcessStartTime {
28 pub fn now() -> Self {
29 Self {
30 monotonic_clock: std::time::Instant::now(),
31 calendar_based: chrono::Local::now(),
32 }
33 }
34 }
35
36 pub struct Blackbox<'a> {
37 process_start_time: &'a ProcessStartTime,
38 /// Do nothing if this is `None`
39 configured: Option<ConfiguredBlackbox<'a>>,
40 }
41
42 struct ConfiguredBlackbox<'a> {
43 repo: &'a Repo,
44 max_size: u64,
45 max_files: u32,
46 date_format: &'a str,
47 }
48
49 impl<'a> Blackbox<'a> {
50 pub fn new(
51 invocation: &'a CliInvocation<'a>,
52 process_start_time: &'a ProcessStartTime,
53 ) -> Result<Self, HgError> {
54 let configured = if let Ok(repo) = invocation.repo {
55 let config = invocation.config();
56 if config.get(b"extensions", b"blackbox").is_none() {
57 // The extension is not enabled
58 None
59 } else {
60 Some(ConfiguredBlackbox {
61 repo,
62 max_size: config
63 .get_byte_size(b"blackbox", b"maxsize")?
64 .unwrap_or(DEFAULT_MAX_SIZE),
65 max_files: config
66 .get_u32(b"blackbox", b"maxfiles")?
67 .unwrap_or(DEFAULT_MAX_FILES),
68 date_format: config
69 .get_str(b"blackbox", b"date-format")?
70 .unwrap_or(DEFAULT_DATE_FORMAT),
71 })
72 }
73 } else {
74 // Without a local repository there’s no `.hg/blackbox.log` to
75 // write to.
76 None
77 };
78 Ok(Self {
79 process_start_time,
80 configured,
81 })
82 }
83
84 pub fn log_command_start(&self) {
85 if let Some(configured) = &self.configured {
86 let message = format_bytes!(b"(rust) {}", format_cli_args());
87 configured.log(&self.process_start_time.calendar_based, &message);
88 }
89 }
90
91 pub fn log_command_end(&self, exit_code: i32) {
92 if let Some(configured) = &self.configured {
93 let now = chrono::Local::now();
94 let duration = self
95 .process_start_time
96 .monotonic_clock
97 .elapsed()
98 .as_secs_f64();
99 let message = format_bytes!(
100 b"(rust) {} exited {} after {} seconds",
101 format_cli_args(),
102 exit_code,
103 format_bytes::Utf8(format_args!("{:.03}", duration))
104 );
105 configured.log(&now, &message);
106 }
107 }
108 }
109
110 impl ConfiguredBlackbox<'_> {
111 fn log(&self, date_time: &DateTime, message: &[u8]) {
112 let date = format_bytes::Utf8(date_time.format(self.date_format));
113 let user = users::get_current_username().map(get_bytes_from_os_str);
114 let user = user.as_deref().unwrap_or(b"???");
115 let rev = format_bytes::Utf8(match self.repo.dirstate_parents() {
116 Ok(parents) if parents.p2 == hg::revlog::node::NULL_NODE => {
117 format!("{:x}", parents.p1)
118 }
119 Ok(parents) => format!("{:x}+{:x}", parents.p1, parents.p2),
120 Err(_dirstate_corruption_error) => {
121 // TODO: log a non-fatal warning to stderr
122 "???".to_owned()
123 }
124 });
125 let pid = std::process::id();
126 let line = format_bytes!(
127 b"{} {} @{} ({})> {}\n",
128 date,
129 user,
130 rev,
131 pid,
132 message
133 );
134 let result =
135 hg::logging::LogFile::new(self.repo.hg_vfs(), "blackbox.log")
136 .max_size(Some(self.max_size))
137 .max_files(self.max_files)
138 .write(&line);
139 match result {
140 Ok(()) => {}
141 Err(_io_error) => {
142 // TODO: log a non-fatal warning to stderr
143 }
144 }
145 }
146 }
147
148 fn format_cli_args() -> Vec<u8> {
149 let mut args = std::env::args_os();
150 let _ = args.next(); // Skip the first (or zeroth) arg, the name of the `rhg` executable
151 let mut args = args.map(|arg| shell_quote(&get_bytes_from_os_str(arg)));
152 let mut formatted = Vec::new();
153 if let Some(arg) = args.next() {
154 formatted.extend(arg)
155 }
156 for arg in args {
157 formatted.push(b' ');
158 formatted.extend(arg)
159 }
160 formatted
161 }
@@ -1,1049 +1,1084 b''
1 # This file is automatically @generated by Cargo.
1 # This file is automatically @generated by Cargo.
2 # It is not intended for manual editing.
2 # It is not intended for manual editing.
3 [[package]]
3 [[package]]
4 name = "adler"
4 name = "adler"
5 version = "0.2.3"
5 version = "0.2.3"
6 source = "registry+https://github.com/rust-lang/crates.io-index"
6 source = "registry+https://github.com/rust-lang/crates.io-index"
7
7
8 [[package]]
8 [[package]]
9 name = "aho-corasick"
9 name = "aho-corasick"
10 version = "0.7.15"
10 version = "0.7.15"
11 source = "registry+https://github.com/rust-lang/crates.io-index"
11 source = "registry+https://github.com/rust-lang/crates.io-index"
12 dependencies = [
12 dependencies = [
13 "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
13 "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
14 ]
14 ]
15
15
16 [[package]]
16 [[package]]
17 name = "ansi_term"
17 name = "ansi_term"
18 version = "0.11.0"
18 version = "0.11.0"
19 source = "registry+https://github.com/rust-lang/crates.io-index"
19 source = "registry+https://github.com/rust-lang/crates.io-index"
20 dependencies = [
20 dependencies = [
21 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
21 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
22 ]
22 ]
23
23
24 [[package]]
24 [[package]]
25 name = "atty"
25 name = "atty"
26 version = "0.2.14"
26 version = "0.2.14"
27 source = "registry+https://github.com/rust-lang/crates.io-index"
27 source = "registry+https://github.com/rust-lang/crates.io-index"
28 dependencies = [
28 dependencies = [
29 "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
29 "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
30 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
30 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
31 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
31 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
32 ]
32 ]
33
33
34 [[package]]
34 [[package]]
35 name = "autocfg"
35 name = "autocfg"
36 version = "1.0.1"
36 version = "1.0.1"
37 source = "registry+https://github.com/rust-lang/crates.io-index"
37 source = "registry+https://github.com/rust-lang/crates.io-index"
38
38
39 [[package]]
39 [[package]]
40 name = "bitflags"
40 name = "bitflags"
41 version = "1.2.1"
41 version = "1.2.1"
42 source = "registry+https://github.com/rust-lang/crates.io-index"
42 source = "registry+https://github.com/rust-lang/crates.io-index"
43
43
44 [[package]]
44 [[package]]
45 name = "bitmaps"
45 name = "bitmaps"
46 version = "2.1.0"
46 version = "2.1.0"
47 source = "registry+https://github.com/rust-lang/crates.io-index"
47 source = "registry+https://github.com/rust-lang/crates.io-index"
48 dependencies = [
48 dependencies = [
49 "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
49 "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
50 ]
50 ]
51
51
52 [[package]]
52 [[package]]
53 name = "byteorder"
53 name = "byteorder"
54 version = "1.3.4"
54 version = "1.3.4"
55 source = "registry+https://github.com/rust-lang/crates.io-index"
55 source = "registry+https://github.com/rust-lang/crates.io-index"
56
56
57 [[package]]
57 [[package]]
58 name = "bytes-cast"
58 name = "bytes-cast"
59 version = "0.1.0"
59 version = "0.1.0"
60 source = "registry+https://github.com/rust-lang/crates.io-index"
60 source = "registry+https://github.com/rust-lang/crates.io-index"
61 dependencies = [
61 dependencies = [
62 "bytes-cast-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
62 "bytes-cast-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
63 ]
63 ]
64
64
65 [[package]]
65 [[package]]
66 name = "bytes-cast-derive"
66 name = "bytes-cast-derive"
67 version = "0.1.0"
67 version = "0.1.0"
68 source = "registry+https://github.com/rust-lang/crates.io-index"
68 source = "registry+https://github.com/rust-lang/crates.io-index"
69 dependencies = [
69 dependencies = [
70 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
70 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
71 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
71 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
72 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
72 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
73 ]
73 ]
74
74
75 [[package]]
75 [[package]]
76 name = "cc"
76 name = "cc"
77 version = "1.0.66"
77 version = "1.0.66"
78 source = "registry+https://github.com/rust-lang/crates.io-index"
78 source = "registry+https://github.com/rust-lang/crates.io-index"
79 dependencies = [
79 dependencies = [
80 "jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
80 "jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
81 ]
81 ]
82
82
83 [[package]]
83 [[package]]
84 name = "cfg-if"
84 name = "cfg-if"
85 version = "0.1.10"
85 version = "0.1.10"
86 source = "registry+https://github.com/rust-lang/crates.io-index"
86 source = "registry+https://github.com/rust-lang/crates.io-index"
87
87
88 [[package]]
88 [[package]]
89 name = "cfg-if"
89 name = "cfg-if"
90 version = "1.0.0"
90 version = "1.0.0"
91 source = "registry+https://github.com/rust-lang/crates.io-index"
91 source = "registry+https://github.com/rust-lang/crates.io-index"
92
92
93 [[package]]
93 [[package]]
94 name = "chrono"
95 version = "0.4.19"
96 source = "registry+https://github.com/rust-lang/crates.io-index"
97 dependencies = [
98 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
99 "num-integer 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
100 "num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
101 "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
102 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
103 ]
104
105 [[package]]
94 name = "clap"
106 name = "clap"
95 version = "2.33.3"
107 version = "2.33.3"
96 source = "registry+https://github.com/rust-lang/crates.io-index"
108 source = "registry+https://github.com/rust-lang/crates.io-index"
97 dependencies = [
109 dependencies = [
98 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
110 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
99 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
111 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
100 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
112 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
101 "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
113 "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
102 "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
114 "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
103 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
115 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
104 "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
116 "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
105 ]
117 ]
106
118
107 [[package]]
119 [[package]]
108 name = "const_fn"
120 name = "const_fn"
109 version = "0.4.4"
121 version = "0.4.4"
110 source = "registry+https://github.com/rust-lang/crates.io-index"
122 source = "registry+https://github.com/rust-lang/crates.io-index"
111
123
112 [[package]]
124 [[package]]
113 name = "cpython"
125 name = "cpython"
114 version = "0.4.1"
126 version = "0.4.1"
115 source = "registry+https://github.com/rust-lang/crates.io-index"
127 source = "registry+https://github.com/rust-lang/crates.io-index"
116 dependencies = [
128 dependencies = [
117 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
129 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
118 "num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
130 "num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
119 "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
131 "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
120 "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
132 "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
121 ]
133 ]
122
134
123 [[package]]
135 [[package]]
124 name = "crc32fast"
136 name = "crc32fast"
125 version = "1.2.1"
137 version = "1.2.1"
126 source = "registry+https://github.com/rust-lang/crates.io-index"
138 source = "registry+https://github.com/rust-lang/crates.io-index"
127 dependencies = [
139 dependencies = [
128 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
140 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
129 ]
141 ]
130
142
131 [[package]]
143 [[package]]
132 name = "crossbeam-channel"
144 name = "crossbeam-channel"
133 version = "0.4.4"
145 version = "0.4.4"
134 source = "registry+https://github.com/rust-lang/crates.io-index"
146 source = "registry+https://github.com/rust-lang/crates.io-index"
135 dependencies = [
147 dependencies = [
136 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
148 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
137 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
149 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
138 ]
150 ]
139
151
140 [[package]]
152 [[package]]
141 name = "crossbeam-channel"
153 name = "crossbeam-channel"
142 version = "0.5.0"
154 version = "0.5.0"
143 source = "registry+https://github.com/rust-lang/crates.io-index"
155 source = "registry+https://github.com/rust-lang/crates.io-index"
144 dependencies = [
156 dependencies = [
145 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
157 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
146 "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
158 "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
147 ]
159 ]
148
160
149 [[package]]
161 [[package]]
150 name = "crossbeam-deque"
162 name = "crossbeam-deque"
151 version = "0.8.0"
163 version = "0.8.0"
152 source = "registry+https://github.com/rust-lang/crates.io-index"
164 source = "registry+https://github.com/rust-lang/crates.io-index"
153 dependencies = [
165 dependencies = [
154 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
166 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
155 "crossbeam-epoch 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
167 "crossbeam-epoch 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
156 "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
168 "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
157 ]
169 ]
158
170
159 [[package]]
171 [[package]]
160 name = "crossbeam-epoch"
172 name = "crossbeam-epoch"
161 version = "0.9.1"
173 version = "0.9.1"
162 source = "registry+https://github.com/rust-lang/crates.io-index"
174 source = "registry+https://github.com/rust-lang/crates.io-index"
163 dependencies = [
175 dependencies = [
164 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
176 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
165 "const_fn 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
177 "const_fn 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
166 "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
178 "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
167 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
179 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
168 "memoffset 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
180 "memoffset 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
169 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
181 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
170 ]
182 ]
171
183
172 [[package]]
184 [[package]]
173 name = "crossbeam-utils"
185 name = "crossbeam-utils"
174 version = "0.7.2"
186 version = "0.7.2"
175 source = "registry+https://github.com/rust-lang/crates.io-index"
187 source = "registry+https://github.com/rust-lang/crates.io-index"
176 dependencies = [
188 dependencies = [
177 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
189 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
178 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
190 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
179 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
191 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
180 ]
192 ]
181
193
182 [[package]]
194 [[package]]
183 name = "crossbeam-utils"
195 name = "crossbeam-utils"
184 version = "0.8.1"
196 version = "0.8.1"
185 source = "registry+https://github.com/rust-lang/crates.io-index"
197 source = "registry+https://github.com/rust-lang/crates.io-index"
186 dependencies = [
198 dependencies = [
187 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
199 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
188 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
200 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
189 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
201 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
190 ]
202 ]
191
203
192 [[package]]
204 [[package]]
193 name = "ctor"
205 name = "ctor"
194 version = "0.1.16"
206 version = "0.1.16"
195 source = "registry+https://github.com/rust-lang/crates.io-index"
207 source = "registry+https://github.com/rust-lang/crates.io-index"
196 dependencies = [
208 dependencies = [
197 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
209 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
198 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
210 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
199 ]
211 ]
200
212
201 [[package]]
213 [[package]]
202 name = "derive_more"
214 name = "derive_more"
203 version = "0.99.11"
215 version = "0.99.11"
204 source = "registry+https://github.com/rust-lang/crates.io-index"
216 source = "registry+https://github.com/rust-lang/crates.io-index"
205 dependencies = [
217 dependencies = [
206 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
218 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
207 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
219 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
208 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
220 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
209 ]
221 ]
210
222
211 [[package]]
223 [[package]]
212 name = "difference"
224 name = "difference"
213 version = "2.0.0"
225 version = "2.0.0"
214 source = "registry+https://github.com/rust-lang/crates.io-index"
226 source = "registry+https://github.com/rust-lang/crates.io-index"
215
227
216 [[package]]
228 [[package]]
217 name = "either"
229 name = "either"
218 version = "1.6.1"
230 version = "1.6.1"
219 source = "registry+https://github.com/rust-lang/crates.io-index"
231 source = "registry+https://github.com/rust-lang/crates.io-index"
220
232
221 [[package]]
233 [[package]]
222 name = "env_logger"
234 name = "env_logger"
223 version = "0.7.1"
235 version = "0.7.1"
224 source = "registry+https://github.com/rust-lang/crates.io-index"
236 source = "registry+https://github.com/rust-lang/crates.io-index"
225 dependencies = [
237 dependencies = [
226 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
238 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
227 "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
239 "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
228 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
240 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
229 "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
241 "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
230 "termcolor 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
242 "termcolor 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
231 ]
243 ]
232
244
233 [[package]]
245 [[package]]
234 name = "flate2"
246 name = "flate2"
235 version = "1.0.19"
247 version = "1.0.19"
236 source = "registry+https://github.com/rust-lang/crates.io-index"
248 source = "registry+https://github.com/rust-lang/crates.io-index"
237 dependencies = [
249 dependencies = [
238 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
250 "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
239 "crc32fast 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
251 "crc32fast 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
240 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
252 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
241 "libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
253 "libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
242 "miniz_oxide 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
254 "miniz_oxide 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
243 ]
255 ]
244
256
245 [[package]]
257 [[package]]
246 name = "format-bytes"
258 name = "format-bytes"
247 version = "0.2.0"
259 version = "0.2.0"
248 source = "registry+https://github.com/rust-lang/crates.io-index"
260 source = "registry+https://github.com/rust-lang/crates.io-index"
249 dependencies = [
261 dependencies = [
250 "format-bytes-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
262 "format-bytes-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
251 "proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)",
263 "proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)",
252 ]
264 ]
253
265
254 [[package]]
266 [[package]]
255 name = "format-bytes-macros"
267 name = "format-bytes-macros"
256 version = "0.3.0"
268 version = "0.3.0"
257 source = "registry+https://github.com/rust-lang/crates.io-index"
269 source = "registry+https://github.com/rust-lang/crates.io-index"
258 dependencies = [
270 dependencies = [
259 "proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)",
271 "proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)",
260 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
272 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
261 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
273 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
262 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
274 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
263 ]
275 ]
264
276
265 [[package]]
277 [[package]]
266 name = "fuchsia-cprng"
278 name = "fuchsia-cprng"
267 version = "0.1.1"
279 version = "0.1.1"
268 source = "registry+https://github.com/rust-lang/crates.io-index"
280 source = "registry+https://github.com/rust-lang/crates.io-index"
269
281
270 [[package]]
282 [[package]]
271 name = "gcc"
283 name = "gcc"
272 version = "0.3.55"
284 version = "0.3.55"
273 source = "registry+https://github.com/rust-lang/crates.io-index"
285 source = "registry+https://github.com/rust-lang/crates.io-index"
274
286
275 [[package]]
287 [[package]]
276 name = "getrandom"
288 name = "getrandom"
277 version = "0.1.15"
289 version = "0.1.15"
278 source = "registry+https://github.com/rust-lang/crates.io-index"
290 source = "registry+https://github.com/rust-lang/crates.io-index"
279 dependencies = [
291 dependencies = [
280 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
292 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
281 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
293 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
282 "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
294 "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
283 ]
295 ]
284
296
285 [[package]]
297 [[package]]
286 name = "glob"
298 name = "glob"
287 version = "0.3.0"
299 version = "0.3.0"
288 source = "registry+https://github.com/rust-lang/crates.io-index"
300 source = "registry+https://github.com/rust-lang/crates.io-index"
289
301
290 [[package]]
302 [[package]]
291 name = "hermit-abi"
303 name = "hermit-abi"
292 version = "0.1.17"
304 version = "0.1.17"
293 source = "registry+https://github.com/rust-lang/crates.io-index"
305 source = "registry+https://github.com/rust-lang/crates.io-index"
294 dependencies = [
306 dependencies = [
295 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
307 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
296 ]
308 ]
297
309
298 [[package]]
310 [[package]]
299 name = "hg-core"
311 name = "hg-core"
300 version = "0.1.0"
312 version = "0.1.0"
301 dependencies = [
313 dependencies = [
302 "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
314 "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
303 "bytes-cast 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
315 "bytes-cast 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
304 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
316 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
305 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
317 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
306 "derive_more 0.99.11 (registry+https://github.com/rust-lang/crates.io-index)",
318 "derive_more 0.99.11 (registry+https://github.com/rust-lang/crates.io-index)",
307 "flate2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
319 "flate2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
308 "format-bytes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
320 "format-bytes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
309 "home 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
321 "home 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
310 "im-rc 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
322 "im-rc 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
311 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
323 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
312 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
324 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
313 "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
325 "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
314 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
326 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
315 "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
327 "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
316 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
328 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
317 "rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
329 "rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
318 "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
330 "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
319 "rayon 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
331 "rayon 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
320 "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
332 "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
321 "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
333 "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
322 "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
334 "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
323 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
335 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
324 "twox-hash 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
336 "twox-hash 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
325 "zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
337 "zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
326 ]
338 ]
327
339
328 [[package]]
340 [[package]]
329 name = "hg-cpython"
341 name = "hg-cpython"
330 version = "0.1.0"
342 version = "0.1.0"
331 dependencies = [
343 dependencies = [
332 "cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
344 "cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
333 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
345 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
334 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
346 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
335 "hg-core 0.1.0",
347 "hg-core 0.1.0",
336 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
348 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
337 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
349 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
338 ]
350 ]
339
351
340 [[package]]
352 [[package]]
341 name = "home"
353 name = "home"
342 version = "0.5.3"
354 version = "0.5.3"
343 source = "registry+https://github.com/rust-lang/crates.io-index"
355 source = "registry+https://github.com/rust-lang/crates.io-index"
344 dependencies = [
356 dependencies = [
345 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
357 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
346 ]
358 ]
347
359
348 [[package]]
360 [[package]]
349 name = "humantime"
361 name = "humantime"
350 version = "1.3.0"
362 version = "1.3.0"
351 source = "registry+https://github.com/rust-lang/crates.io-index"
363 source = "registry+https://github.com/rust-lang/crates.io-index"
352 dependencies = [
364 dependencies = [
353 "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
365 "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
354 ]
366 ]
355
367
356 [[package]]
368 [[package]]
357 name = "im-rc"
369 name = "im-rc"
358 version = "15.0.0"
370 version = "15.0.0"
359 source = "registry+https://github.com/rust-lang/crates.io-index"
371 source = "registry+https://github.com/rust-lang/crates.io-index"
360 dependencies = [
372 dependencies = [
361 "bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
373 "bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
362 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
374 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
363 "rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
375 "rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
364 "sized-chunks 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
376 "sized-chunks 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
365 "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
377 "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
366 "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
378 "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
367 ]
379 ]
368
380
369 [[package]]
381 [[package]]
370 name = "itertools"
382 name = "itertools"
371 version = "0.9.0"
383 version = "0.9.0"
372 source = "registry+https://github.com/rust-lang/crates.io-index"
384 source = "registry+https://github.com/rust-lang/crates.io-index"
373 dependencies = [
385 dependencies = [
374 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
386 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
375 ]
387 ]
376
388
377 [[package]]
389 [[package]]
378 name = "jobserver"
390 name = "jobserver"
379 version = "0.1.21"
391 version = "0.1.21"
380 source = "registry+https://github.com/rust-lang/crates.io-index"
392 source = "registry+https://github.com/rust-lang/crates.io-index"
381 dependencies = [
393 dependencies = [
382 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
394 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
383 ]
395 ]
384
396
385 [[package]]
397 [[package]]
386 name = "lazy_static"
398 name = "lazy_static"
387 version = "1.4.0"
399 version = "1.4.0"
388 source = "registry+https://github.com/rust-lang/crates.io-index"
400 source = "registry+https://github.com/rust-lang/crates.io-index"
389
401
390 [[package]]
402 [[package]]
391 name = "libc"
403 name = "libc"
392 version = "0.2.81"
404 version = "0.2.81"
393 source = "registry+https://github.com/rust-lang/crates.io-index"
405 source = "registry+https://github.com/rust-lang/crates.io-index"
394
406
395 [[package]]
407 [[package]]
396 name = "libz-sys"
408 name = "libz-sys"
397 version = "1.1.2"
409 version = "1.1.2"
398 source = "registry+https://github.com/rust-lang/crates.io-index"
410 source = "registry+https://github.com/rust-lang/crates.io-index"
399 dependencies = [
411 dependencies = [
400 "cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
412 "cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
401 "pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
413 "pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
402 "vcpkg 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
414 "vcpkg 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
403 ]
415 ]
404
416
405 [[package]]
417 [[package]]
406 name = "log"
418 name = "log"
407 version = "0.4.11"
419 version = "0.4.11"
408 source = "registry+https://github.com/rust-lang/crates.io-index"
420 source = "registry+https://github.com/rust-lang/crates.io-index"
409 dependencies = [
421 dependencies = [
410 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
422 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
411 ]
423 ]
412
424
413 [[package]]
425 [[package]]
414 name = "maybe-uninit"
426 name = "maybe-uninit"
415 version = "2.0.0"
427 version = "2.0.0"
416 source = "registry+https://github.com/rust-lang/crates.io-index"
428 source = "registry+https://github.com/rust-lang/crates.io-index"
417
429
418 [[package]]
430 [[package]]
419 name = "memchr"
431 name = "memchr"
420 version = "2.3.4"
432 version = "2.3.4"
421 source = "registry+https://github.com/rust-lang/crates.io-index"
433 source = "registry+https://github.com/rust-lang/crates.io-index"
422
434
423 [[package]]
435 [[package]]
424 name = "memmap"
436 name = "memmap"
425 version = "0.7.0"
437 version = "0.7.0"
426 source = "registry+https://github.com/rust-lang/crates.io-index"
438 source = "registry+https://github.com/rust-lang/crates.io-index"
427 dependencies = [
439 dependencies = [
428 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
440 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
429 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
441 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
430 ]
442 ]
431
443
432 [[package]]
444 [[package]]
433 name = "memoffset"
445 name = "memoffset"
434 version = "0.6.1"
446 version = "0.6.1"
435 source = "registry+https://github.com/rust-lang/crates.io-index"
447 source = "registry+https://github.com/rust-lang/crates.io-index"
436 dependencies = [
448 dependencies = [
437 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
449 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
438 ]
450 ]
439
451
440 [[package]]
452 [[package]]
441 name = "micro-timer"
453 name = "micro-timer"
442 version = "0.3.1"
454 version = "0.3.1"
443 source = "registry+https://github.com/rust-lang/crates.io-index"
455 source = "registry+https://github.com/rust-lang/crates.io-index"
444 dependencies = [
456 dependencies = [
445 "micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
457 "micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
446 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
458 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
447 ]
459 ]
448
460
449 [[package]]
461 [[package]]
450 name = "micro-timer-macros"
462 name = "micro-timer-macros"
451 version = "0.3.1"
463 version = "0.3.1"
452 source = "registry+https://github.com/rust-lang/crates.io-index"
464 source = "registry+https://github.com/rust-lang/crates.io-index"
453 dependencies = [
465 dependencies = [
454 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
466 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
455 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
467 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
456 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
468 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
457 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
469 "syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
458 ]
470 ]
459
471
460 [[package]]
472 [[package]]
461 name = "miniz_oxide"
473 name = "miniz_oxide"
462 version = "0.4.3"
474 version = "0.4.3"
463 source = "registry+https://github.com/rust-lang/crates.io-index"
475 source = "registry+https://github.com/rust-lang/crates.io-index"
464 dependencies = [
476 dependencies = [
465 "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
477 "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
466 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
478 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
467 ]
479 ]
468
480
469 [[package]]
481 [[package]]
482 name = "num-integer"
483 version = "0.1.44"
484 source = "registry+https://github.com/rust-lang/crates.io-index"
485 dependencies = [
486 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
487 "num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
488 ]
489
490 [[package]]
470 name = "num-traits"
491 name = "num-traits"
471 version = "0.2.14"
492 version = "0.2.14"
472 source = "registry+https://github.com/rust-lang/crates.io-index"
493 source = "registry+https://github.com/rust-lang/crates.io-index"
473 dependencies = [
494 dependencies = [
474 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
495 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
475 ]
496 ]
476
497
477 [[package]]
498 [[package]]
478 name = "num_cpus"
499 name = "num_cpus"
479 version = "1.13.0"
500 version = "1.13.0"
480 source = "registry+https://github.com/rust-lang/crates.io-index"
501 source = "registry+https://github.com/rust-lang/crates.io-index"
481 dependencies = [
502 dependencies = [
482 "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
503 "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
483 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
504 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
484 ]
505 ]
485
506
486 [[package]]
507 [[package]]
487 name = "output_vt100"
508 name = "output_vt100"
488 version = "0.1.2"
509 version = "0.1.2"
489 source = "registry+https://github.com/rust-lang/crates.io-index"
510 source = "registry+https://github.com/rust-lang/crates.io-index"
490 dependencies = [
511 dependencies = [
491 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
512 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
492 ]
513 ]
493
514
494 [[package]]
515 [[package]]
495 name = "pkg-config"
516 name = "pkg-config"
496 version = "0.3.19"
517 version = "0.3.19"
497 source = "registry+https://github.com/rust-lang/crates.io-index"
518 source = "registry+https://github.com/rust-lang/crates.io-index"
498
519
499 [[package]]
520 [[package]]
500 name = "ppv-lite86"
521 name = "ppv-lite86"
501 version = "0.2.10"
522 version = "0.2.10"
502 source = "registry+https://github.com/rust-lang/crates.io-index"
523 source = "registry+https://github.com/rust-lang/crates.io-index"
503
524
504 [[package]]
525 [[package]]
505 name = "pretty_assertions"
526 name = "pretty_assertions"
506 version = "0.6.1"
527 version = "0.6.1"
507 source = "registry+https://github.com/rust-lang/crates.io-index"
528 source = "registry+https://github.com/rust-lang/crates.io-index"
508 dependencies = [
529 dependencies = [
509 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
530 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
510 "ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
531 "ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
511 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
532 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
512 "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
533 "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
513 ]
534 ]
514
535
515 [[package]]
536 [[package]]
516 name = "proc-macro-hack"
537 name = "proc-macro-hack"
517 version = "0.5.19"
538 version = "0.5.19"
518 source = "registry+https://github.com/rust-lang/crates.io-index"
539 source = "registry+https://github.com/rust-lang/crates.io-index"
519
540
520 [[package]]
541 [[package]]
521 name = "proc-macro2"
542 name = "proc-macro2"
522 version = "1.0.24"
543 version = "1.0.24"
523 source = "registry+https://github.com/rust-lang/crates.io-index"
544 source = "registry+https://github.com/rust-lang/crates.io-index"
524 dependencies = [
545 dependencies = [
525 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
546 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
526 ]
547 ]
527
548
528 [[package]]
549 [[package]]
529 name = "python27-sys"
550 name = "python27-sys"
530 version = "0.4.1"
551 version = "0.4.1"
531 source = "registry+https://github.com/rust-lang/crates.io-index"
552 source = "registry+https://github.com/rust-lang/crates.io-index"
532 dependencies = [
553 dependencies = [
533 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
554 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
534 "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
555 "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
535 ]
556 ]
536
557
537 [[package]]
558 [[package]]
538 name = "python3-sys"
559 name = "python3-sys"
539 version = "0.4.1"
560 version = "0.4.1"
540 source = "registry+https://github.com/rust-lang/crates.io-index"
561 source = "registry+https://github.com/rust-lang/crates.io-index"
541 dependencies = [
562 dependencies = [
542 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
563 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
543 "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
564 "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
544 ]
565 ]
545
566
546 [[package]]
567 [[package]]
547 name = "quick-error"
568 name = "quick-error"
548 version = "1.2.3"
569 version = "1.2.3"
549 source = "registry+https://github.com/rust-lang/crates.io-index"
570 source = "registry+https://github.com/rust-lang/crates.io-index"
550
571
551 [[package]]
572 [[package]]
552 name = "quote"
573 name = "quote"
553 version = "1.0.7"
574 version = "1.0.7"
554 source = "registry+https://github.com/rust-lang/crates.io-index"
575 source = "registry+https://github.com/rust-lang/crates.io-index"
555 dependencies = [
576 dependencies = [
556 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
577 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
557 ]
578 ]
558
579
559 [[package]]
580 [[package]]
560 name = "rand"
581 name = "rand"
561 version = "0.3.23"
582 version = "0.3.23"
562 source = "registry+https://github.com/rust-lang/crates.io-index"
583 source = "registry+https://github.com/rust-lang/crates.io-index"
563 dependencies = [
584 dependencies = [
564 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
585 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
565 "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
586 "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
566 ]
587 ]
567
588
568 [[package]]
589 [[package]]
569 name = "rand"
590 name = "rand"
570 version = "0.4.6"
591 version = "0.4.6"
571 source = "registry+https://github.com/rust-lang/crates.io-index"
592 source = "registry+https://github.com/rust-lang/crates.io-index"
572 dependencies = [
593 dependencies = [
573 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
594 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
574 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
595 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
575 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
596 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
576 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
597 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
577 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
598 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
578 ]
599 ]
579
600
580 [[package]]
601 [[package]]
581 name = "rand"
602 name = "rand"
582 version = "0.7.3"
603 version = "0.7.3"
583 source = "registry+https://github.com/rust-lang/crates.io-index"
604 source = "registry+https://github.com/rust-lang/crates.io-index"
584 dependencies = [
605 dependencies = [
585 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
606 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
586 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
607 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
587 "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
608 "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
588 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
609 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
589 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
610 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
590 ]
611 ]
591
612
592 [[package]]
613 [[package]]
593 name = "rand_chacha"
614 name = "rand_chacha"
594 version = "0.2.2"
615 version = "0.2.2"
595 source = "registry+https://github.com/rust-lang/crates.io-index"
616 source = "registry+https://github.com/rust-lang/crates.io-index"
596 dependencies = [
617 dependencies = [
597 "ppv-lite86 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
618 "ppv-lite86 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
598 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
619 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
599 ]
620 ]
600
621
601 [[package]]
622 [[package]]
602 name = "rand_core"
623 name = "rand_core"
603 version = "0.3.1"
624 version = "0.3.1"
604 source = "registry+https://github.com/rust-lang/crates.io-index"
625 source = "registry+https://github.com/rust-lang/crates.io-index"
605 dependencies = [
626 dependencies = [
606 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
627 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
607 ]
628 ]
608
629
609 [[package]]
630 [[package]]
610 name = "rand_core"
631 name = "rand_core"
611 version = "0.4.2"
632 version = "0.4.2"
612 source = "registry+https://github.com/rust-lang/crates.io-index"
633 source = "registry+https://github.com/rust-lang/crates.io-index"
613
634
614 [[package]]
635 [[package]]
615 name = "rand_core"
636 name = "rand_core"
616 version = "0.5.1"
637 version = "0.5.1"
617 source = "registry+https://github.com/rust-lang/crates.io-index"
638 source = "registry+https://github.com/rust-lang/crates.io-index"
618 dependencies = [
639 dependencies = [
619 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
640 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
620 ]
641 ]
621
642
622 [[package]]
643 [[package]]
623 name = "rand_distr"
644 name = "rand_distr"
624 version = "0.2.2"
645 version = "0.2.2"
625 source = "registry+https://github.com/rust-lang/crates.io-index"
646 source = "registry+https://github.com/rust-lang/crates.io-index"
626 dependencies = [
647 dependencies = [
627 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
648 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
628 ]
649 ]
629
650
630 [[package]]
651 [[package]]
631 name = "rand_hc"
652 name = "rand_hc"
632 version = "0.2.0"
653 version = "0.2.0"
633 source = "registry+https://github.com/rust-lang/crates.io-index"
654 source = "registry+https://github.com/rust-lang/crates.io-index"
634 dependencies = [
655 dependencies = [
635 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
656 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
636 ]
657 ]
637
658
638 [[package]]
659 [[package]]
639 name = "rand_pcg"
660 name = "rand_pcg"
640 version = "0.2.1"
661 version = "0.2.1"
641 source = "registry+https://github.com/rust-lang/crates.io-index"
662 source = "registry+https://github.com/rust-lang/crates.io-index"
642 dependencies = [
663 dependencies = [
643 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
664 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
644 ]
665 ]
645
666
646 [[package]]
667 [[package]]
647 name = "rand_xoshiro"
668 name = "rand_xoshiro"
648 version = "0.4.0"
669 version = "0.4.0"
649 source = "registry+https://github.com/rust-lang/crates.io-index"
670 source = "registry+https://github.com/rust-lang/crates.io-index"
650 dependencies = [
671 dependencies = [
651 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
672 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
652 ]
673 ]
653
674
654 [[package]]
675 [[package]]
655 name = "rayon"
676 name = "rayon"
656 version = "1.5.0"
677 version = "1.5.0"
657 source = "registry+https://github.com/rust-lang/crates.io-index"
678 source = "registry+https://github.com/rust-lang/crates.io-index"
658 dependencies = [
679 dependencies = [
659 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
680 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
660 "crossbeam-deque 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
681 "crossbeam-deque 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
661 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
682 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
662 "rayon-core 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
683 "rayon-core 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
663 ]
684 ]
664
685
665 [[package]]
686 [[package]]
666 name = "rayon-core"
687 name = "rayon-core"
667 version = "1.9.0"
688 version = "1.9.0"
668 source = "registry+https://github.com/rust-lang/crates.io-index"
689 source = "registry+https://github.com/rust-lang/crates.io-index"
669 dependencies = [
690 dependencies = [
670 "crossbeam-channel 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
691 "crossbeam-channel 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
671 "crossbeam-deque 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
692 "crossbeam-deque 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
672 "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
693 "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
673 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
694 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
674 "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
695 "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
675 ]
696 ]
676
697
677 [[package]]
698 [[package]]
678 name = "rdrand"
699 name = "rdrand"
679 version = "0.4.0"
700 version = "0.4.0"
680 source = "registry+https://github.com/rust-lang/crates.io-index"
701 source = "registry+https://github.com/rust-lang/crates.io-index"
681 dependencies = [
702 dependencies = [
682 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
703 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
683 ]
704 ]
684
705
685 [[package]]
706 [[package]]
686 name = "redox_syscall"
707 name = "redox_syscall"
687 version = "0.1.57"
708 version = "0.1.57"
688 source = "registry+https://github.com/rust-lang/crates.io-index"
709 source = "registry+https://github.com/rust-lang/crates.io-index"
689
710
690 [[package]]
711 [[package]]
691 name = "regex"
712 name = "regex"
692 version = "1.4.2"
713 version = "1.4.2"
693 source = "registry+https://github.com/rust-lang/crates.io-index"
714 source = "registry+https://github.com/rust-lang/crates.io-index"
694 dependencies = [
715 dependencies = [
695 "aho-corasick 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)",
716 "aho-corasick 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)",
696 "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
717 "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
697 "regex-syntax 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
718 "regex-syntax 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
698 "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
719 "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
699 ]
720 ]
700
721
701 [[package]]
722 [[package]]
702 name = "regex-syntax"
723 name = "regex-syntax"
703 version = "0.6.21"
724 version = "0.6.21"
704 source = "registry+https://github.com/rust-lang/crates.io-index"
725 source = "registry+https://github.com/rust-lang/crates.io-index"
705
726
706 [[package]]
727 [[package]]
707 name = "remove_dir_all"
728 name = "remove_dir_all"
708 version = "0.5.3"
729 version = "0.5.3"
709 source = "registry+https://github.com/rust-lang/crates.io-index"
730 source = "registry+https://github.com/rust-lang/crates.io-index"
710 dependencies = [
731 dependencies = [
711 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
732 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
712 ]
733 ]
713
734
714 [[package]]
735 [[package]]
715 name = "rhg"
736 name = "rhg"
716 version = "0.1.0"
737 version = "0.1.0"
717 dependencies = [
738 dependencies = [
739 "chrono 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
718 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
740 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
719 "derive_more 0.99.11 (registry+https://github.com/rust-lang/crates.io-index)",
741 "derive_more 0.99.11 (registry+https://github.com/rust-lang/crates.io-index)",
720 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
742 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
721 "format-bytes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
743 "format-bytes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
722 "hg-core 0.1.0",
744 "hg-core 0.1.0",
723 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
745 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
724 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
746 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
747 "users 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
725 ]
748 ]
726
749
727 [[package]]
750 [[package]]
728 name = "rust-crypto"
751 name = "rust-crypto"
729 version = "0.2.36"
752 version = "0.2.36"
730 source = "registry+https://github.com/rust-lang/crates.io-index"
753 source = "registry+https://github.com/rust-lang/crates.io-index"
731 dependencies = [
754 dependencies = [
732 "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)",
755 "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)",
733 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
756 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
734 "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
757 "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
735 "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
758 "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
736 "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
759 "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
737 ]
760 ]
738
761
739 [[package]]
762 [[package]]
740 name = "rustc-serialize"
763 name = "rustc-serialize"
741 version = "0.3.24"
764 version = "0.3.24"
742 source = "registry+https://github.com/rust-lang/crates.io-index"
765 source = "registry+https://github.com/rust-lang/crates.io-index"
743
766
744 [[package]]
767 [[package]]
745 name = "same-file"
768 name = "same-file"
746 version = "1.0.6"
769 version = "1.0.6"
747 source = "registry+https://github.com/rust-lang/crates.io-index"
770 source = "registry+https://github.com/rust-lang/crates.io-index"
748 dependencies = [
771 dependencies = [
749 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
772 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
750 ]
773 ]
751
774
752 [[package]]
775 [[package]]
753 name = "scopeguard"
776 name = "scopeguard"
754 version = "1.1.0"
777 version = "1.1.0"
755 source = "registry+https://github.com/rust-lang/crates.io-index"
778 source = "registry+https://github.com/rust-lang/crates.io-index"
756
779
757 [[package]]
780 [[package]]
758 name = "sized-chunks"
781 name = "sized-chunks"
759 version = "0.6.2"
782 version = "0.6.2"
760 source = "registry+https://github.com/rust-lang/crates.io-index"
783 source = "registry+https://github.com/rust-lang/crates.io-index"
761 dependencies = [
784 dependencies = [
762 "bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
785 "bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
763 "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
786 "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
764 ]
787 ]
765
788
766 [[package]]
789 [[package]]
767 name = "static_assertions"
790 name = "static_assertions"
768 version = "1.1.0"
791 version = "1.1.0"
769 source = "registry+https://github.com/rust-lang/crates.io-index"
792 source = "registry+https://github.com/rust-lang/crates.io-index"
770
793
771 [[package]]
794 [[package]]
772 name = "strsim"
795 name = "strsim"
773 version = "0.8.0"
796 version = "0.8.0"
774 source = "registry+https://github.com/rust-lang/crates.io-index"
797 source = "registry+https://github.com/rust-lang/crates.io-index"
775
798
776 [[package]]
799 [[package]]
777 name = "syn"
800 name = "syn"
778 version = "1.0.54"
801 version = "1.0.54"
779 source = "registry+https://github.com/rust-lang/crates.io-index"
802 source = "registry+https://github.com/rust-lang/crates.io-index"
780 dependencies = [
803 dependencies = [
781 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
804 "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
782 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
805 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
783 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
806 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
784 ]
807 ]
785
808
786 [[package]]
809 [[package]]
787 name = "tempfile"
810 name = "tempfile"
788 version = "3.1.0"
811 version = "3.1.0"
789 source = "registry+https://github.com/rust-lang/crates.io-index"
812 source = "registry+https://github.com/rust-lang/crates.io-index"
790 dependencies = [
813 dependencies = [
791 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
814 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
792 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
815 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
793 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
816 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
794 "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
817 "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
795 "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
818 "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
796 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
819 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
797 ]
820 ]
798
821
799 [[package]]
822 [[package]]
800 name = "termcolor"
823 name = "termcolor"
801 version = "1.1.2"
824 version = "1.1.2"
802 source = "registry+https://github.com/rust-lang/crates.io-index"
825 source = "registry+https://github.com/rust-lang/crates.io-index"
803 dependencies = [
826 dependencies = [
804 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
827 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
805 ]
828 ]
806
829
807 [[package]]
830 [[package]]
808 name = "textwrap"
831 name = "textwrap"
809 version = "0.11.0"
832 version = "0.11.0"
810 source = "registry+https://github.com/rust-lang/crates.io-index"
833 source = "registry+https://github.com/rust-lang/crates.io-index"
811 dependencies = [
834 dependencies = [
812 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
835 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
813 ]
836 ]
814
837
815 [[package]]
838 [[package]]
816 name = "thread_local"
839 name = "thread_local"
817 version = "1.0.1"
840 version = "1.0.1"
818 source = "registry+https://github.com/rust-lang/crates.io-index"
841 source = "registry+https://github.com/rust-lang/crates.io-index"
819 dependencies = [
842 dependencies = [
820 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
843 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
821 ]
844 ]
822
845
823 [[package]]
846 [[package]]
824 name = "time"
847 name = "time"
825 version = "0.1.44"
848 version = "0.1.44"
826 source = "registry+https://github.com/rust-lang/crates.io-index"
849 source = "registry+https://github.com/rust-lang/crates.io-index"
827 dependencies = [
850 dependencies = [
828 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
851 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
829 "wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
852 "wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
830 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
853 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
831 ]
854 ]
832
855
833 [[package]]
856 [[package]]
834 name = "twox-hash"
857 name = "twox-hash"
835 version = "1.6.0"
858 version = "1.6.0"
836 source = "registry+https://github.com/rust-lang/crates.io-index"
859 source = "registry+https://github.com/rust-lang/crates.io-index"
837 dependencies = [
860 dependencies = [
838 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
861 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
839 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
862 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
840 "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
863 "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
841 ]
864 ]
842
865
843 [[package]]
866 [[package]]
844 name = "typenum"
867 name = "typenum"
845 version = "1.12.0"
868 version = "1.12.0"
846 source = "registry+https://github.com/rust-lang/crates.io-index"
869 source = "registry+https://github.com/rust-lang/crates.io-index"
847
870
848 [[package]]
871 [[package]]
849 name = "unicode-width"
872 name = "unicode-width"
850 version = "0.1.8"
873 version = "0.1.8"
851 source = "registry+https://github.com/rust-lang/crates.io-index"
874 source = "registry+https://github.com/rust-lang/crates.io-index"
852
875
853 [[package]]
876 [[package]]
854 name = "unicode-xid"
877 name = "unicode-xid"
855 version = "0.2.1"
878 version = "0.2.1"
856 source = "registry+https://github.com/rust-lang/crates.io-index"
879 source = "registry+https://github.com/rust-lang/crates.io-index"
857
880
858 [[package]]
881 [[package]]
882 name = "users"
883 version = "0.11.0"
884 source = "registry+https://github.com/rust-lang/crates.io-index"
885 dependencies = [
886 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
887 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
888 ]
889
890 [[package]]
859 name = "vcpkg"
891 name = "vcpkg"
860 version = "0.2.11"
892 version = "0.2.11"
861 source = "registry+https://github.com/rust-lang/crates.io-index"
893 source = "registry+https://github.com/rust-lang/crates.io-index"
862
894
863 [[package]]
895 [[package]]
864 name = "vec_map"
896 name = "vec_map"
865 version = "0.8.2"
897 version = "0.8.2"
866 source = "registry+https://github.com/rust-lang/crates.io-index"
898 source = "registry+https://github.com/rust-lang/crates.io-index"
867
899
868 [[package]]
900 [[package]]
869 name = "version_check"
901 name = "version_check"
870 version = "0.9.2"
902 version = "0.9.2"
871 source = "registry+https://github.com/rust-lang/crates.io-index"
903 source = "registry+https://github.com/rust-lang/crates.io-index"
872
904
873 [[package]]
905 [[package]]
874 name = "wasi"
906 name = "wasi"
875 version = "0.9.0+wasi-snapshot-preview1"
907 version = "0.9.0+wasi-snapshot-preview1"
876 source = "registry+https://github.com/rust-lang/crates.io-index"
908 source = "registry+https://github.com/rust-lang/crates.io-index"
877
909
878 [[package]]
910 [[package]]
879 name = "wasi"
911 name = "wasi"
880 version = "0.10.0+wasi-snapshot-preview1"
912 version = "0.10.0+wasi-snapshot-preview1"
881 source = "registry+https://github.com/rust-lang/crates.io-index"
913 source = "registry+https://github.com/rust-lang/crates.io-index"
882
914
883 [[package]]
915 [[package]]
884 name = "winapi"
916 name = "winapi"
885 version = "0.3.9"
917 version = "0.3.9"
886 source = "registry+https://github.com/rust-lang/crates.io-index"
918 source = "registry+https://github.com/rust-lang/crates.io-index"
887 dependencies = [
919 dependencies = [
888 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
920 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
889 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
921 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
890 ]
922 ]
891
923
892 [[package]]
924 [[package]]
893 name = "winapi-i686-pc-windows-gnu"
925 name = "winapi-i686-pc-windows-gnu"
894 version = "0.4.0"
926 version = "0.4.0"
895 source = "registry+https://github.com/rust-lang/crates.io-index"
927 source = "registry+https://github.com/rust-lang/crates.io-index"
896
928
897 [[package]]
929 [[package]]
898 name = "winapi-util"
930 name = "winapi-util"
899 version = "0.1.5"
931 version = "0.1.5"
900 source = "registry+https://github.com/rust-lang/crates.io-index"
932 source = "registry+https://github.com/rust-lang/crates.io-index"
901 dependencies = [
933 dependencies = [
902 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
934 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
903 ]
935 ]
904
936
905 [[package]]
937 [[package]]
906 name = "winapi-x86_64-pc-windows-gnu"
938 name = "winapi-x86_64-pc-windows-gnu"
907 version = "0.4.0"
939 version = "0.4.0"
908 source = "registry+https://github.com/rust-lang/crates.io-index"
940 source = "registry+https://github.com/rust-lang/crates.io-index"
909
941
910 [[package]]
942 [[package]]
911 name = "zstd"
943 name = "zstd"
912 version = "0.5.3+zstd.1.4.5"
944 version = "0.5.3+zstd.1.4.5"
913 source = "registry+https://github.com/rust-lang/crates.io-index"
945 source = "registry+https://github.com/rust-lang/crates.io-index"
914 dependencies = [
946 dependencies = [
915 "zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
947 "zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
916 ]
948 ]
917
949
918 [[package]]
950 [[package]]
919 name = "zstd-safe"
951 name = "zstd-safe"
920 version = "2.0.5+zstd.1.4.5"
952 version = "2.0.5+zstd.1.4.5"
921 source = "registry+https://github.com/rust-lang/crates.io-index"
953 source = "registry+https://github.com/rust-lang/crates.io-index"
922 dependencies = [
954 dependencies = [
923 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
955 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
924 "zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
956 "zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
925 ]
957 ]
926
958
927 [[package]]
959 [[package]]
928 name = "zstd-sys"
960 name = "zstd-sys"
929 version = "1.4.17+zstd.1.4.5"
961 version = "1.4.17+zstd.1.4.5"
930 source = "registry+https://github.com/rust-lang/crates.io-index"
962 source = "registry+https://github.com/rust-lang/crates.io-index"
931 dependencies = [
963 dependencies = [
932 "cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
964 "cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
933 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
965 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
934 "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
966 "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
935 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
967 "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
936 ]
968 ]
937
969
938 [metadata]
970 [metadata]
939 "checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
971 "checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
940 "checksum aho-corasick 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
972 "checksum aho-corasick 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
941 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
973 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
942 "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
974 "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
943 "checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
975 "checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
944 "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
976 "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
945 "checksum bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
977 "checksum bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
946 "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
978 "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
947 "checksum bytes-cast 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3196ba300c7bc9282a4331e878496cb3e9603a898a8f1446601317163e16ca52"
979 "checksum bytes-cast 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3196ba300c7bc9282a4331e878496cb3e9603a898a8f1446601317163e16ca52"
948 "checksum bytes-cast-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb936af9de38476664d6b58e529aff30d482e4ce1c5e150293d00730b0d81fdb"
980 "checksum bytes-cast-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb936af9de38476664d6b58e529aff30d482e4ce1c5e150293d00730b0d81fdb"
949 "checksum cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
981 "checksum cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
950 "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
982 "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
951 "checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
983 "checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
984 "checksum chrono 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
952 "checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
985 "checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
953 "checksum const_fn 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826"
986 "checksum const_fn 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826"
954 "checksum cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95"
987 "checksum cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95"
955 "checksum crc32fast 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
988 "checksum crc32fast 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
956 "checksum crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
989 "checksum crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
957 "checksum crossbeam-channel 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
990 "checksum crossbeam-channel 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
958 "checksum crossbeam-deque 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
991 "checksum crossbeam-deque 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
959 "checksum crossbeam-epoch 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
992 "checksum crossbeam-epoch 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
960 "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
993 "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
961 "checksum crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
994 "checksum crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
962 "checksum ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
995 "checksum ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
963 "checksum derive_more 0.99.11 (registry+https://github.com/rust-lang/crates.io-index)" = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
996 "checksum derive_more 0.99.11 (registry+https://github.com/rust-lang/crates.io-index)" = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
964 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
997 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
965 "checksum either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
998 "checksum either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
966 "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
999 "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
967 "checksum flate2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
1000 "checksum flate2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
968 "checksum format-bytes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc35f5e45d6b31053cea13078ffc6fa52fa8617aa54b7ac2011720d9c009e04f"
1001 "checksum format-bytes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc35f5e45d6b31053cea13078ffc6fa52fa8617aa54b7ac2011720d9c009e04f"
969 "checksum format-bytes-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b05089e341a0460449e2210c3bf7b61597860b07f0deae58da38dbed0a4c6b6d"
1002 "checksum format-bytes-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b05089e341a0460449e2210c3bf7b61597860b07f0deae58da38dbed0a4c6b6d"
970 "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
1003 "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
971 "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
1004 "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
972 "checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
1005 "checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
973 "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
1006 "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
974 "checksum hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
1007 "checksum hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
975 "checksum home 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
1008 "checksum home 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
976 "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
1009 "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
977 "checksum im-rc 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
1010 "checksum im-rc 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
978 "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
1011 "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
979 "checksum jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
1012 "checksum jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
980 "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
1013 "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
981 "checksum libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)" = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
1014 "checksum libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)" = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
982 "checksum libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
1015 "checksum libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
983 "checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
1016 "checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
984 "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
1017 "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
985 "checksum memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
1018 "checksum memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
986 "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
1019 "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
987 "checksum memoffset 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
1020 "checksum memoffset 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
988 "checksum micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2620153e1d903d26b72b89f0e9c48d8c4756cba941c185461dddc234980c298c"
1021 "checksum micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2620153e1d903d26b72b89f0e9c48d8c4756cba941c185461dddc234980c298c"
989 "checksum micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e28a3473e6abd6e9aab36aaeef32ad22ae0bd34e79f376643594c2b152ec1c5d"
1022 "checksum micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e28a3473e6abd6e9aab36aaeef32ad22ae0bd34e79f376643594c2b152ec1c5d"
990 "checksum miniz_oxide 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
1023 "checksum miniz_oxide 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
1024 "checksum num-integer 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
991 "checksum num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
1025 "checksum num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
992 "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
1026 "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
993 "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
1027 "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
994 "checksum pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
1028 "checksum pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
995 "checksum ppv-lite86 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
1029 "checksum ppv-lite86 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
996 "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
1030 "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
997 "checksum proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
1031 "checksum proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
998 "checksum proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
1032 "checksum proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
999 "checksum python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c"
1033 "checksum python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c"
1000 "checksum python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4"
1034 "checksum python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4"
1001 "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
1035 "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
1002 "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
1036 "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
1003 "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
1037 "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
1004 "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
1038 "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
1005 "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
1039 "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
1006 "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
1040 "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
1007 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
1041 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
1008 "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
1042 "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
1009 "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
1043 "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
1010 "checksum rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
1044 "checksum rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
1011 "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
1045 "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
1012 "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
1046 "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
1013 "checksum rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
1047 "checksum rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
1014 "checksum rayon 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
1048 "checksum rayon 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
1015 "checksum rayon-core 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
1049 "checksum rayon-core 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
1016 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
1050 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
1017 "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
1051 "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
1018 "checksum regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
1052 "checksum regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
1019 "checksum regex-syntax 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
1053 "checksum regex-syntax 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
1020 "checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
1054 "checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
1021 "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
1055 "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
1022 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
1056 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
1023 "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1057 "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1024 "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
1058 "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
1025 "checksum sized-chunks 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1ec31ceca5644fa6d444cc77548b88b67f46db6f7c71683b0f9336e671830d2f"
1059 "checksum sized-chunks 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1ec31ceca5644fa6d444cc77548b88b67f46db6f7c71683b0f9336e671830d2f"
1026 "checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
1060 "checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
1027 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
1061 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
1028 "checksum syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
1062 "checksum syn 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
1029 "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
1063 "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
1030 "checksum termcolor 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
1064 "checksum termcolor 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
1031 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
1065 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
1032 "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
1066 "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
1033 "checksum time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
1067 "checksum time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
1034 "checksum twox-hash 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59"
1068 "checksum twox-hash 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59"
1035 "checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
1069 "checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
1036 "checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
1070 "checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
1037 "checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
1071 "checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
1072 "checksum users 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
1038 "checksum vcpkg 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
1073 "checksum vcpkg 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
1039 "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
1074 "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
1040 "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
1075 "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
1041 "checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1076 "checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1042 "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
1077 "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
1043 "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1078 "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1044 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1079 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1045 "checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1080 "checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1046 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1081 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1047 "checksum zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8"
1082 "checksum zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8"
1048 "checksum zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055"
1083 "checksum zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055"
1049 "checksum zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b"
1084 "checksum zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b"
@@ -1,500 +1,508 b''
1 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
1 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 use crate::errors::HgError;
6 use crate::errors::HgError;
7 use crate::utils::hg_path::HgPath;
7 use crate::utils::hg_path::HgPath;
8 use crate::{
8 use crate::{
9 dirstate::{CopyMap, EntryState, RawEntry, StateMap},
9 dirstate::{CopyMap, EntryState, RawEntry, StateMap},
10 DirstateEntry, DirstateParents,
10 DirstateEntry, DirstateParents,
11 };
11 };
12 use byteorder::{BigEndian, WriteBytesExt};
12 use byteorder::{BigEndian, WriteBytesExt};
13 use bytes_cast::BytesCast;
13 use bytes_cast::BytesCast;
14 use micro_timer::timed;
14 use micro_timer::timed;
15 use std::convert::{TryFrom, TryInto};
15 use std::convert::{TryFrom, TryInto};
16 use std::time::Duration;
16 use std::time::Duration;
17
17
18 /// Parents are stored in the dirstate as byte hashes.
18 /// Parents are stored in the dirstate as byte hashes.
19 pub const PARENT_SIZE: usize = 20;
19 pub const PARENT_SIZE: usize = 20;
20 /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits.
20 /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits.
21 const MIN_ENTRY_SIZE: usize = 17;
21 const MIN_ENTRY_SIZE: usize = 17;
22
22
23 type ParseResult<'a> = (
23 type ParseResult<'a> = (
24 &'a DirstateParents,
24 &'a DirstateParents,
25 Vec<(&'a HgPath, DirstateEntry)>,
25 Vec<(&'a HgPath, DirstateEntry)>,
26 Vec<(&'a HgPath, &'a HgPath)>,
26 Vec<(&'a HgPath, &'a HgPath)>,
27 );
27 );
28
28
29 pub fn parse_dirstate_parents(
30 contents: &[u8],
31 ) -> Result<&DirstateParents, HgError> {
32 let (parents, _rest) = DirstateParents::from_bytes(contents)
33 .map_err(|_| HgError::corrupted("Too little data for dirstate."))?;
34 Ok(parents)
35 }
36
29 #[timed]
37 #[timed]
30 pub fn parse_dirstate(mut contents: &[u8]) -> Result<ParseResult, HgError> {
38 pub fn parse_dirstate(mut contents: &[u8]) -> Result<ParseResult, HgError> {
31 let mut copies = Vec::new();
39 let mut copies = Vec::new();
32 let mut entries = Vec::new();
40 let mut entries = Vec::new();
33
41
34 let (parents, rest) = DirstateParents::from_bytes(contents)
42 let (parents, rest) = DirstateParents::from_bytes(contents)
35 .map_err(|_| HgError::corrupted("Too little data for dirstate."))?;
43 .map_err(|_| HgError::corrupted("Too little data for dirstate."))?;
36 contents = rest;
44 contents = rest;
37 while !contents.is_empty() {
45 while !contents.is_empty() {
38 let (raw_entry, rest) = RawEntry::from_bytes(contents)
46 let (raw_entry, rest) = RawEntry::from_bytes(contents)
39 .map_err(|_| HgError::corrupted("Overflow in dirstate."))?;
47 .map_err(|_| HgError::corrupted("Overflow in dirstate."))?;
40
48
41 let entry = DirstateEntry {
49 let entry = DirstateEntry {
42 state: EntryState::try_from(raw_entry.state)?,
50 state: EntryState::try_from(raw_entry.state)?,
43 mode: raw_entry.mode.get(),
51 mode: raw_entry.mode.get(),
44 mtime: raw_entry.mtime.get(),
52 mtime: raw_entry.mtime.get(),
45 size: raw_entry.size.get(),
53 size: raw_entry.size.get(),
46 };
54 };
47 let (paths, rest) =
55 let (paths, rest) =
48 u8::slice_from_bytes(rest, raw_entry.length.get() as usize)
56 u8::slice_from_bytes(rest, raw_entry.length.get() as usize)
49 .map_err(|_| HgError::corrupted("Overflow in dirstate."))?;
57 .map_err(|_| HgError::corrupted("Overflow in dirstate."))?;
50
58
51 // `paths` is either a single path, or two paths separated by a NULL
59 // `paths` is either a single path, or two paths separated by a NULL
52 // byte
60 // byte
53 let mut iter = paths.splitn(2, |&byte| byte == b'\0');
61 let mut iter = paths.splitn(2, |&byte| byte == b'\0');
54 let path = HgPath::new(
62 let path = HgPath::new(
55 iter.next().expect("splitn always yields at least one item"),
63 iter.next().expect("splitn always yields at least one item"),
56 );
64 );
57 if let Some(copy_source) = iter.next() {
65 if let Some(copy_source) = iter.next() {
58 copies.push((path, HgPath::new(copy_source)));
66 copies.push((path, HgPath::new(copy_source)));
59 }
67 }
60
68
61 entries.push((path, entry));
69 entries.push((path, entry));
62 contents = rest;
70 contents = rest;
63 }
71 }
64 Ok((parents, entries, copies))
72 Ok((parents, entries, copies))
65 }
73 }
66
74
67 /// `now` is the duration in seconds since the Unix epoch
75 /// `now` is the duration in seconds since the Unix epoch
68 #[cfg(not(feature = "dirstate-tree"))]
76 #[cfg(not(feature = "dirstate-tree"))]
69 pub fn pack_dirstate(
77 pub fn pack_dirstate(
70 state_map: &mut StateMap,
78 state_map: &mut StateMap,
71 copy_map: &CopyMap,
79 copy_map: &CopyMap,
72 parents: DirstateParents,
80 parents: DirstateParents,
73 now: Duration,
81 now: Duration,
74 ) -> Result<Vec<u8>, HgError> {
82 ) -> Result<Vec<u8>, HgError> {
75 // TODO move away from i32 before 2038.
83 // TODO move away from i32 before 2038.
76 let now: i32 = now.as_secs().try_into().expect("time overflow");
84 let now: i32 = now.as_secs().try_into().expect("time overflow");
77
85
78 let expected_size: usize = state_map
86 let expected_size: usize = state_map
79 .iter()
87 .iter()
80 .map(|(filename, _)| {
88 .map(|(filename, _)| {
81 let mut length = MIN_ENTRY_SIZE + filename.len();
89 let mut length = MIN_ENTRY_SIZE + filename.len();
82 if let Some(copy) = copy_map.get(filename) {
90 if let Some(copy) = copy_map.get(filename) {
83 length += copy.len() + 1;
91 length += copy.len() + 1;
84 }
92 }
85 length
93 length
86 })
94 })
87 .sum();
95 .sum();
88 let expected_size = expected_size + PARENT_SIZE * 2;
96 let expected_size = expected_size + PARENT_SIZE * 2;
89
97
90 let mut packed = Vec::with_capacity(expected_size);
98 let mut packed = Vec::with_capacity(expected_size);
91
99
92 packed.extend(parents.p1.as_bytes());
100 packed.extend(parents.p1.as_bytes());
93 packed.extend(parents.p2.as_bytes());
101 packed.extend(parents.p2.as_bytes());
94
102
95 for (filename, entry) in state_map.iter_mut() {
103 for (filename, entry) in state_map.iter_mut() {
96 let new_filename = filename.to_owned();
104 let new_filename = filename.to_owned();
97 let mut new_mtime: i32 = entry.mtime;
105 let mut new_mtime: i32 = entry.mtime;
98 if entry.state == EntryState::Normal && entry.mtime == now {
106 if entry.state == EntryState::Normal && entry.mtime == now {
99 // The file was last modified "simultaneously" with the current
107 // The file was last modified "simultaneously" with the current
100 // write to dirstate (i.e. within the same second for file-
108 // write to dirstate (i.e. within the same second for file-
101 // systems with a granularity of 1 sec). This commonly happens
109 // systems with a granularity of 1 sec). This commonly happens
102 // for at least a couple of files on 'update'.
110 // for at least a couple of files on 'update'.
103 // The user could change the file without changing its size
111 // The user could change the file without changing its size
104 // within the same second. Invalidate the file's mtime in
112 // within the same second. Invalidate the file's mtime in
105 // dirstate, forcing future 'status' calls to compare the
113 // dirstate, forcing future 'status' calls to compare the
106 // contents of the file if the size is the same. This prevents
114 // contents of the file if the size is the same. This prevents
107 // mistakenly treating such files as clean.
115 // mistakenly treating such files as clean.
108 new_mtime = -1;
116 new_mtime = -1;
109 *entry = DirstateEntry {
117 *entry = DirstateEntry {
110 mtime: new_mtime,
118 mtime: new_mtime,
111 ..*entry
119 ..*entry
112 };
120 };
113 }
121 }
114 let mut new_filename = new_filename.into_vec();
122 let mut new_filename = new_filename.into_vec();
115 if let Some(copy) = copy_map.get(filename) {
123 if let Some(copy) = copy_map.get(filename) {
116 new_filename.push(b'\0');
124 new_filename.push(b'\0');
117 new_filename.extend(copy.bytes());
125 new_filename.extend(copy.bytes());
118 }
126 }
119
127
120 // Unwrapping because `impl std::io::Write for Vec<u8>` never errors
128 // Unwrapping because `impl std::io::Write for Vec<u8>` never errors
121 packed.write_u8(entry.state.into()).unwrap();
129 packed.write_u8(entry.state.into()).unwrap();
122 packed.write_i32::<BigEndian>(entry.mode).unwrap();
130 packed.write_i32::<BigEndian>(entry.mode).unwrap();
123 packed.write_i32::<BigEndian>(entry.size).unwrap();
131 packed.write_i32::<BigEndian>(entry.size).unwrap();
124 packed.write_i32::<BigEndian>(new_mtime).unwrap();
132 packed.write_i32::<BigEndian>(new_mtime).unwrap();
125 packed
133 packed
126 .write_i32::<BigEndian>(new_filename.len() as i32)
134 .write_i32::<BigEndian>(new_filename.len() as i32)
127 .unwrap();
135 .unwrap();
128 packed.extend(new_filename)
136 packed.extend(new_filename)
129 }
137 }
130
138
131 if packed.len() != expected_size {
139 if packed.len() != expected_size {
132 return Err(HgError::CorruptedRepository(format!(
140 return Err(HgError::CorruptedRepository(format!(
133 "bad dirstate size: {} != {}",
141 "bad dirstate size: {} != {}",
134 expected_size,
142 expected_size,
135 packed.len()
143 packed.len()
136 )));
144 )));
137 }
145 }
138
146
139 Ok(packed)
147 Ok(packed)
140 }
148 }
141 /// `now` is the duration in seconds since the Unix epoch
149 /// `now` is the duration in seconds since the Unix epoch
142 #[cfg(feature = "dirstate-tree")]
150 #[cfg(feature = "dirstate-tree")]
143 pub fn pack_dirstate(
151 pub fn pack_dirstate(
144 state_map: &mut StateMap,
152 state_map: &mut StateMap,
145 copy_map: &CopyMap,
153 copy_map: &CopyMap,
146 parents: DirstateParents,
154 parents: DirstateParents,
147 now: Duration,
155 now: Duration,
148 ) -> Result<Vec<u8>, DirstatePackError> {
156 ) -> Result<Vec<u8>, DirstatePackError> {
149 // TODO move away from i32 before 2038.
157 // TODO move away from i32 before 2038.
150 let now: i32 = now.as_secs().try_into().expect("time overflow");
158 let now: i32 = now.as_secs().try_into().expect("time overflow");
151
159
152 let expected_size: usize = state_map
160 let expected_size: usize = state_map
153 .iter()
161 .iter()
154 .map(|(filename, _)| {
162 .map(|(filename, _)| {
155 let mut length = MIN_ENTRY_SIZE + filename.len();
163 let mut length = MIN_ENTRY_SIZE + filename.len();
156 if let Some(copy) = copy_map.get(&filename) {
164 if let Some(copy) = copy_map.get(&filename) {
157 length += copy.len() + 1;
165 length += copy.len() + 1;
158 }
166 }
159 length
167 length
160 })
168 })
161 .sum();
169 .sum();
162 let expected_size = expected_size + PARENT_SIZE * 2;
170 let expected_size = expected_size + PARENT_SIZE * 2;
163
171
164 let mut packed = Vec::with_capacity(expected_size);
172 let mut packed = Vec::with_capacity(expected_size);
165 let mut new_state_map = vec![];
173 let mut new_state_map = vec![];
166
174
167 packed.extend(&parents.p1);
175 packed.extend(&parents.p1);
168 packed.extend(&parents.p2);
176 packed.extend(&parents.p2);
169
177
170 for (filename, entry) in state_map.iter() {
178 for (filename, entry) in state_map.iter() {
171 let new_filename = filename.to_owned();
179 let new_filename = filename.to_owned();
172 let mut new_mtime: i32 = entry.mtime;
180 let mut new_mtime: i32 = entry.mtime;
173 if entry.state == EntryState::Normal && entry.mtime == now {
181 if entry.state == EntryState::Normal && entry.mtime == now {
174 // The file was last modified "simultaneously" with the current
182 // The file was last modified "simultaneously" with the current
175 // write to dirstate (i.e. within the same second for file-
183 // write to dirstate (i.e. within the same second for file-
176 // systems with a granularity of 1 sec). This commonly happens
184 // systems with a granularity of 1 sec). This commonly happens
177 // for at least a couple of files on 'update'.
185 // for at least a couple of files on 'update'.
178 // The user could change the file without changing its size
186 // The user could change the file without changing its size
179 // within the same second. Invalidate the file's mtime in
187 // within the same second. Invalidate the file's mtime in
180 // dirstate, forcing future 'status' calls to compare the
188 // dirstate, forcing future 'status' calls to compare the
181 // contents of the file if the size is the same. This prevents
189 // contents of the file if the size is the same. This prevents
182 // mistakenly treating such files as clean.
190 // mistakenly treating such files as clean.
183 new_mtime = -1;
191 new_mtime = -1;
184 new_state_map.push((
192 new_state_map.push((
185 filename.to_owned(),
193 filename.to_owned(),
186 DirstateEntry {
194 DirstateEntry {
187 mtime: new_mtime,
195 mtime: new_mtime,
188 ..entry
196 ..entry
189 },
197 },
190 ));
198 ));
191 }
199 }
192 let mut new_filename = new_filename.into_vec();
200 let mut new_filename = new_filename.into_vec();
193 if let Some(copy) = copy_map.get(&filename) {
201 if let Some(copy) = copy_map.get(&filename) {
194 new_filename.push(b'\0');
202 new_filename.push(b'\0');
195 new_filename.extend(copy.bytes());
203 new_filename.extend(copy.bytes());
196 }
204 }
197
205
198 packed.write_u8(entry.state.into())?;
206 packed.write_u8(entry.state.into())?;
199 packed.write_i32::<BigEndian>(entry.mode)?;
207 packed.write_i32::<BigEndian>(entry.mode)?;
200 packed.write_i32::<BigEndian>(entry.size)?;
208 packed.write_i32::<BigEndian>(entry.size)?;
201 packed.write_i32::<BigEndian>(new_mtime)?;
209 packed.write_i32::<BigEndian>(new_mtime)?;
202 packed.write_i32::<BigEndian>(new_filename.len() as i32)?;
210 packed.write_i32::<BigEndian>(new_filename.len() as i32)?;
203 packed.extend(new_filename)
211 packed.extend(new_filename)
204 }
212 }
205
213
206 if packed.len() != expected_size {
214 if packed.len() != expected_size {
207 return Err(DirstatePackError::BadSize(expected_size, packed.len()));
215 return Err(DirstatePackError::BadSize(expected_size, packed.len()));
208 }
216 }
209
217
210 state_map.extend(new_state_map);
218 state_map.extend(new_state_map);
211
219
212 Ok(packed)
220 Ok(packed)
213 }
221 }
214
222
215 #[cfg(test)]
223 #[cfg(test)]
216 mod tests {
224 mod tests {
217 use super::*;
225 use super::*;
218 use crate::{utils::hg_path::HgPathBuf, FastHashMap};
226 use crate::{utils::hg_path::HgPathBuf, FastHashMap};
219 use pretty_assertions::assert_eq;
227 use pretty_assertions::assert_eq;
220
228
221 #[test]
229 #[test]
222 fn test_pack_dirstate_empty() {
230 fn test_pack_dirstate_empty() {
223 let mut state_map = StateMap::default();
231 let mut state_map = StateMap::default();
224 let copymap = FastHashMap::default();
232 let copymap = FastHashMap::default();
225 let parents = DirstateParents {
233 let parents = DirstateParents {
226 p1: b"12345678910111213141".into(),
234 p1: b"12345678910111213141".into(),
227 p2: b"00000000000000000000".into(),
235 p2: b"00000000000000000000".into(),
228 };
236 };
229 let now = Duration::new(15000000, 0);
237 let now = Duration::new(15000000, 0);
230 let expected = b"1234567891011121314100000000000000000000".to_vec();
238 let expected = b"1234567891011121314100000000000000000000".to_vec();
231
239
232 assert_eq!(
240 assert_eq!(
233 expected,
241 expected,
234 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
242 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
235 );
243 );
236
244
237 assert!(state_map.is_empty())
245 assert!(state_map.is_empty())
238 }
246 }
239 #[test]
247 #[test]
240 fn test_pack_dirstate_one_entry() {
248 fn test_pack_dirstate_one_entry() {
241 let expected_state_map: StateMap = [(
249 let expected_state_map: StateMap = [(
242 HgPathBuf::from_bytes(b"f1"),
250 HgPathBuf::from_bytes(b"f1"),
243 DirstateEntry {
251 DirstateEntry {
244 state: EntryState::Normal,
252 state: EntryState::Normal,
245 mode: 0o644,
253 mode: 0o644,
246 size: 0,
254 size: 0,
247 mtime: 791231220,
255 mtime: 791231220,
248 },
256 },
249 )]
257 )]
250 .iter()
258 .iter()
251 .cloned()
259 .cloned()
252 .collect();
260 .collect();
253 let mut state_map = expected_state_map.clone();
261 let mut state_map = expected_state_map.clone();
254
262
255 let copymap = FastHashMap::default();
263 let copymap = FastHashMap::default();
256 let parents = DirstateParents {
264 let parents = DirstateParents {
257 p1: b"12345678910111213141".into(),
265 p1: b"12345678910111213141".into(),
258 p2: b"00000000000000000000".into(),
266 p2: b"00000000000000000000".into(),
259 };
267 };
260 let now = Duration::new(15000000, 0);
268 let now = Duration::new(15000000, 0);
261 let expected = [
269 let expected = [
262 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
270 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
263 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
271 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
264 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
272 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
265 41, 58, 244, 0, 0, 0, 2, 102, 49,
273 41, 58, 244, 0, 0, 0, 2, 102, 49,
266 ]
274 ]
267 .to_vec();
275 .to_vec();
268
276
269 assert_eq!(
277 assert_eq!(
270 expected,
278 expected,
271 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
279 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
272 );
280 );
273
281
274 assert_eq!(expected_state_map, state_map);
282 assert_eq!(expected_state_map, state_map);
275 }
283 }
276 #[test]
284 #[test]
277 fn test_pack_dirstate_one_entry_with_copy() {
285 fn test_pack_dirstate_one_entry_with_copy() {
278 let expected_state_map: StateMap = [(
286 let expected_state_map: StateMap = [(
279 HgPathBuf::from_bytes(b"f1"),
287 HgPathBuf::from_bytes(b"f1"),
280 DirstateEntry {
288 DirstateEntry {
281 state: EntryState::Normal,
289 state: EntryState::Normal,
282 mode: 0o644,
290 mode: 0o644,
283 size: 0,
291 size: 0,
284 mtime: 791231220,
292 mtime: 791231220,
285 },
293 },
286 )]
294 )]
287 .iter()
295 .iter()
288 .cloned()
296 .cloned()
289 .collect();
297 .collect();
290 let mut state_map = expected_state_map.clone();
298 let mut state_map = expected_state_map.clone();
291 let mut copymap = FastHashMap::default();
299 let mut copymap = FastHashMap::default();
292 copymap.insert(
300 copymap.insert(
293 HgPathBuf::from_bytes(b"f1"),
301 HgPathBuf::from_bytes(b"f1"),
294 HgPathBuf::from_bytes(b"copyname"),
302 HgPathBuf::from_bytes(b"copyname"),
295 );
303 );
296 let parents = DirstateParents {
304 let parents = DirstateParents {
297 p1: b"12345678910111213141".into(),
305 p1: b"12345678910111213141".into(),
298 p2: b"00000000000000000000".into(),
306 p2: b"00000000000000000000".into(),
299 };
307 };
300 let now = Duration::new(15000000, 0);
308 let now = Duration::new(15000000, 0);
301 let expected = [
309 let expected = [
302 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
310 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
303 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
311 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
304 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
312 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
305 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, 112, 121, 110, 97,
313 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, 112, 121, 110, 97,
306 109, 101,
314 109, 101,
307 ]
315 ]
308 .to_vec();
316 .to_vec();
309
317
310 assert_eq!(
318 assert_eq!(
311 expected,
319 expected,
312 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
320 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
313 );
321 );
314 assert_eq!(expected_state_map, state_map);
322 assert_eq!(expected_state_map, state_map);
315 }
323 }
316
324
317 #[test]
325 #[test]
318 fn test_parse_pack_one_entry_with_copy() {
326 fn test_parse_pack_one_entry_with_copy() {
319 let mut state_map: StateMap = [(
327 let mut state_map: StateMap = [(
320 HgPathBuf::from_bytes(b"f1"),
328 HgPathBuf::from_bytes(b"f1"),
321 DirstateEntry {
329 DirstateEntry {
322 state: EntryState::Normal,
330 state: EntryState::Normal,
323 mode: 0o644,
331 mode: 0o644,
324 size: 0,
332 size: 0,
325 mtime: 791231220,
333 mtime: 791231220,
326 },
334 },
327 )]
335 )]
328 .iter()
336 .iter()
329 .cloned()
337 .cloned()
330 .collect();
338 .collect();
331 let mut copymap = FastHashMap::default();
339 let mut copymap = FastHashMap::default();
332 copymap.insert(
340 copymap.insert(
333 HgPathBuf::from_bytes(b"f1"),
341 HgPathBuf::from_bytes(b"f1"),
334 HgPathBuf::from_bytes(b"copyname"),
342 HgPathBuf::from_bytes(b"copyname"),
335 );
343 );
336 let parents = DirstateParents {
344 let parents = DirstateParents {
337 p1: b"12345678910111213141".into(),
345 p1: b"12345678910111213141".into(),
338 p2: b"00000000000000000000".into(),
346 p2: b"00000000000000000000".into(),
339 };
347 };
340 let now = Duration::new(15000000, 0);
348 let now = Duration::new(15000000, 0);
341 let result =
349 let result =
342 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
350 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
343 .unwrap();
351 .unwrap();
344
352
345 let (new_parents, entries, copies) =
353 let (new_parents, entries, copies) =
346 parse_dirstate(result.as_slice()).unwrap();
354 parse_dirstate(result.as_slice()).unwrap();
347 let new_state_map: StateMap = entries
355 let new_state_map: StateMap = entries
348 .into_iter()
356 .into_iter()
349 .map(|(path, entry)| (path.to_owned(), entry))
357 .map(|(path, entry)| (path.to_owned(), entry))
350 .collect();
358 .collect();
351 let new_copy_map: CopyMap = copies
359 let new_copy_map: CopyMap = copies
352 .into_iter()
360 .into_iter()
353 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
361 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
354 .collect();
362 .collect();
355
363
356 assert_eq!(
364 assert_eq!(
357 (&parents, state_map, copymap),
365 (&parents, state_map, copymap),
358 (new_parents, new_state_map, new_copy_map)
366 (new_parents, new_state_map, new_copy_map)
359 )
367 )
360 }
368 }
361
369
362 #[test]
370 #[test]
363 fn test_parse_pack_multiple_entries_with_copy() {
371 fn test_parse_pack_multiple_entries_with_copy() {
364 let mut state_map: StateMap = [
372 let mut state_map: StateMap = [
365 (
373 (
366 HgPathBuf::from_bytes(b"f1"),
374 HgPathBuf::from_bytes(b"f1"),
367 DirstateEntry {
375 DirstateEntry {
368 state: EntryState::Normal,
376 state: EntryState::Normal,
369 mode: 0o644,
377 mode: 0o644,
370 size: 0,
378 size: 0,
371 mtime: 791231220,
379 mtime: 791231220,
372 },
380 },
373 ),
381 ),
374 (
382 (
375 HgPathBuf::from_bytes(b"f2"),
383 HgPathBuf::from_bytes(b"f2"),
376 DirstateEntry {
384 DirstateEntry {
377 state: EntryState::Merged,
385 state: EntryState::Merged,
378 mode: 0o777,
386 mode: 0o777,
379 size: 1000,
387 size: 1000,
380 mtime: 791231220,
388 mtime: 791231220,
381 },
389 },
382 ),
390 ),
383 (
391 (
384 HgPathBuf::from_bytes(b"f3"),
392 HgPathBuf::from_bytes(b"f3"),
385 DirstateEntry {
393 DirstateEntry {
386 state: EntryState::Removed,
394 state: EntryState::Removed,
387 mode: 0o644,
395 mode: 0o644,
388 size: 234553,
396 size: 234553,
389 mtime: 791231220,
397 mtime: 791231220,
390 },
398 },
391 ),
399 ),
392 (
400 (
393 HgPathBuf::from_bytes(b"f4\xF6"),
401 HgPathBuf::from_bytes(b"f4\xF6"),
394 DirstateEntry {
402 DirstateEntry {
395 state: EntryState::Added,
403 state: EntryState::Added,
396 mode: 0o644,
404 mode: 0o644,
397 size: -1,
405 size: -1,
398 mtime: -1,
406 mtime: -1,
399 },
407 },
400 ),
408 ),
401 ]
409 ]
402 .iter()
410 .iter()
403 .cloned()
411 .cloned()
404 .collect();
412 .collect();
405 let mut copymap = FastHashMap::default();
413 let mut copymap = FastHashMap::default();
406 copymap.insert(
414 copymap.insert(
407 HgPathBuf::from_bytes(b"f1"),
415 HgPathBuf::from_bytes(b"f1"),
408 HgPathBuf::from_bytes(b"copyname"),
416 HgPathBuf::from_bytes(b"copyname"),
409 );
417 );
410 copymap.insert(
418 copymap.insert(
411 HgPathBuf::from_bytes(b"f4\xF6"),
419 HgPathBuf::from_bytes(b"f4\xF6"),
412 HgPathBuf::from_bytes(b"copyname2"),
420 HgPathBuf::from_bytes(b"copyname2"),
413 );
421 );
414 let parents = DirstateParents {
422 let parents = DirstateParents {
415 p1: b"12345678910111213141".into(),
423 p1: b"12345678910111213141".into(),
416 p2: b"00000000000000000000".into(),
424 p2: b"00000000000000000000".into(),
417 };
425 };
418 let now = Duration::new(15000000, 0);
426 let now = Duration::new(15000000, 0);
419 let result =
427 let result =
420 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
428 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
421 .unwrap();
429 .unwrap();
422
430
423 let (new_parents, entries, copies) =
431 let (new_parents, entries, copies) =
424 parse_dirstate(result.as_slice()).unwrap();
432 parse_dirstate(result.as_slice()).unwrap();
425 let new_state_map: StateMap = entries
433 let new_state_map: StateMap = entries
426 .into_iter()
434 .into_iter()
427 .map(|(path, entry)| (path.to_owned(), entry))
435 .map(|(path, entry)| (path.to_owned(), entry))
428 .collect();
436 .collect();
429 let new_copy_map: CopyMap = copies
437 let new_copy_map: CopyMap = copies
430 .into_iter()
438 .into_iter()
431 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
439 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
432 .collect();
440 .collect();
433
441
434 assert_eq!(
442 assert_eq!(
435 (&parents, state_map, copymap),
443 (&parents, state_map, copymap),
436 (new_parents, new_state_map, new_copy_map)
444 (new_parents, new_state_map, new_copy_map)
437 )
445 )
438 }
446 }
439
447
440 #[test]
448 #[test]
441 /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4
449 /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4
442 fn test_parse_pack_one_entry_with_copy_and_time_conflict() {
450 fn test_parse_pack_one_entry_with_copy_and_time_conflict() {
443 let mut state_map: StateMap = [(
451 let mut state_map: StateMap = [(
444 HgPathBuf::from_bytes(b"f1"),
452 HgPathBuf::from_bytes(b"f1"),
445 DirstateEntry {
453 DirstateEntry {
446 state: EntryState::Normal,
454 state: EntryState::Normal,
447 mode: 0o644,
455 mode: 0o644,
448 size: 0,
456 size: 0,
449 mtime: 15000000,
457 mtime: 15000000,
450 },
458 },
451 )]
459 )]
452 .iter()
460 .iter()
453 .cloned()
461 .cloned()
454 .collect();
462 .collect();
455 let mut copymap = FastHashMap::default();
463 let mut copymap = FastHashMap::default();
456 copymap.insert(
464 copymap.insert(
457 HgPathBuf::from_bytes(b"f1"),
465 HgPathBuf::from_bytes(b"f1"),
458 HgPathBuf::from_bytes(b"copyname"),
466 HgPathBuf::from_bytes(b"copyname"),
459 );
467 );
460 let parents = DirstateParents {
468 let parents = DirstateParents {
461 p1: b"12345678910111213141".into(),
469 p1: b"12345678910111213141".into(),
462 p2: b"00000000000000000000".into(),
470 p2: b"00000000000000000000".into(),
463 };
471 };
464 let now = Duration::new(15000000, 0);
472 let now = Duration::new(15000000, 0);
465 let result =
473 let result =
466 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
474 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
467 .unwrap();
475 .unwrap();
468
476
469 let (new_parents, entries, copies) =
477 let (new_parents, entries, copies) =
470 parse_dirstate(result.as_slice()).unwrap();
478 parse_dirstate(result.as_slice()).unwrap();
471 let new_state_map: StateMap = entries
479 let new_state_map: StateMap = entries
472 .into_iter()
480 .into_iter()
473 .map(|(path, entry)| (path.to_owned(), entry))
481 .map(|(path, entry)| (path.to_owned(), entry))
474 .collect();
482 .collect();
475 let new_copy_map: CopyMap = copies
483 let new_copy_map: CopyMap = copies
476 .into_iter()
484 .into_iter()
477 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
485 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
478 .collect();
486 .collect();
479
487
480 assert_eq!(
488 assert_eq!(
481 (
489 (
482 &parents,
490 &parents,
483 [(
491 [(
484 HgPathBuf::from_bytes(b"f1"),
492 HgPathBuf::from_bytes(b"f1"),
485 DirstateEntry {
493 DirstateEntry {
486 state: EntryState::Normal,
494 state: EntryState::Normal,
487 mode: 0o644,
495 mode: 0o644,
488 size: 0,
496 size: 0,
489 mtime: -1
497 mtime: -1
490 }
498 }
491 )]
499 )]
492 .iter()
500 .iter()
493 .cloned()
501 .cloned()
494 .collect::<StateMap>(),
502 .collect::<StateMap>(),
495 copymap,
503 copymap,
496 ),
504 ),
497 (new_parents, new_state_map, new_copy_map)
505 (new_parents, new_state_map, new_copy_map)
498 )
506 )
499 }
507 }
500 }
508 }
@@ -1,254 +1,263 b''
1 use crate::config::{Config, ConfigError, ConfigParseError};
1 use crate::config::{Config, ConfigError, ConfigParseError};
2 use crate::errors::{HgError, IoErrorContext, IoResultExt};
2 use crate::errors::{HgError, IoErrorContext, IoResultExt};
3 use crate::requirements;
3 use crate::requirements;
4 use crate::utils::current_dir;
4 use crate::utils::current_dir;
5 use crate::utils::files::get_path_from_bytes;
5 use crate::utils::files::get_path_from_bytes;
6 use memmap::{Mmap, MmapOptions};
6 use memmap::{Mmap, MmapOptions};
7 use std::collections::HashSet;
7 use std::collections::HashSet;
8 use std::path::{Path, PathBuf};
8 use std::path::{Path, PathBuf};
9
9
10 /// A repository on disk
10 /// A repository on disk
11 pub struct Repo {
11 pub struct Repo {
12 working_directory: PathBuf,
12 working_directory: PathBuf,
13 dot_hg: PathBuf,
13 dot_hg: PathBuf,
14 store: PathBuf,
14 store: PathBuf,
15 requirements: HashSet<String>,
15 requirements: HashSet<String>,
16 config: Config,
16 config: Config,
17 }
17 }
18
18
19 #[derive(Debug, derive_more::From)]
19 #[derive(Debug, derive_more::From)]
20 pub enum RepoError {
20 pub enum RepoError {
21 NotFound {
21 NotFound {
22 at: PathBuf,
22 at: PathBuf,
23 },
23 },
24 #[from]
24 #[from]
25 ConfigParseError(ConfigParseError),
25 ConfigParseError(ConfigParseError),
26 #[from]
26 #[from]
27 Other(HgError),
27 Other(HgError),
28 }
28 }
29
29
30 impl From<ConfigError> for RepoError {
30 impl From<ConfigError> for RepoError {
31 fn from(error: ConfigError) -> Self {
31 fn from(error: ConfigError) -> Self {
32 match error {
32 match error {
33 ConfigError::Parse(error) => error.into(),
33 ConfigError::Parse(error) => error.into(),
34 ConfigError::Other(error) => error.into(),
34 ConfigError::Other(error) => error.into(),
35 }
35 }
36 }
36 }
37 }
37 }
38
38
39 /// Filesystem access abstraction for the contents of a given "base" diretory
39 /// Filesystem access abstraction for the contents of a given "base" diretory
40 #[derive(Clone, Copy)]
40 #[derive(Clone, Copy)]
41 pub struct Vfs<'a> {
41 pub struct Vfs<'a> {
42 pub(crate) base: &'a Path,
42 pub(crate) base: &'a Path,
43 }
43 }
44
44
45 impl Repo {
45 impl Repo {
46 /// Find a repository, either at the given path (which must contain a `.hg`
46 /// Find a repository, either at the given path (which must contain a `.hg`
47 /// sub-directory) or by searching the current directory and its
47 /// sub-directory) or by searching the current directory and its
48 /// ancestors.
48 /// ancestors.
49 ///
49 ///
50 /// A method with two very different "modes" like this usually a code smell
50 /// A method with two very different "modes" like this usually a code smell
51 /// to make two methods instead, but in this case an `Option` is what rhg
51 /// to make two methods instead, but in this case an `Option` is what rhg
52 /// sub-commands get from Clap for the `-R` / `--repository` CLI argument.
52 /// sub-commands get from Clap for the `-R` / `--repository` CLI argument.
53 /// Having two methods would just move that `if` to almost all callers.
53 /// Having two methods would just move that `if` to almost all callers.
54 pub fn find(
54 pub fn find(
55 config: &Config,
55 config: &Config,
56 explicit_path: Option<&Path>,
56 explicit_path: Option<&Path>,
57 ) -> Result<Self, RepoError> {
57 ) -> Result<Self, RepoError> {
58 if let Some(root) = explicit_path {
58 if let Some(root) = explicit_path {
59 // Having an absolute path isn’t necessary here but can help code
59 // Having an absolute path isn’t necessary here but can help code
60 // elsewhere
60 // elsewhere
61 let root = current_dir()?.join(root);
61 let root = current_dir()?.join(root);
62 if root.join(".hg").is_dir() {
62 if root.join(".hg").is_dir() {
63 Self::new_at_path(root, config)
63 Self::new_at_path(root, config)
64 } else {
64 } else {
65 Err(RepoError::NotFound {
65 Err(RepoError::NotFound {
66 at: root.to_owned(),
66 at: root.to_owned(),
67 })
67 })
68 }
68 }
69 } else {
69 } else {
70 let current_directory = crate::utils::current_dir()?;
70 let current_directory = crate::utils::current_dir()?;
71 // ancestors() is inclusive: it first yields `current_directory`
71 // ancestors() is inclusive: it first yields `current_directory`
72 // as-is.
72 // as-is.
73 for ancestor in current_directory.ancestors() {
73 for ancestor in current_directory.ancestors() {
74 if ancestor.join(".hg").is_dir() {
74 if ancestor.join(".hg").is_dir() {
75 return Self::new_at_path(ancestor.to_owned(), config);
75 return Self::new_at_path(ancestor.to_owned(), config);
76 }
76 }
77 }
77 }
78 Err(RepoError::NotFound {
78 Err(RepoError::NotFound {
79 at: current_directory,
79 at: current_directory,
80 })
80 })
81 }
81 }
82 }
82 }
83
83
84 /// To be called after checking that `.hg` is a sub-directory
84 /// To be called after checking that `.hg` is a sub-directory
85 fn new_at_path(
85 fn new_at_path(
86 working_directory: PathBuf,
86 working_directory: PathBuf,
87 config: &Config,
87 config: &Config,
88 ) -> Result<Self, RepoError> {
88 ) -> Result<Self, RepoError> {
89 let dot_hg = working_directory.join(".hg");
89 let dot_hg = working_directory.join(".hg");
90
90
91 let mut repo_config_files = Vec::new();
91 let mut repo_config_files = Vec::new();
92 repo_config_files.push(dot_hg.join("hgrc"));
92 repo_config_files.push(dot_hg.join("hgrc"));
93 repo_config_files.push(dot_hg.join("hgrc-not-shared"));
93 repo_config_files.push(dot_hg.join("hgrc-not-shared"));
94
94
95 let hg_vfs = Vfs { base: &dot_hg };
95 let hg_vfs = Vfs { base: &dot_hg };
96 let mut reqs = requirements::load_if_exists(hg_vfs)?;
96 let mut reqs = requirements::load_if_exists(hg_vfs)?;
97 let relative =
97 let relative =
98 reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
98 reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
99 let shared =
99 let shared =
100 reqs.contains(requirements::SHARED_REQUIREMENT) || relative;
100 reqs.contains(requirements::SHARED_REQUIREMENT) || relative;
101
101
102 // From `mercurial/localrepo.py`:
102 // From `mercurial/localrepo.py`:
103 //
103 //
104 // if .hg/requires contains the sharesafe requirement, it means
104 // if .hg/requires contains the sharesafe requirement, it means
105 // there exists a `.hg/store/requires` too and we should read it
105 // there exists a `.hg/store/requires` too and we should read it
106 // NOTE: presence of SHARESAFE_REQUIREMENT imply that store requirement
106 // NOTE: presence of SHARESAFE_REQUIREMENT imply that store requirement
107 // is present. We never write SHARESAFE_REQUIREMENT for a repo if store
107 // is present. We never write SHARESAFE_REQUIREMENT for a repo if store
108 // is not present, refer checkrequirementscompat() for that
108 // is not present, refer checkrequirementscompat() for that
109 //
109 //
110 // However, if SHARESAFE_REQUIREMENT is not present, it means that the
110 // However, if SHARESAFE_REQUIREMENT is not present, it means that the
111 // repository was shared the old way. We check the share source
111 // repository was shared the old way. We check the share source
112 // .hg/requires for SHARESAFE_REQUIREMENT to detect whether the
112 // .hg/requires for SHARESAFE_REQUIREMENT to detect whether the
113 // current repository needs to be reshared
113 // current repository needs to be reshared
114 let share_safe = reqs.contains(requirements::SHARESAFE_REQUIREMENT);
114 let share_safe = reqs.contains(requirements::SHARESAFE_REQUIREMENT);
115
115
116 let store_path;
116 let store_path;
117 if !shared {
117 if !shared {
118 store_path = dot_hg.join("store");
118 store_path = dot_hg.join("store");
119 if share_safe {
119 if share_safe {
120 reqs.extend(requirements::load(Vfs { base: &store_path })?);
120 reqs.extend(requirements::load(Vfs { base: &store_path })?);
121 }
121 }
122 } else {
122 } else {
123 let bytes = hg_vfs.read("sharedpath")?;
123 let bytes = hg_vfs.read("sharedpath")?;
124 let mut shared_path = get_path_from_bytes(&bytes).to_owned();
124 let mut shared_path = get_path_from_bytes(&bytes).to_owned();
125 if relative {
125 if relative {
126 shared_path = dot_hg.join(shared_path)
126 shared_path = dot_hg.join(shared_path)
127 }
127 }
128 if !shared_path.is_dir() {
128 if !shared_path.is_dir() {
129 return Err(HgError::corrupted(format!(
129 return Err(HgError::corrupted(format!(
130 ".hg/sharedpath points to nonexistent directory {}",
130 ".hg/sharedpath points to nonexistent directory {}",
131 shared_path.display()
131 shared_path.display()
132 ))
132 ))
133 .into());
133 .into());
134 }
134 }
135
135
136 store_path = shared_path.join("store");
136 store_path = shared_path.join("store");
137
137
138 let source_is_share_safe =
138 let source_is_share_safe =
139 requirements::load(Vfs { base: &shared_path })?
139 requirements::load(Vfs { base: &shared_path })?
140 .contains(requirements::SHARESAFE_REQUIREMENT);
140 .contains(requirements::SHARESAFE_REQUIREMENT);
141
141
142 if share_safe && !source_is_share_safe {
142 if share_safe && !source_is_share_safe {
143 return Err(match config
143 return Err(match config
144 .get(b"safe-mismatch", b"source-not-safe")
144 .get(b"safe-mismatch", b"source-not-safe")
145 {
145 {
146 Some(b"abort") | None => HgError::abort(
146 Some(b"abort") | None => HgError::abort(
147 "share source does not support share-safe requirement",
147 "share source does not support share-safe requirement",
148 ),
148 ),
149 _ => HgError::unsupported("share-safe downgrade"),
149 _ => HgError::unsupported("share-safe downgrade"),
150 }
150 }
151 .into());
151 .into());
152 } else if source_is_share_safe && !share_safe {
152 } else if source_is_share_safe && !share_safe {
153 return Err(
153 return Err(
154 match config.get(b"safe-mismatch", b"source-safe") {
154 match config.get(b"safe-mismatch", b"source-safe") {
155 Some(b"abort") | None => HgError::abort(
155 Some(b"abort") | None => HgError::abort(
156 "version mismatch: source uses share-safe \
156 "version mismatch: source uses share-safe \
157 functionality while the current share does not",
157 functionality while the current share does not",
158 ),
158 ),
159 _ => HgError::unsupported("share-safe upgrade"),
159 _ => HgError::unsupported("share-safe upgrade"),
160 }
160 }
161 .into(),
161 .into(),
162 );
162 );
163 }
163 }
164
164
165 if share_safe {
165 if share_safe {
166 repo_config_files.insert(0, shared_path.join("hgrc"))
166 repo_config_files.insert(0, shared_path.join("hgrc"))
167 }
167 }
168 }
168 }
169
169
170 let repo_config = config.combine_with_repo(&repo_config_files)?;
170 let repo_config = config.combine_with_repo(&repo_config_files)?;
171
171
172 let repo = Self {
172 let repo = Self {
173 requirements: reqs,
173 requirements: reqs,
174 working_directory,
174 working_directory,
175 store: store_path,
175 store: store_path,
176 dot_hg,
176 dot_hg,
177 config: repo_config,
177 config: repo_config,
178 };
178 };
179
179
180 requirements::check(&repo)?;
180 requirements::check(&repo)?;
181
181
182 Ok(repo)
182 Ok(repo)
183 }
183 }
184
184
185 pub fn working_directory_path(&self) -> &Path {
185 pub fn working_directory_path(&self) -> &Path {
186 &self.working_directory
186 &self.working_directory
187 }
187 }
188
188
189 pub fn requirements(&self) -> &HashSet<String> {
189 pub fn requirements(&self) -> &HashSet<String> {
190 &self.requirements
190 &self.requirements
191 }
191 }
192
192
193 pub fn config(&self) -> &Config {
193 pub fn config(&self) -> &Config {
194 &self.config
194 &self.config
195 }
195 }
196
196
197 /// For accessing repository files (in `.hg`), except for the store
197 /// For accessing repository files (in `.hg`), except for the store
198 /// (`.hg/store`).
198 /// (`.hg/store`).
199 pub fn hg_vfs(&self) -> Vfs<'_> {
199 pub fn hg_vfs(&self) -> Vfs<'_> {
200 Vfs { base: &self.dot_hg }
200 Vfs { base: &self.dot_hg }
201 }
201 }
202
202
203 /// For accessing repository store files (in `.hg/store`)
203 /// For accessing repository store files (in `.hg/store`)
204 pub fn store_vfs(&self) -> Vfs<'_> {
204 pub fn store_vfs(&self) -> Vfs<'_> {
205 Vfs { base: &self.store }
205 Vfs { base: &self.store }
206 }
206 }
207
207
208 /// For accessing the working copy
208 /// For accessing the working copy
209
209
210 // The undescore prefix silences the "never used" warning. Remove before
210 // The undescore prefix silences the "never used" warning. Remove before
211 // using.
211 // using.
212 pub fn _working_directory_vfs(&self) -> Vfs<'_> {
212 pub fn _working_directory_vfs(&self) -> Vfs<'_> {
213 Vfs {
213 Vfs {
214 base: &self.working_directory,
214 base: &self.working_directory,
215 }
215 }
216 }
216 }
217
218 pub fn dirstate_parents(
219 &self,
220 ) -> Result<crate::dirstate::DirstateParents, HgError> {
221 let dirstate = self.hg_vfs().mmap_open("dirstate")?;
222 let parents =
223 crate::dirstate::parsers::parse_dirstate_parents(&dirstate)?;
224 Ok(parents.clone())
225 }
217 }
226 }
218
227
219 impl Vfs<'_> {
228 impl Vfs<'_> {
220 pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
229 pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
221 self.base.join(relative_path)
230 self.base.join(relative_path)
222 }
231 }
223
232
224 pub fn read(
233 pub fn read(
225 &self,
234 &self,
226 relative_path: impl AsRef<Path>,
235 relative_path: impl AsRef<Path>,
227 ) -> Result<Vec<u8>, HgError> {
236 ) -> Result<Vec<u8>, HgError> {
228 let path = self.join(relative_path);
237 let path = self.join(relative_path);
229 std::fs::read(&path).when_reading_file(&path)
238 std::fs::read(&path).when_reading_file(&path)
230 }
239 }
231
240
232 pub fn mmap_open(
241 pub fn mmap_open(
233 &self,
242 &self,
234 relative_path: impl AsRef<Path>,
243 relative_path: impl AsRef<Path>,
235 ) -> Result<Mmap, HgError> {
244 ) -> Result<Mmap, HgError> {
236 let path = self.base.join(relative_path);
245 let path = self.base.join(relative_path);
237 let file = std::fs::File::open(&path).when_reading_file(&path)?;
246 let file = std::fs::File::open(&path).when_reading_file(&path)?;
238 // TODO: what are the safety requirements here?
247 // TODO: what are the safety requirements here?
239 let mmap = unsafe { MmapOptions::new().map(&file) }
248 let mmap = unsafe { MmapOptions::new().map(&file) }
240 .when_reading_file(&path)?;
249 .when_reading_file(&path)?;
241 Ok(mmap)
250 Ok(mmap)
242 }
251 }
243
252
244 pub fn rename(
253 pub fn rename(
245 &self,
254 &self,
246 relative_from: impl AsRef<Path>,
255 relative_from: impl AsRef<Path>,
247 relative_to: impl AsRef<Path>,
256 relative_to: impl AsRef<Path>,
248 ) -> Result<(), HgError> {
257 ) -> Result<(), HgError> {
249 let from = self.join(relative_from);
258 let from = self.join(relative_from);
250 let to = self.join(relative_to);
259 let to = self.join(relative_to);
251 std::fs::rename(&from, &to)
260 std::fs::rename(&from, &to)
252 .with_context(|| IoErrorContext::RenamingFile { from, to })
261 .with_context(|| IoErrorContext::RenamingFile { from, to })
253 }
262 }
254 }
263 }
@@ -1,351 +1,380 b''
1 // utils module
1 // utils module
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! Contains useful functions, traits, structs, etc. for use in core.
8 //! Contains useful functions, traits, structs, etc. for use in core.
9
9
10 use crate::errors::{HgError, IoErrorContext};
10 use crate::errors::{HgError, IoErrorContext};
11 use crate::utils::hg_path::HgPath;
11 use crate::utils::hg_path::HgPath;
12 use im_rc::ordmap::DiffItem;
12 use im_rc::ordmap::DiffItem;
13 use im_rc::ordmap::OrdMap;
13 use im_rc::ordmap::OrdMap;
14 use std::{io::Write, ops::Deref};
14 use std::{io::Write, ops::Deref};
15
15
16 pub mod files;
16 pub mod files;
17 pub mod hg_path;
17 pub mod hg_path;
18 pub mod path_auditor;
18 pub mod path_auditor;
19
19
20 /// Useful until rust/issues/56345 is stable
20 /// Useful until rust/issues/56345 is stable
21 ///
21 ///
22 /// # Examples
22 /// # Examples
23 ///
23 ///
24 /// ```
24 /// ```
25 /// use crate::hg::utils::find_slice_in_slice;
25 /// use crate::hg::utils::find_slice_in_slice;
26 ///
26 ///
27 /// let haystack = b"This is the haystack".to_vec();
27 /// let haystack = b"This is the haystack".to_vec();
28 /// assert_eq!(find_slice_in_slice(&haystack, b"the"), Some(8));
28 /// assert_eq!(find_slice_in_slice(&haystack, b"the"), Some(8));
29 /// assert_eq!(find_slice_in_slice(&haystack, b"not here"), None);
29 /// assert_eq!(find_slice_in_slice(&haystack, b"not here"), None);
30 /// ```
30 /// ```
31 pub fn find_slice_in_slice<T>(slice: &[T], needle: &[T]) -> Option<usize>
31 pub fn find_slice_in_slice<T>(slice: &[T], needle: &[T]) -> Option<usize>
32 where
32 where
33 for<'a> &'a [T]: PartialEq,
33 for<'a> &'a [T]: PartialEq,
34 {
34 {
35 slice
35 slice
36 .windows(needle.len())
36 .windows(needle.len())
37 .position(|window| window == needle)
37 .position(|window| window == needle)
38 }
38 }
39
39
40 /// Replaces the `from` slice with the `to` slice inside the `buf` slice.
40 /// Replaces the `from` slice with the `to` slice inside the `buf` slice.
41 ///
41 ///
42 /// # Examples
42 /// # Examples
43 ///
43 ///
44 /// ```
44 /// ```
45 /// use crate::hg::utils::replace_slice;
45 /// use crate::hg::utils::replace_slice;
46 /// let mut line = b"I hate writing tests!".to_vec();
46 /// let mut line = b"I hate writing tests!".to_vec();
47 /// replace_slice(&mut line, b"hate", b"love");
47 /// replace_slice(&mut line, b"hate", b"love");
48 /// assert_eq!(
48 /// assert_eq!(
49 /// line,
49 /// line,
50 /// b"I love writing tests!".to_vec()
50 /// b"I love writing tests!".to_vec()
51 /// );
51 /// );
52 /// ```
52 /// ```
53 pub fn replace_slice<T>(buf: &mut [T], from: &[T], to: &[T])
53 pub fn replace_slice<T>(buf: &mut [T], from: &[T], to: &[T])
54 where
54 where
55 T: Clone + PartialEq,
55 T: Clone + PartialEq,
56 {
56 {
57 if buf.len() < from.len() || from.len() != to.len() {
57 if buf.len() < from.len() || from.len() != to.len() {
58 return;
58 return;
59 }
59 }
60 for i in 0..=buf.len() - from.len() {
60 for i in 0..=buf.len() - from.len() {
61 if buf[i..].starts_with(from) {
61 if buf[i..].starts_with(from) {
62 buf[i..(i + from.len())].clone_from_slice(to);
62 buf[i..(i + from.len())].clone_from_slice(to);
63 }
63 }
64 }
64 }
65 }
65 }
66
66
67 pub trait SliceExt {
67 pub trait SliceExt {
68 fn trim_end(&self) -> &Self;
68 fn trim_end(&self) -> &Self;
69 fn trim_start(&self) -> &Self;
69 fn trim_start(&self) -> &Self;
70 fn trim(&self) -> &Self;
70 fn trim(&self) -> &Self;
71 fn drop_prefix(&self, needle: &Self) -> Option<&Self>;
71 fn drop_prefix(&self, needle: &Self) -> Option<&Self>;
72 fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])>;
72 fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])>;
73 }
73 }
74
74
75 #[allow(clippy::trivially_copy_pass_by_ref)]
75 #[allow(clippy::trivially_copy_pass_by_ref)]
76 fn is_not_whitespace(c: &u8) -> bool {
76 fn is_not_whitespace(c: &u8) -> bool {
77 !(*c as char).is_whitespace()
77 !(*c as char).is_whitespace()
78 }
78 }
79
79
80 impl SliceExt for [u8] {
80 impl SliceExt for [u8] {
81 fn trim_end(&self) -> &[u8] {
81 fn trim_end(&self) -> &[u8] {
82 if let Some(last) = self.iter().rposition(is_not_whitespace) {
82 if let Some(last) = self.iter().rposition(is_not_whitespace) {
83 &self[..=last]
83 &self[..=last]
84 } else {
84 } else {
85 &[]
85 &[]
86 }
86 }
87 }
87 }
88 fn trim_start(&self) -> &[u8] {
88 fn trim_start(&self) -> &[u8] {
89 if let Some(first) = self.iter().position(is_not_whitespace) {
89 if let Some(first) = self.iter().position(is_not_whitespace) {
90 &self[first..]
90 &self[first..]
91 } else {
91 } else {
92 &[]
92 &[]
93 }
93 }
94 }
94 }
95
95
96 /// ```
96 /// ```
97 /// use hg::utils::SliceExt;
97 /// use hg::utils::SliceExt;
98 /// assert_eq!(
98 /// assert_eq!(
99 /// b" to trim ".trim(),
99 /// b" to trim ".trim(),
100 /// b"to trim"
100 /// b"to trim"
101 /// );
101 /// );
102 /// assert_eq!(
102 /// assert_eq!(
103 /// b"to trim ".trim(),
103 /// b"to trim ".trim(),
104 /// b"to trim"
104 /// b"to trim"
105 /// );
105 /// );
106 /// assert_eq!(
106 /// assert_eq!(
107 /// b" to trim".trim(),
107 /// b" to trim".trim(),
108 /// b"to trim"
108 /// b"to trim"
109 /// );
109 /// );
110 /// ```
110 /// ```
111 fn trim(&self) -> &[u8] {
111 fn trim(&self) -> &[u8] {
112 self.trim_start().trim_end()
112 self.trim_start().trim_end()
113 }
113 }
114
114
115 fn drop_prefix(&self, needle: &Self) -> Option<&Self> {
115 fn drop_prefix(&self, needle: &Self) -> Option<&Self> {
116 if self.starts_with(needle) {
116 if self.starts_with(needle) {
117 Some(&self[needle.len()..])
117 Some(&self[needle.len()..])
118 } else {
118 } else {
119 None
119 None
120 }
120 }
121 }
121 }
122
122
123 fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])> {
123 fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])> {
124 let mut iter = self.splitn(2, |&byte| byte == separator);
124 let mut iter = self.splitn(2, |&byte| byte == separator);
125 let a = iter.next()?;
125 let a = iter.next()?;
126 let b = iter.next()?;
126 let b = iter.next()?;
127 Some((a, b))
127 Some((a, b))
128 }
128 }
129 }
129 }
130
130
131 pub trait Escaped {
131 pub trait Escaped {
132 /// Return bytes escaped for display to the user
132 /// Return bytes escaped for display to the user
133 fn escaped_bytes(&self) -> Vec<u8>;
133 fn escaped_bytes(&self) -> Vec<u8>;
134 }
134 }
135
135
136 impl Escaped for u8 {
136 impl Escaped for u8 {
137 fn escaped_bytes(&self) -> Vec<u8> {
137 fn escaped_bytes(&self) -> Vec<u8> {
138 let mut acc = vec![];
138 let mut acc = vec![];
139 match self {
139 match self {
140 c @ b'\'' | c @ b'\\' => {
140 c @ b'\'' | c @ b'\\' => {
141 acc.push(b'\\');
141 acc.push(b'\\');
142 acc.push(*c);
142 acc.push(*c);
143 }
143 }
144 b'\t' => {
144 b'\t' => {
145 acc.extend(br"\\t");
145 acc.extend(br"\\t");
146 }
146 }
147 b'\n' => {
147 b'\n' => {
148 acc.extend(br"\\n");
148 acc.extend(br"\\n");
149 }
149 }
150 b'\r' => {
150 b'\r' => {
151 acc.extend(br"\\r");
151 acc.extend(br"\\r");
152 }
152 }
153 c if (*c < b' ' || *c >= 127) => {
153 c if (*c < b' ' || *c >= 127) => {
154 write!(acc, "\\x{:x}", self).unwrap();
154 write!(acc, "\\x{:x}", self).unwrap();
155 }
155 }
156 c => {
156 c => {
157 acc.push(*c);
157 acc.push(*c);
158 }
158 }
159 }
159 }
160 acc
160 acc
161 }
161 }
162 }
162 }
163
163
164 impl<'a, T: Escaped> Escaped for &'a [T] {
164 impl<'a, T: Escaped> Escaped for &'a [T] {
165 fn escaped_bytes(&self) -> Vec<u8> {
165 fn escaped_bytes(&self) -> Vec<u8> {
166 self.iter().flat_map(Escaped::escaped_bytes).collect()
166 self.iter().flat_map(Escaped::escaped_bytes).collect()
167 }
167 }
168 }
168 }
169
169
170 impl<T: Escaped> Escaped for Vec<T> {
170 impl<T: Escaped> Escaped for Vec<T> {
171 fn escaped_bytes(&self) -> Vec<u8> {
171 fn escaped_bytes(&self) -> Vec<u8> {
172 self.deref().escaped_bytes()
172 self.deref().escaped_bytes()
173 }
173 }
174 }
174 }
175
175
176 impl<'a> Escaped for &'a HgPath {
176 impl<'a> Escaped for &'a HgPath {
177 fn escaped_bytes(&self) -> Vec<u8> {
177 fn escaped_bytes(&self) -> Vec<u8> {
178 self.as_bytes().escaped_bytes()
178 self.as_bytes().escaped_bytes()
179 }
179 }
180 }
180 }
181
181
182 // TODO: use the str method when we require Rust 1.45
182 // TODO: use the str method when we require Rust 1.45
183 pub(crate) fn strip_suffix<'a>(s: &'a str, suffix: &str) -> Option<&'a str> {
183 pub(crate) fn strip_suffix<'a>(s: &'a str, suffix: &str) -> Option<&'a str> {
184 if s.ends_with(suffix) {
184 if s.ends_with(suffix) {
185 Some(&s[..s.len() - suffix.len()])
185 Some(&s[..s.len() - suffix.len()])
186 } else {
186 } else {
187 None
187 None
188 }
188 }
189 }
189 }
190
190
191 #[cfg(unix)]
192 pub fn shell_quote(value: &[u8]) -> Vec<u8> {
193 // TODO: Use the `matches!` macro when we require Rust 1.42+
194 if value.iter().all(|&byte| match byte {
195 b'a'..=b'z'
196 | b'A'..=b'Z'
197 | b'0'..=b'9'
198 | b'.'
199 | b'_'
200 | b'/'
201 | b'+'
202 | b'-' => true,
203 _ => false,
204 }) {
205 value.to_owned()
206 } else {
207 let mut quoted = Vec::with_capacity(value.len() + 2);
208 quoted.push(b'\'');
209 for &byte in value {
210 if byte == b'\'' {
211 quoted.push(b'\\');
212 }
213 quoted.push(byte);
214 }
215 quoted.push(b'\'');
216 quoted
217 }
218 }
219
191 pub fn current_dir() -> Result<std::path::PathBuf, HgError> {
220 pub fn current_dir() -> Result<std::path::PathBuf, HgError> {
192 std::env::current_dir().map_err(|error| HgError::IoError {
221 std::env::current_dir().map_err(|error| HgError::IoError {
193 error,
222 error,
194 context: IoErrorContext::CurrentDir,
223 context: IoErrorContext::CurrentDir,
195 })
224 })
196 }
225 }
197
226
198 pub fn current_exe() -> Result<std::path::PathBuf, HgError> {
227 pub fn current_exe() -> Result<std::path::PathBuf, HgError> {
199 std::env::current_exe().map_err(|error| HgError::IoError {
228 std::env::current_exe().map_err(|error| HgError::IoError {
200 error,
229 error,
201 context: IoErrorContext::CurrentExe,
230 context: IoErrorContext::CurrentExe,
202 })
231 })
203 }
232 }
204
233
205 pub(crate) enum MergeResult<V> {
234 pub(crate) enum MergeResult<V> {
206 UseLeftValue,
235 UseLeftValue,
207 UseRightValue,
236 UseRightValue,
208 UseNewValue(V),
237 UseNewValue(V),
209 }
238 }
210
239
211 /// Return the union of the two given maps,
240 /// Return the union of the two given maps,
212 /// calling `merge(key, left_value, right_value)` to resolve keys that exist in
241 /// calling `merge(key, left_value, right_value)` to resolve keys that exist in
213 /// both.
242 /// both.
214 ///
243 ///
215 /// CC https://github.com/bodil/im-rs/issues/166
244 /// CC https://github.com/bodil/im-rs/issues/166
216 pub(crate) fn ordmap_union_with_merge<K, V>(
245 pub(crate) fn ordmap_union_with_merge<K, V>(
217 left: OrdMap<K, V>,
246 left: OrdMap<K, V>,
218 right: OrdMap<K, V>,
247 right: OrdMap<K, V>,
219 mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
248 mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
220 ) -> OrdMap<K, V>
249 ) -> OrdMap<K, V>
221 where
250 where
222 K: Clone + Ord,
251 K: Clone + Ord,
223 V: Clone + PartialEq,
252 V: Clone + PartialEq,
224 {
253 {
225 if left.ptr_eq(&right) {
254 if left.ptr_eq(&right) {
226 // One of the two maps is an unmodified clone of the other
255 // One of the two maps is an unmodified clone of the other
227 left
256 left
228 } else if left.len() / 2 > right.len() {
257 } else if left.len() / 2 > right.len() {
229 // When two maps have different sizes,
258 // When two maps have different sizes,
230 // their size difference is a lower bound on
259 // their size difference is a lower bound on
231 // how many keys of the larger map are not also in the smaller map.
260 // how many keys of the larger map are not also in the smaller map.
232 // This in turn is a lower bound on the number of differences in
261 // This in turn is a lower bound on the number of differences in
233 // `OrdMap::diff` and the "amount of work" that would be done
262 // `OrdMap::diff` and the "amount of work" that would be done
234 // by `ordmap_union_with_merge_by_diff`.
263 // by `ordmap_union_with_merge_by_diff`.
235 //
264 //
236 // Here `left` is more than twice the size of `right`,
265 // Here `left` is more than twice the size of `right`,
237 // so the number of differences is more than the total size of
266 // so the number of differences is more than the total size of
238 // `right`. Therefore an algorithm based on iterating `right`
267 // `right`. Therefore an algorithm based on iterating `right`
239 // is more efficient.
268 // is more efficient.
240 //
269 //
241 // This helps a lot when a tiny (or empty) map is merged
270 // This helps a lot when a tiny (or empty) map is merged
242 // with a large one.
271 // with a large one.
243 ordmap_union_with_merge_by_iter(left, right, merge)
272 ordmap_union_with_merge_by_iter(left, right, merge)
244 } else if left.len() < right.len() / 2 {
273 } else if left.len() < right.len() / 2 {
245 // Same as above but with `left` and `right` swapped
274 // Same as above but with `left` and `right` swapped
246 ordmap_union_with_merge_by_iter(right, left, |key, a, b| {
275 ordmap_union_with_merge_by_iter(right, left, |key, a, b| {
247 // Also swapped in `merge` arguments:
276 // Also swapped in `merge` arguments:
248 match merge(key, b, a) {
277 match merge(key, b, a) {
249 MergeResult::UseNewValue(v) => MergeResult::UseNewValue(v),
278 MergeResult::UseNewValue(v) => MergeResult::UseNewValue(v),
250 // … and swap back in `merge` result:
279 // … and swap back in `merge` result:
251 MergeResult::UseLeftValue => MergeResult::UseRightValue,
280 MergeResult::UseLeftValue => MergeResult::UseRightValue,
252 MergeResult::UseRightValue => MergeResult::UseLeftValue,
281 MergeResult::UseRightValue => MergeResult::UseLeftValue,
253 }
282 }
254 })
283 })
255 } else {
284 } else {
256 // For maps of similar size, use the algorithm based on `OrdMap::diff`
285 // For maps of similar size, use the algorithm based on `OrdMap::diff`
257 ordmap_union_with_merge_by_diff(left, right, merge)
286 ordmap_union_with_merge_by_diff(left, right, merge)
258 }
287 }
259 }
288 }
260
289
261 /// Efficient if `right` is much smaller than `left`
290 /// Efficient if `right` is much smaller than `left`
262 fn ordmap_union_with_merge_by_iter<K, V>(
291 fn ordmap_union_with_merge_by_iter<K, V>(
263 mut left: OrdMap<K, V>,
292 mut left: OrdMap<K, V>,
264 right: OrdMap<K, V>,
293 right: OrdMap<K, V>,
265 mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
294 mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
266 ) -> OrdMap<K, V>
295 ) -> OrdMap<K, V>
267 where
296 where
268 K: Clone + Ord,
297 K: Clone + Ord,
269 V: Clone,
298 V: Clone,
270 {
299 {
271 for (key, right_value) in right {
300 for (key, right_value) in right {
272 match left.get(&key) {
301 match left.get(&key) {
273 None => {
302 None => {
274 left.insert(key, right_value);
303 left.insert(key, right_value);
275 }
304 }
276 Some(left_value) => match merge(&key, left_value, &right_value) {
305 Some(left_value) => match merge(&key, left_value, &right_value) {
277 MergeResult::UseLeftValue => {}
306 MergeResult::UseLeftValue => {}
278 MergeResult::UseRightValue => {
307 MergeResult::UseRightValue => {
279 left.insert(key, right_value);
308 left.insert(key, right_value);
280 }
309 }
281 MergeResult::UseNewValue(new_value) => {
310 MergeResult::UseNewValue(new_value) => {
282 left.insert(key, new_value);
311 left.insert(key, new_value);
283 }
312 }
284 },
313 },
285 }
314 }
286 }
315 }
287 left
316 left
288 }
317 }
289
318
290 /// Fallback when both maps are of similar size
319 /// Fallback when both maps are of similar size
291 fn ordmap_union_with_merge_by_diff<K, V>(
320 fn ordmap_union_with_merge_by_diff<K, V>(
292 mut left: OrdMap<K, V>,
321 mut left: OrdMap<K, V>,
293 mut right: OrdMap<K, V>,
322 mut right: OrdMap<K, V>,
294 mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
323 mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
295 ) -> OrdMap<K, V>
324 ) -> OrdMap<K, V>
296 where
325 where
297 K: Clone + Ord,
326 K: Clone + Ord,
298 V: Clone + PartialEq,
327 V: Clone + PartialEq,
299 {
328 {
300 // (key, value) pairs that would need to be inserted in either map
329 // (key, value) pairs that would need to be inserted in either map
301 // in order to turn it into the union.
330 // in order to turn it into the union.
302 //
331 //
303 // TODO: if/when https://github.com/bodil/im-rs/pull/168 is accepted,
332 // TODO: if/when https://github.com/bodil/im-rs/pull/168 is accepted,
304 // change these from `Vec<(K, V)>` to `Vec<(&K, Cow<V>)>`
333 // change these from `Vec<(K, V)>` to `Vec<(&K, Cow<V>)>`
305 // with `left_updates` only borrowing from `right` and `right_updates` from
334 // with `left_updates` only borrowing from `right` and `right_updates` from
306 // `left`, and with `Cow::Owned` used for `MergeResult::UseNewValue`.
335 // `left`, and with `Cow::Owned` used for `MergeResult::UseNewValue`.
307 //
336 //
308 // This would allow moving all `.clone()` calls to after we’ve decided
337 // This would allow moving all `.clone()` calls to after we’ve decided
309 // which of `right_updates` or `left_updates` to use
338 // which of `right_updates` or `left_updates` to use
310 // (value ones becoming `Cow::into_owned`),
339 // (value ones becoming `Cow::into_owned`),
311 // and avoid making clones we don’t end up using.
340 // and avoid making clones we don’t end up using.
312 let mut left_updates = Vec::new();
341 let mut left_updates = Vec::new();
313 let mut right_updates = Vec::new();
342 let mut right_updates = Vec::new();
314
343
315 for difference in left.diff(&right) {
344 for difference in left.diff(&right) {
316 match difference {
345 match difference {
317 DiffItem::Add(key, value) => {
346 DiffItem::Add(key, value) => {
318 left_updates.push((key.clone(), value.clone()))
347 left_updates.push((key.clone(), value.clone()))
319 }
348 }
320 DiffItem::Remove(key, value) => {
349 DiffItem::Remove(key, value) => {
321 right_updates.push((key.clone(), value.clone()))
350 right_updates.push((key.clone(), value.clone()))
322 }
351 }
323 DiffItem::Update {
352 DiffItem::Update {
324 old: (key, left_value),
353 old: (key, left_value),
325 new: (_, right_value),
354 new: (_, right_value),
326 } => match merge(key, left_value, right_value) {
355 } => match merge(key, left_value, right_value) {
327 MergeResult::UseLeftValue => {
356 MergeResult::UseLeftValue => {
328 right_updates.push((key.clone(), left_value.clone()))
357 right_updates.push((key.clone(), left_value.clone()))
329 }
358 }
330 MergeResult::UseRightValue => {
359 MergeResult::UseRightValue => {
331 left_updates.push((key.clone(), right_value.clone()))
360 left_updates.push((key.clone(), right_value.clone()))
332 }
361 }
333 MergeResult::UseNewValue(new_value) => {
362 MergeResult::UseNewValue(new_value) => {
334 left_updates.push((key.clone(), new_value.clone()));
363 left_updates.push((key.clone(), new_value.clone()));
335 right_updates.push((key.clone(), new_value))
364 right_updates.push((key.clone(), new_value))
336 }
365 }
337 },
366 },
338 }
367 }
339 }
368 }
340 if left_updates.len() < right_updates.len() {
369 if left_updates.len() < right_updates.len() {
341 for (key, value) in left_updates {
370 for (key, value) in left_updates {
342 left.insert(key, value);
371 left.insert(key, value);
343 }
372 }
344 left
373 left
345 } else {
374 } else {
346 for (key, value) in right_updates {
375 for (key, value) in right_updates {
347 right.insert(key, value);
376 right.insert(key, value);
348 }
377 }
349 right
378 right
350 }
379 }
351 }
380 }
@@ -1,17 +1,19 b''
1 [package]
1 [package]
2 name = "rhg"
2 name = "rhg"
3 version = "0.1.0"
3 version = "0.1.0"
4 authors = [
4 authors = [
5 "Antoine Cezar <antoine.cezar@octobus.net>",
5 "Antoine Cezar <antoine.cezar@octobus.net>",
6 "Raphaël Gomès <raphael.gomes@octobus.net>",
6 "Raphaël Gomès <raphael.gomes@octobus.net>",
7 ]
7 ]
8 edition = "2018"
8 edition = "2018"
9
9
10 [dependencies]
10 [dependencies]
11 hg-core = { path = "../hg-core"}
11 hg-core = { path = "../hg-core"}
12 chrono = "0.4.19"
12 clap = "2.33.1"
13 clap = "2.33.1"
13 derive_more = "0.99"
14 derive_more = "0.99"
14 log = "0.4.11"
15 log = "0.4.11"
15 micro-timer = "0.3.1"
16 micro-timer = "0.3.1"
16 env_logger = "0.7.1"
17 env_logger = "0.7.1"
17 format-bytes = "0.2.0"
18 format-bytes = "0.2.0"
19 users = "0.11.0"
@@ -1,175 +1,191 b''
1 extern crate log;
1 extern crate log;
2 use crate::ui::Ui;
2 use crate::ui::Ui;
3 use clap::App;
3 use clap::App;
4 use clap::AppSettings;
4 use clap::AppSettings;
5 use clap::Arg;
5 use clap::Arg;
6 use clap::ArgMatches;
6 use clap::ArgMatches;
7 use format_bytes::format_bytes;
7 use format_bytes::format_bytes;
8 use hg::config::Config;
8 use hg::config::Config;
9 use hg::repo::{Repo, RepoError};
9 use hg::repo::{Repo, RepoError};
10 use std::path::{Path, PathBuf};
10 use std::path::{Path, PathBuf};
11
11
12 mod blackbox;
12 mod error;
13 mod error;
13 mod exitcode;
14 mod exitcode;
14 mod ui;
15 mod ui;
15 use error::CommandError;
16 use error::CommandError;
16
17
17 fn add_global_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
18 fn add_global_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
18 app.arg(
19 app.arg(
19 Arg::with_name("repository")
20 Arg::with_name("repository")
20 .help("repository root directory")
21 .help("repository root directory")
21 .short("-R")
22 .short("-R")
22 .long("--repository")
23 .long("--repository")
23 .value_name("REPO")
24 .value_name("REPO")
24 .takes_value(true),
25 .takes_value(true),
25 )
26 )
26 .arg(
27 .arg(
27 Arg::with_name("config")
28 Arg::with_name("config")
28 .help("set/override config option (use 'section.name=value')")
29 .help("set/override config option (use 'section.name=value')")
29 .long("--config")
30 .long("--config")
30 .value_name("CONFIG")
31 .value_name("CONFIG")
31 .takes_value(true)
32 .takes_value(true)
32 // Ok: `--config section.key1=val --config section.key2=val2`
33 // Ok: `--config section.key1=val --config section.key2=val2`
33 .multiple(true)
34 .multiple(true)
34 // Not ok: `--config section.key1=val section.key2=val2`
35 // Not ok: `--config section.key1=val section.key2=val2`
35 .number_of_values(1),
36 .number_of_values(1),
36 )
37 )
37 }
38 }
38
39
39 fn main_with_result(ui: &ui::Ui) -> Result<(), CommandError> {
40 fn main_with_result(
41 ui: &ui::Ui,
42 process_start_time: &blackbox::ProcessStartTime,
43 ) -> Result<(), CommandError> {
40 env_logger::init();
44 env_logger::init();
41 let app = App::new("rhg")
45 let app = App::new("rhg")
42 .setting(AppSettings::AllowInvalidUtf8)
46 .setting(AppSettings::AllowInvalidUtf8)
43 .setting(AppSettings::SubcommandRequired)
47 .setting(AppSettings::SubcommandRequired)
44 .setting(AppSettings::VersionlessSubcommands)
48 .setting(AppSettings::VersionlessSubcommands)
45 .version("0.0.1");
49 .version("0.0.1");
46 let app = add_global_args(app);
50 let app = add_global_args(app);
47 let app = add_subcommand_args(app);
51 let app = add_subcommand_args(app);
48
52
49 let matches = app.clone().get_matches_safe()?;
53 let matches = app.clone().get_matches_safe()?;
50
54
51 let (subcommand_name, subcommand_matches) = matches.subcommand();
55 let (subcommand_name, subcommand_matches) = matches.subcommand();
52 let run = subcommand_run_fn(subcommand_name)
56 let run = subcommand_run_fn(subcommand_name)
53 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
57 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
54 let subcommand_args = subcommand_matches
58 let subcommand_args = subcommand_matches
55 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
59 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
56
60
57 // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s.
61 // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s.
58 // `hg log -R ./foo`
62 // `hg log -R ./foo`
59 let value_of_global_arg = |name| {
63 let value_of_global_arg = |name| {
60 subcommand_args
64 subcommand_args
61 .value_of_os(name)
65 .value_of_os(name)
62 .or_else(|| matches.value_of_os(name))
66 .or_else(|| matches.value_of_os(name))
63 };
67 };
64 // For arguments where multiple occurences are allowed, return a
68 // For arguments where multiple occurences are allowed, return a
65 // possibly-iterator of all values.
69 // possibly-iterator of all values.
66 let values_of_global_arg = |name: &str| {
70 let values_of_global_arg = |name: &str| {
67 let a = matches.values_of_os(name).into_iter().flatten();
71 let a = matches.values_of_os(name).into_iter().flatten();
68 let b = subcommand_args.values_of_os(name).into_iter().flatten();
72 let b = subcommand_args.values_of_os(name).into_iter().flatten();
69 a.chain(b)
73 a.chain(b)
70 };
74 };
71
75
72 let config_args = values_of_global_arg("config")
76 let config_args = values_of_global_arg("config")
73 .map(hg::utils::files::get_bytes_from_os_str);
77 .map(hg::utils::files::get_bytes_from_os_str);
74 let non_repo_config = &hg::config::Config::load(config_args)?;
78 let non_repo_config = &hg::config::Config::load(config_args)?;
75
79
76 let repo_path = value_of_global_arg("repository").map(Path::new);
80 let repo_path = value_of_global_arg("repository").map(Path::new);
77 let repo = match Repo::find(non_repo_config, repo_path) {
81 let repo = match Repo::find(non_repo_config, repo_path) {
78 Ok(repo) => Ok(repo),
82 Ok(repo) => Ok(repo),
79 Err(RepoError::NotFound { at }) if repo_path.is_none() => {
83 Err(RepoError::NotFound { at }) if repo_path.is_none() => {
80 // Not finding a repo is not fatal yet, if `-R` was not given
84 // Not finding a repo is not fatal yet, if `-R` was not given
81 Err(NoRepoInCwdError { cwd: at })
85 Err(NoRepoInCwdError { cwd: at })
82 }
86 }
83 Err(error) => return Err(error.into()),
87 Err(error) => return Err(error.into()),
84 };
88 };
85
89
86 run(&CliInvocation {
90 let invocation = CliInvocation {
87 ui,
91 ui,
88 subcommand_args,
92 subcommand_args,
89 non_repo_config,
93 non_repo_config,
90 repo: repo.as_ref(),
94 repo: repo.as_ref(),
91 })
95 };
96 let blackbox = blackbox::Blackbox::new(&invocation, process_start_time)?;
97 blackbox.log_command_start();
98 let result = run(&invocation);
99 blackbox.log_command_end(exit_code(&result));
100 result
92 }
101 }
93
102
94 fn main() {
103 fn main() {
104 // Run this first, before we find out if the blackbox extension is even
105 // enabled, in order to include everything in-between in the duration
106 // measurements. Reading config files can be slow if they’re on NFS.
107 let process_start_time = blackbox::ProcessStartTime::now();
108
95 let ui = ui::Ui::new();
109 let ui = ui::Ui::new();
96
110
97 let exit_code = match main_with_result(&ui) {
111 let result = main_with_result(&ui, &process_start_time);
112 if let Err(CommandError::Abort { message }) = &result {
113 if !message.is_empty() {
114 // Ignore errors when writing to stderr, we’re already exiting
115 // with failure code so there’s not much more we can do.
116 let _ = ui.write_stderr(&format_bytes!(b"abort: {}\n", message));
117 }
118 }
119 std::process::exit(exit_code(&result))
120 }
121
122 fn exit_code(result: &Result<(), CommandError>) -> i32 {
123 match result {
98 Ok(()) => exitcode::OK,
124 Ok(()) => exitcode::OK,
125 Err(CommandError::Abort { .. }) => exitcode::ABORT,
99
126
100 // Exit with a specific code and no error message to let a potential
127 // Exit with a specific code and no error message to let a potential
101 // wrapper script fallback to Python-based Mercurial.
128 // wrapper script fallback to Python-based Mercurial.
102 Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED,
129 Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED,
103
130 }
104 Err(CommandError::Abort { message }) => {
105 if !message.is_empty() {
106 // Ignore errors when writing to stderr, we’re already exiting
107 // with failure code so there’s not much more we can do.
108 let _ =
109 ui.write_stderr(&format_bytes!(b"abort: {}\n", message));
110 }
111 exitcode::ABORT
112 }
113 };
114 std::process::exit(exit_code)
115 }
131 }
116
132
117 macro_rules! subcommands {
133 macro_rules! subcommands {
118 ($( $command: ident )+) => {
134 ($( $command: ident )+) => {
119 mod commands {
135 mod commands {
120 $(
136 $(
121 pub mod $command;
137 pub mod $command;
122 )+
138 )+
123 }
139 }
124
140
125 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
141 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
126 app
142 app
127 $(
143 $(
128 .subcommand(add_global_args(commands::$command::args()))
144 .subcommand(add_global_args(commands::$command::args()))
129 )+
145 )+
130 }
146 }
131
147
132 pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>;
148 pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>;
133
149
134 fn subcommand_run_fn(name: &str) -> Option<RunFn> {
150 fn subcommand_run_fn(name: &str) -> Option<RunFn> {
135 match name {
151 match name {
136 $(
152 $(
137 stringify!($command) => Some(commands::$command::run),
153 stringify!($command) => Some(commands::$command::run),
138 )+
154 )+
139 _ => None,
155 _ => None,
140 }
156 }
141 }
157 }
142 };
158 };
143 }
159 }
144
160
145 subcommands! {
161 subcommands! {
146 cat
162 cat
147 debugdata
163 debugdata
148 debugrequirements
164 debugrequirements
149 files
165 files
150 root
166 root
151 config
167 config
152 }
168 }
153 pub struct CliInvocation<'a> {
169 pub struct CliInvocation<'a> {
154 ui: &'a Ui,
170 ui: &'a Ui,
155 subcommand_args: &'a ArgMatches<'a>,
171 subcommand_args: &'a ArgMatches<'a>,
156 non_repo_config: &'a Config,
172 non_repo_config: &'a Config,
157 /// References inside `Result` is a bit peculiar but allow
173 /// References inside `Result` is a bit peculiar but allow
158 /// `invocation.repo?` to work out with `&CliInvocation` since this
174 /// `invocation.repo?` to work out with `&CliInvocation` since this
159 /// `Result` type is `Copy`.
175 /// `Result` type is `Copy`.
160 repo: Result<&'a Repo, &'a NoRepoInCwdError>,
176 repo: Result<&'a Repo, &'a NoRepoInCwdError>,
161 }
177 }
162
178
163 struct NoRepoInCwdError {
179 struct NoRepoInCwdError {
164 cwd: PathBuf,
180 cwd: PathBuf,
165 }
181 }
166
182
167 impl CliInvocation<'_> {
183 impl CliInvocation<'_> {
168 fn config(&self) -> &Config {
184 fn config(&self) -> &Config {
169 if let Ok(repo) = self.repo {
185 if let Ok(repo) = self.repo {
170 repo.config()
186 repo.config()
171 } else {
187 } else {
172 self.non_repo_config
188 self.non_repo_config
173 }
189 }
174 }
190 }
175 }
191 }
@@ -1,263 +1,275 b''
1 #require rust
1 #require rust
2
2
3 Define an rhg function that will only run if rhg exists
3 Define an rhg function that will only run if rhg exists
4 $ rhg() {
4 $ rhg() {
5 > if [ -f "$RUNTESTDIR/../rust/target/release/rhg" ]; then
5 > if [ -f "$RUNTESTDIR/../rust/target/release/rhg" ]; then
6 > "$RUNTESTDIR/../rust/target/release/rhg" "$@"
6 > "$RUNTESTDIR/../rust/target/release/rhg" "$@"
7 > else
7 > else
8 > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg."
8 > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg."
9 > exit 80
9 > exit 80
10 > fi
10 > fi
11 > }
11 > }
12
12
13 Unimplemented command
13 Unimplemented command
14 $ rhg unimplemented-command
14 $ rhg unimplemented-command
15 [252]
15 [252]
16
16
17 Finding root
17 Finding root
18 $ rhg root
18 $ rhg root
19 abort: no repository found in '$TESTTMP' (.hg not found)!
19 abort: no repository found in '$TESTTMP' (.hg not found)!
20 [255]
20 [255]
21
21
22 $ hg init repository
22 $ hg init repository
23 $ cd repository
23 $ cd repository
24 $ rhg root
24 $ rhg root
25 $TESTTMP/repository
25 $TESTTMP/repository
26
26
27 Reading and setting configuration
27 Reading and setting configuration
28 $ echo "[ui]" >> $HGRCPATH
28 $ echo "[ui]" >> $HGRCPATH
29 $ echo "username = user1" >> $HGRCPATH
29 $ echo "username = user1" >> $HGRCPATH
30 $ rhg config ui.username
30 $ rhg config ui.username
31 user1
31 user1
32 $ echo "[ui]" >> .hg/hgrc
32 $ echo "[ui]" >> .hg/hgrc
33 $ echo "username = user2" >> .hg/hgrc
33 $ echo "username = user2" >> .hg/hgrc
34 $ rhg config ui.username
34 $ rhg config ui.username
35 user2
35 user2
36 $ rhg --config ui.username=user3 config ui.username
36 $ rhg --config ui.username=user3 config ui.username
37 user3
37 user3
38
38
39 Unwritable file descriptor
39 Unwritable file descriptor
40 $ rhg root > /dev/full
40 $ rhg root > /dev/full
41 abort: No space left on device (os error 28)
41 abort: No space left on device (os error 28)
42 [255]
42 [255]
43
43
44 Deleted repository
44 Deleted repository
45 $ rm -rf `pwd`
45 $ rm -rf `pwd`
46 $ rhg root
46 $ rhg root
47 abort: $ENOENT$: current directory
47 abort: $ENOENT$: current directory
48 [255]
48 [255]
49
49
50 Listing tracked files
50 Listing tracked files
51 $ cd $TESTTMP
51 $ cd $TESTTMP
52 $ hg init repository
52 $ hg init repository
53 $ cd repository
53 $ cd repository
54 $ for i in 1 2 3; do
54 $ for i in 1 2 3; do
55 > echo $i >> file$i
55 > echo $i >> file$i
56 > hg add file$i
56 > hg add file$i
57 > done
57 > done
58 > hg commit -m "commit $i" -q
58 > hg commit -m "commit $i" -q
59
59
60 Listing tracked files from root
60 Listing tracked files from root
61 $ rhg files
61 $ rhg files
62 file1
62 file1
63 file2
63 file2
64 file3
64 file3
65
65
66 Listing tracked files from subdirectory
66 Listing tracked files from subdirectory
67 $ mkdir -p path/to/directory
67 $ mkdir -p path/to/directory
68 $ cd path/to/directory
68 $ cd path/to/directory
69 $ rhg files
69 $ rhg files
70 ../../../file1
70 ../../../file1
71 ../../../file2
71 ../../../file2
72 ../../../file3
72 ../../../file3
73
73
74 Listing tracked files through broken pipe
74 Listing tracked files through broken pipe
75 $ rhg files | head -n 1
75 $ rhg files | head -n 1
76 ../../../file1
76 ../../../file1
77
77
78 Debuging data in inline index
78 Debuging data in inline index
79 $ cd $TESTTMP
79 $ cd $TESTTMP
80 $ rm -rf repository
80 $ rm -rf repository
81 $ hg init repository
81 $ hg init repository
82 $ cd repository
82 $ cd repository
83 $ for i in 1 2 3 4 5 6; do
83 $ for i in 1 2 3 4 5 6; do
84 > echo $i >> file-$i
84 > echo $i >> file-$i
85 > hg add file-$i
85 > hg add file-$i
86 > hg commit -m "Commit $i" -q
86 > hg commit -m "Commit $i" -q
87 > done
87 > done
88 $ rhg debugdata -c 2
88 $ rhg debugdata -c 2
89 8d0267cb034247ebfa5ee58ce59e22e57a492297
89 8d0267cb034247ebfa5ee58ce59e22e57a492297
90 test
90 test
91 0 0
91 0 0
92 file-3
92 file-3
93
93
94 Commit 3 (no-eol)
94 Commit 3 (no-eol)
95 $ rhg debugdata -m 2
95 $ rhg debugdata -m 2
96 file-1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
96 file-1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
97 file-2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
97 file-2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
98 file-3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
98 file-3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
99
99
100 Debuging with full node id
100 Debuging with full node id
101 $ rhg debugdata -c `hg log -r 0 -T '{node}'`
101 $ rhg debugdata -c `hg log -r 0 -T '{node}'`
102 d1d1c679d3053e8926061b6f45ca52009f011e3f
102 d1d1c679d3053e8926061b6f45ca52009f011e3f
103 test
103 test
104 0 0
104 0 0
105 file-1
105 file-1
106
106
107 Commit 1 (no-eol)
107 Commit 1 (no-eol)
108
108
109 Specifying revisions by changeset ID
109 Specifying revisions by changeset ID
110 $ hg log -T '{node}\n'
110 $ hg log -T '{node}\n'
111 c6ad58c44207b6ff8a4fbbca7045a5edaa7e908b
111 c6ad58c44207b6ff8a4fbbca7045a5edaa7e908b
112 d654274993d0149eecc3cc03214f598320211900
112 d654274993d0149eecc3cc03214f598320211900
113 f646af7e96481d3a5470b695cf30ad8e3ab6c575
113 f646af7e96481d3a5470b695cf30ad8e3ab6c575
114 cf8b83f14ead62b374b6e91a0e9303b85dfd9ed7
114 cf8b83f14ead62b374b6e91a0e9303b85dfd9ed7
115 91c6f6e73e39318534dc415ea4e8a09c99cd74d6
115 91c6f6e73e39318534dc415ea4e8a09c99cd74d6
116 6ae9681c6d30389694d8701faf24b583cf3ccafe
116 6ae9681c6d30389694d8701faf24b583cf3ccafe
117 $ rhg files -r cf8b83
117 $ rhg files -r cf8b83
118 file-1
118 file-1
119 file-2
119 file-2
120 file-3
120 file-3
121 $ rhg cat -r cf8b83 file-2
121 $ rhg cat -r cf8b83 file-2
122 2
122 2
123 $ rhg cat -r c file-2
123 $ rhg cat -r c file-2
124 abort: ambiguous revision identifier c
124 abort: ambiguous revision identifier c
125 [255]
125 [255]
126 $ rhg cat -r d file-2
126 $ rhg cat -r d file-2
127 2
127 2
128
128
129 Cat files
129 Cat files
130 $ cd $TESTTMP
130 $ cd $TESTTMP
131 $ rm -rf repository
131 $ rm -rf repository
132 $ hg init repository
132 $ hg init repository
133 $ cd repository
133 $ cd repository
134 $ echo "original content" > original
134 $ echo "original content" > original
135 $ hg add original
135 $ hg add original
136 $ hg commit -m "add original" original
136 $ hg commit -m "add original" original
137 $ rhg cat -r 0 original
137 $ rhg cat -r 0 original
138 original content
138 original content
139 Cat copied file should not display copy metadata
139 Cat copied file should not display copy metadata
140 $ hg copy original copy_of_original
140 $ hg copy original copy_of_original
141 $ hg commit -m "add copy of original"
141 $ hg commit -m "add copy of original"
142 $ rhg cat -r 1 copy_of_original
142 $ rhg cat -r 1 copy_of_original
143 original content
143 original content
144
144
145 Requirements
145 Requirements
146 $ rhg debugrequirements
146 $ rhg debugrequirements
147 dotencode
147 dotencode
148 fncache
148 fncache
149 generaldelta
149 generaldelta
150 revlogv1
150 revlogv1
151 sparserevlog
151 sparserevlog
152 store
152 store
153
153
154 $ echo indoor-pool >> .hg/requires
154 $ echo indoor-pool >> .hg/requires
155 $ rhg files
155 $ rhg files
156 [252]
156 [252]
157
157
158 $ rhg cat -r 1 copy_of_original
158 $ rhg cat -r 1 copy_of_original
159 [252]
159 [252]
160
160
161 $ rhg debugrequirements
161 $ rhg debugrequirements
162 [252]
162 [252]
163
163
164 $ echo -e '\xFF' >> .hg/requires
164 $ echo -e '\xFF' >> .hg/requires
165 $ rhg debugrequirements
165 $ rhg debugrequirements
166 abort: corrupted repository: parse error in 'requires' file
166 abort: corrupted repository: parse error in 'requires' file
167 [255]
167 [255]
168
168
169 Persistent nodemap
169 Persistent nodemap
170 $ cd $TESTTMP
170 $ cd $TESTTMP
171 $ rm -rf repository
171 $ rm -rf repository
172 $ hg init repository
172 $ hg init repository
173 $ cd repository
173 $ cd repository
174 $ rhg debugrequirements | grep nodemap
174 $ rhg debugrequirements | grep nodemap
175 [1]
175 [1]
176 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
176 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
177 $ hg id -r tip
177 $ hg id -r tip
178 c3ae8dec9fad tip
178 c3ae8dec9fad tip
179 $ ls .hg/store/00changelog*
179 $ ls .hg/store/00changelog*
180 .hg/store/00changelog.d
180 .hg/store/00changelog.d
181 .hg/store/00changelog.i
181 .hg/store/00changelog.i
182 $ rhg files -r c3ae8dec9fad
182 $ rhg files -r c3ae8dec9fad
183 of
183 of
184
184
185 $ cd $TESTTMP
185 $ cd $TESTTMP
186 $ rm -rf repository
186 $ rm -rf repository
187 $ hg --config format.use-persistent-nodemap=True init repository
187 $ hg --config format.use-persistent-nodemap=True init repository
188 $ cd repository
188 $ cd repository
189 $ rhg debugrequirements | grep nodemap
189 $ rhg debugrequirements | grep nodemap
190 persistent-nodemap
190 persistent-nodemap
191 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
191 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
192 $ hg id -r tip
192 $ hg id -r tip
193 c3ae8dec9fad tip
193 c3ae8dec9fad tip
194 $ ls .hg/store/00changelog*
194 $ ls .hg/store/00changelog*
195 .hg/store/00changelog-*.nd (glob)
195 .hg/store/00changelog-*.nd (glob)
196 .hg/store/00changelog.d
196 .hg/store/00changelog.d
197 .hg/store/00changelog.i
197 .hg/store/00changelog.i
198 .hg/store/00changelog.n
198 .hg/store/00changelog.n
199
199
200 Specifying revisions by changeset ID
200 Specifying revisions by changeset ID
201 $ rhg files -r c3ae8dec9fad
201 $ rhg files -r c3ae8dec9fad
202 of
202 of
203 $ rhg cat -r c3ae8dec9fad of
203 $ rhg cat -r c3ae8dec9fad of
204 r5000
204 r5000
205
205
206 Crate a shared repository
206 Crate a shared repository
207
207
208 $ echo "[extensions]" >> $HGRCPATH
208 $ echo "[extensions]" >> $HGRCPATH
209 $ echo "share = " >> $HGRCPATH
209 $ echo "share = " >> $HGRCPATH
210
210
211 $ cd $TESTTMP
211 $ cd $TESTTMP
212 $ hg init repo1
212 $ hg init repo1
213 $ echo a > repo1/a
213 $ echo a > repo1/a
214 $ hg -R repo1 commit -A -m'init'
214 $ hg -R repo1 commit -A -m'init'
215 adding a
215 adding a
216
216
217 $ hg share repo1 repo2
217 $ hg share repo1 repo2
218 updating working directory
218 updating working directory
219 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
220
220
221 And check that basic rhg commands work with sharing
221 And check that basic rhg commands work with sharing
222
222
223 $ rhg files -R repo2
223 $ rhg files -R repo2
224 repo2/a
224 repo2/a
225 $ rhg -R repo2 cat -r 0 repo2/a
225 $ rhg -R repo2 cat -r 0 repo2/a
226 a
226 a
227
227
228 Same with relative sharing
228 Same with relative sharing
229
229
230 $ hg share repo2 repo3 --relative
230 $ hg share repo2 repo3 --relative
231 updating working directory
231 updating working directory
232 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
233
233
234 $ rhg files -R repo3
234 $ rhg files -R repo3
235 repo3/a
235 repo3/a
236 $ rhg -R repo3 cat -r 0 repo3/a
236 $ rhg -R repo3 cat -r 0 repo3/a
237 a
237 a
238
238
239 Same with share-safe
239 Same with share-safe
240
240
241 $ echo "[format]" >> $HGRCPATH
241 $ echo "[format]" >> $HGRCPATH
242 $ echo "use-share-safe = True" >> $HGRCPATH
242 $ echo "use-share-safe = True" >> $HGRCPATH
243
243
244 $ cd $TESTTMP
244 $ cd $TESTTMP
245 $ hg init repo4
245 $ hg init repo4
246 $ cd repo4
246 $ cd repo4
247 $ echo a > a
247 $ echo a > a
248 $ hg commit -A -m'init'
248 $ hg commit -A -m'init'
249 adding a
249 adding a
250
250
251 $ cd ..
251 $ cd ..
252 $ hg share repo4 repo5
252 $ hg share repo4 repo5
253 updating working directory
253 updating working directory
254 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
255
255
256 And check that basic rhg commands work with sharing
256 And check that basic rhg commands work with sharing
257
257
258 $ cd repo5
258 $ cd repo5
259 $ rhg files
259 $ rhg files
260 a
260 a
261 $ rhg cat -r 0 a
261 $ rhg cat -r 0 a
262 a
262 a
263
263
264 The blackbox extension is supported
265
266 $ echo "[extensions]" >> $HGRCPATH
267 $ echo "blackbox =" >> $HGRCPATH
268 $ echo "[blackbox]" >> $HGRCPATH
269 $ echo "maxsize = 1" >> $HGRCPATH
270 $ rhg files > /dev/null
271 $ cat .hg/blackbox.log
272 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files exited 0 after 0.??? seconds (glob)
273 $ cat .hg/blackbox.log.1
274 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files (glob)
275
General Comments 0
You need to be logged in to leave comments. Login now