##// END OF EJS Templates
rhg: Remove `rhg.fallback-executable=hg` default configuration...
Simon Sapin -
r47482:bde90e9b default
parent child Browse files
Show More
@@ -1,443 +1,455 b''
1 1 extern crate log;
2 2 use crate::ui::Ui;
3 3 use clap::App;
4 4 use clap::AppSettings;
5 5 use clap::Arg;
6 6 use clap::ArgMatches;
7 7 use format_bytes::{format_bytes, join};
8 8 use hg::config::Config;
9 9 use hg::repo::{Repo, RepoError};
10 10 use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes};
11 11 use hg::utils::SliceExt;
12 12 use std::ffi::OsString;
13 13 use std::path::PathBuf;
14 14 use std::process::Command;
15 15
16 16 mod blackbox;
17 17 mod error;
18 18 mod exitcode;
19 19 mod ui;
20 20 use error::CommandError;
21 21
22 22 fn main_with_result(
23 23 process_start_time: &blackbox::ProcessStartTime,
24 24 ui: &ui::Ui,
25 25 repo: Result<&Repo, &NoRepoInCwdError>,
26 26 config: &Config,
27 27 ) -> Result<(), CommandError> {
28 28 check_extensions(config)?;
29 29
30 30 let app = App::new("rhg")
31 31 .global_setting(AppSettings::AllowInvalidUtf8)
32 32 .global_setting(AppSettings::DisableVersion)
33 33 .setting(AppSettings::SubcommandRequired)
34 34 .setting(AppSettings::VersionlessSubcommands)
35 35 .arg(
36 36 Arg::with_name("repository")
37 37 .help("repository root directory")
38 38 .short("-R")
39 39 .long("--repository")
40 40 .value_name("REPO")
41 41 .takes_value(true)
42 42 // Both ok: `hg -R ./foo log` or `hg log -R ./foo`
43 43 .global(true),
44 44 )
45 45 .arg(
46 46 Arg::with_name("config")
47 47 .help("set/override config option (use 'section.name=value')")
48 48 .long("--config")
49 49 .value_name("CONFIG")
50 50 .takes_value(true)
51 51 .global(true)
52 52 // Ok: `--config section.key1=val --config section.key2=val2`
53 53 .multiple(true)
54 54 // Not ok: `--config section.key1=val section.key2=val2`
55 55 .number_of_values(1),
56 56 )
57 57 .arg(
58 58 Arg::with_name("cwd")
59 59 .help("change working directory")
60 60 .long("--cwd")
61 61 .value_name("DIR")
62 62 .takes_value(true)
63 63 .global(true),
64 64 )
65 65 .version("0.0.1");
66 66 let app = add_subcommand_args(app);
67 67
68 68 let matches = app.clone().get_matches_safe()?;
69 69
70 70 let (subcommand_name, subcommand_matches) = matches.subcommand();
71 71 let run = subcommand_run_fn(subcommand_name)
72 72 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
73 73 let subcommand_args = subcommand_matches
74 74 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
75 75
76 76 let invocation = CliInvocation {
77 77 ui,
78 78 subcommand_args,
79 79 config,
80 80 repo,
81 81 };
82 82 let blackbox = blackbox::Blackbox::new(&invocation, process_start_time)?;
83 83 blackbox.log_command_start();
84 84 let result = run(&invocation);
85 85 blackbox.log_command_end(exit_code(&result));
86 86 result
87 87 }
88 88
89 89 fn main() {
90 90 // Run this first, before we find out if the blackbox extension is even
91 91 // enabled, in order to include everything in-between in the duration
92 92 // measurements. Reading config files can be slow if they’re on NFS.
93 93 let process_start_time = blackbox::ProcessStartTime::now();
94 94
95 95 env_logger::init();
96 96 let ui = ui::Ui::new();
97 97
98 98 let early_args = EarlyArgs::parse(std::env::args_os());
99 99
100 100 let initial_current_dir = early_args.cwd.map(|cwd| {
101 101 let cwd = get_path_from_bytes(&cwd);
102 102 std::env::current_dir()
103 103 .and_then(|initial| {
104 104 std::env::set_current_dir(cwd)?;
105 105 Ok(initial)
106 106 })
107 107 .unwrap_or_else(|error| {
108 108 exit(
109 109 &None,
110 110 &ui,
111 111 OnUnsupported::Abort,
112 112 Err(CommandError::abort(format!(
113 113 "abort: {}: '{}'",
114 114 error,
115 115 cwd.display()
116 116 ))),
117 117 )
118 118 })
119 119 });
120 120
121 121 let non_repo_config =
122 122 Config::load(early_args.config).unwrap_or_else(|error| {
123 123 // Normally this is decided based on config, but we don’t have that
124 124 // available. As of this writing config loading never returns an
125 125 // "unsupported" error but that is not enforced by the type system.
126 126 let on_unsupported = OnUnsupported::Abort;
127 127
128 128 exit(&initial_current_dir, &ui, on_unsupported, Err(error.into()))
129 129 });
130 130
131 131 if let Some(repo_path_bytes) = &early_args.repo {
132 132 lazy_static::lazy_static! {
133 133 static ref SCHEME_RE: regex::bytes::Regex =
134 134 // Same as `_matchscheme` in `mercurial/util.py`
135 135 regex::bytes::Regex::new("^[a-zA-Z0-9+.\\-]+:").unwrap();
136 136 }
137 137 if SCHEME_RE.is_match(&repo_path_bytes) {
138 138 exit(
139 139 &initial_current_dir,
140 140 &ui,
141 OnUnsupported::from_config(&non_repo_config),
141 OnUnsupported::from_config(&ui, &non_repo_config),
142 142 Err(CommandError::UnsupportedFeature {
143 143 message: format_bytes!(
144 144 b"URL-like --repository {}",
145 145 repo_path_bytes
146 146 ),
147 147 }),
148 148 )
149 149 }
150 150 }
151 151 let repo_path = early_args.repo.as_deref().map(get_path_from_bytes);
152 152 let repo_result = match Repo::find(&non_repo_config, repo_path) {
153 153 Ok(repo) => Ok(repo),
154 154 Err(RepoError::NotFound { at }) if repo_path.is_none() => {
155 155 // Not finding a repo is not fatal yet, if `-R` was not given
156 156 Err(NoRepoInCwdError { cwd: at })
157 157 }
158 158 Err(error) => exit(
159 159 &initial_current_dir,
160 160 &ui,
161 OnUnsupported::from_config(&non_repo_config),
161 OnUnsupported::from_config(&ui, &non_repo_config),
162 162 Err(error.into()),
163 163 ),
164 164 };
165 165
166 166 let config = if let Ok(repo) = &repo_result {
167 167 repo.config()
168 168 } else {
169 169 &non_repo_config
170 170 };
171 let on_unsupported = OnUnsupported::from_config(&ui, config);
171 172
172 173 let result = main_with_result(
173 174 &process_start_time,
174 175 &ui,
175 176 repo_result.as_ref(),
176 177 config,
177 178 );
178 exit(
179 &initial_current_dir,
180 &ui,
181 OnUnsupported::from_config(config),
182 result,
183 )
179 exit(&initial_current_dir, &ui, on_unsupported, result)
184 180 }
185 181
186 182 fn exit_code(result: &Result<(), CommandError>) -> i32 {
187 183 match result {
188 184 Ok(()) => exitcode::OK,
189 185 Err(CommandError::Abort { .. }) => exitcode::ABORT,
190 186 Err(CommandError::Unsuccessful) => exitcode::UNSUCCESSFUL,
191 187
192 188 // Exit with a specific code and no error message to let a potential
193 189 // wrapper script fallback to Python-based Mercurial.
194 190 Err(CommandError::UnsupportedFeature { .. }) => {
195 191 exitcode::UNIMPLEMENTED
196 192 }
197 193 }
198 194 }
199 195
200 196 fn exit(
201 197 initial_current_dir: &Option<PathBuf>,
202 198 ui: &Ui,
203 199 mut on_unsupported: OnUnsupported,
204 200 result: Result<(), CommandError>,
205 201 ) -> ! {
206 202 if let (
207 203 OnUnsupported::Fallback { executable },
208 204 Err(CommandError::UnsupportedFeature { .. }),
209 205 ) = (&on_unsupported, &result)
210 206 {
211 207 let mut args = std::env::args_os();
212 208 let executable_path = get_path_from_bytes(&executable);
213 209 let this_executable = args.next().expect("exepcted argv[0] to exist");
214 210 if executable_path == &PathBuf::from(this_executable) {
215 211 // Avoid spawning infinitely many processes until resource
216 212 // exhaustion.
217 213 let _ = ui.write_stderr(&format_bytes!(
218 214 b"Blocking recursive fallback. The 'rhg.fallback-executable = {}' config \
219 215 points to `rhg` itself.\n",
220 216 executable
221 217 ));
222 218 on_unsupported = OnUnsupported::Abort
223 219 } else {
224 220 // `args` is now `argv[1..]` since we’ve already consumed `argv[0]`
225 221 let mut command = Command::new(executable_path);
226 222 command.args(args);
227 223 if let Some(initial) = initial_current_dir {
228 224 command.current_dir(initial);
229 225 }
230 226 let result = command.status();
231 227 match result {
232 228 Ok(status) => std::process::exit(
233 229 status.code().unwrap_or(exitcode::ABORT),
234 230 ),
235 231 Err(error) => {
236 232 let _ = ui.write_stderr(&format_bytes!(
237 233 b"tried to fall back to a '{}' sub-process but got error {}\n",
238 234 executable, format_bytes::Utf8(error)
239 235 ));
240 236 on_unsupported = OnUnsupported::Abort
241 237 }
242 238 }
243 239 }
244 240 }
241 exit_no_fallback(ui, on_unsupported, result)
242 }
243
244 fn exit_no_fallback(
245 ui: &Ui,
246 on_unsupported: OnUnsupported,
247 result: Result<(), CommandError>,
248 ) -> ! {
245 249 match &result {
246 250 Ok(_) => {}
247 251 Err(CommandError::Unsuccessful) => {}
248 252 Err(CommandError::Abort { message }) => {
249 253 if !message.is_empty() {
250 254 // Ignore errors when writing to stderr, we’re already exiting
251 255 // with failure code so there’s not much more we can do.
252 256 let _ = ui.write_stderr(&format_bytes!(b"{}\n", message));
253 257 }
254 258 }
255 259 Err(CommandError::UnsupportedFeature { message }) => {
256 260 match on_unsupported {
257 261 OnUnsupported::Abort => {
258 262 let _ = ui.write_stderr(&format_bytes!(
259 263 b"unsupported feature: {}\n",
260 264 message
261 265 ));
262 266 }
263 267 OnUnsupported::AbortSilent => {}
264 268 OnUnsupported::Fallback { .. } => unreachable!(),
265 269 }
266 270 }
267 271 }
268 272 std::process::exit(exit_code(&result))
269 273 }
270 274
271 275 macro_rules! subcommands {
272 276 ($( $command: ident )+) => {
273 277 mod commands {
274 278 $(
275 279 pub mod $command;
276 280 )+
277 281 }
278 282
279 283 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
280 284 app
281 285 $(
282 286 .subcommand(commands::$command::args())
283 287 )+
284 288 }
285 289
286 290 pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>;
287 291
288 292 fn subcommand_run_fn(name: &str) -> Option<RunFn> {
289 293 match name {
290 294 $(
291 295 stringify!($command) => Some(commands::$command::run),
292 296 )+
293 297 _ => None,
294 298 }
295 299 }
296 300 };
297 301 }
298 302
299 303 subcommands! {
300 304 cat
301 305 debugdata
302 306 debugrequirements
303 307 files
304 308 root
305 309 config
306 310 }
307 311 pub struct CliInvocation<'a> {
308 312 ui: &'a Ui,
309 313 subcommand_args: &'a ArgMatches<'a>,
310 314 config: &'a Config,
311 315 /// References inside `Result` is a bit peculiar but allow
312 316 /// `invocation.repo?` to work out with `&CliInvocation` since this
313 317 /// `Result` type is `Copy`.
314 318 repo: Result<&'a Repo, &'a NoRepoInCwdError>,
315 319 }
316 320
317 321 struct NoRepoInCwdError {
318 322 cwd: PathBuf,
319 323 }
320 324
321 325 /// CLI arguments to be parsed "early" in order to be able to read
322 326 /// configuration before using Clap. Ideally we would also use Clap for this,
323 327 /// see <https://github.com/clap-rs/clap/discussions/2366>.
324 328 ///
325 329 /// These arguments are still declared when we do use Clap later, so that Clap
326 330 /// does not return an error for their presence.
327 331 struct EarlyArgs {
328 332 /// Values of all `--config` arguments. (Possibly none)
329 333 config: Vec<Vec<u8>>,
330 334 /// Value of the `-R` or `--repository` argument, if any.
331 335 repo: Option<Vec<u8>>,
332 336 /// Value of the `--cwd` argument, if any.
333 337 cwd: Option<Vec<u8>>,
334 338 }
335 339
336 340 impl EarlyArgs {
337 341 fn parse(args: impl IntoIterator<Item = OsString>) -> Self {
338 342 let mut args = args.into_iter().map(get_bytes_from_os_str);
339 343 let mut config = Vec::new();
340 344 let mut repo = None;
341 345 let mut cwd = None;
342 346 // Use `while let` instead of `for` so that we can also call
343 347 // `args.next()` inside the loop.
344 348 while let Some(arg) = args.next() {
345 349 if arg == b"--config" {
346 350 if let Some(value) = args.next() {
347 351 config.push(value)
348 352 }
349 353 } else if let Some(value) = arg.drop_prefix(b"--config=") {
350 354 config.push(value.to_owned())
351 355 }
352 356
353 357 if arg == b"--cwd" {
354 358 if let Some(value) = args.next() {
355 359 cwd = Some(value)
356 360 }
357 361 } else if let Some(value) = arg.drop_prefix(b"--cwd=") {
358 362 cwd = Some(value.to_owned())
359 363 }
360 364
361 365 if arg == b"--repository" || arg == b"-R" {
362 366 if let Some(value) = args.next() {
363 367 repo = Some(value)
364 368 }
365 369 } else if let Some(value) = arg.drop_prefix(b"--repository=") {
366 370 repo = Some(value.to_owned())
367 371 } else if let Some(value) = arg.drop_prefix(b"-R") {
368 372 repo = Some(value.to_owned())
369 373 }
370 374 }
371 375 Self { config, repo, cwd }
372 376 }
373 377 }
374 378
375 379 /// What to do when encountering some unsupported feature.
376 380 ///
377 381 /// See `HgError::UnsupportedFeature` and `CommandError::UnsupportedFeature`.
378 382 enum OnUnsupported {
379 383 /// Print an error message describing what feature is not supported,
380 384 /// and exit with code 252.
381 385 Abort,
382 386 /// Silently exit with code 252.
383 387 AbortSilent,
384 388 /// Try running a Python implementation
385 389 Fallback { executable: Vec<u8> },
386 390 }
387 391
388 392 impl OnUnsupported {
389 393 const DEFAULT: Self = OnUnsupported::Abort;
390 const DEFAULT_FALLBACK_EXECUTABLE: &'static [u8] = b"hg";
391 394
392 fn from_config(config: &Config) -> Self {
395 fn from_config(ui: &Ui, config: &Config) -> Self {
393 396 match config
394 397 .get(b"rhg", b"on-unsupported")
395 398 .map(|value| value.to_ascii_lowercase())
396 399 .as_deref()
397 400 {
398 401 Some(b"abort") => OnUnsupported::Abort,
399 402 Some(b"abort-silent") => OnUnsupported::AbortSilent,
400 403 Some(b"fallback") => OnUnsupported::Fallback {
401 404 executable: config
402 405 .get(b"rhg", b"fallback-executable")
403 .unwrap_or(Self::DEFAULT_FALLBACK_EXECUTABLE)
406 .unwrap_or_else(|| {
407 exit_no_fallback(
408 ui,
409 Self::Abort,
410 Err(CommandError::abort(
411 "abort: 'rhg.on-unsupported=fallback' without \
412 'rhg.fallback-executable' set."
413 )),
414 )
415 })
404 416 .to_owned(),
405 417 },
406 418 None => Self::DEFAULT,
407 419 Some(_) => {
408 420 // TODO: warn about unknown config value
409 421 Self::DEFAULT
410 422 }
411 423 }
412 424 }
413 425 }
414 426
415 427 const SUPPORTED_EXTENSIONS: &[&[u8]] = &[b"blackbox", b"share"];
416 428
417 429 fn check_extensions(config: &Config) -> Result<(), CommandError> {
418 430 let enabled = config.get_section_keys(b"extensions");
419 431
420 432 let mut unsupported = enabled;
421 433 for supported in SUPPORTED_EXTENSIONS {
422 434 unsupported.remove(supported);
423 435 }
424 436
425 437 if let Some(ignored_list) =
426 438 config.get_simple_list(b"rhg", b"ignored-extensions")
427 439 {
428 440 for ignored in ignored_list {
429 441 unsupported.remove(ignored);
430 442 }
431 443 }
432 444
433 445 if unsupported.is_empty() {
434 446 Ok(())
435 447 } else {
436 448 Err(CommandError::UnsupportedFeature {
437 449 message: format_bytes!(
438 450 b"extensions: {} (consider adding them to 'rhg.ignored-extensions' config)",
439 451 join(unsupported, b", ")
440 452 ),
441 453 })
442 454 }
443 455 }
@@ -1,299 +1,307 b''
1 1 #require rhg
2 2
3 3 $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort"
4 4
5 5 Unimplemented command
6 6 $ $NO_FALLBACK rhg unimplemented-command
7 7 unsupported feature: error: Found argument 'unimplemented-command' which wasn't expected, or isn't valid in this context
8 8
9 9 USAGE:
10 10 rhg [OPTIONS] <SUBCOMMAND>
11 11
12 12 For more information try --help
13 13
14 14 [252]
15 15 $ rhg unimplemented-command --config rhg.on-unsupported=abort-silent
16 16 [252]
17 17
18 18 Finding root
19 19 $ $NO_FALLBACK rhg root
20 20 abort: no repository found in '$TESTTMP' (.hg not found)!
21 21 [255]
22 22
23 23 $ hg init repository
24 24 $ cd repository
25 25 $ $NO_FALLBACK rhg root
26 26 $TESTTMP/repository
27 27
28 28 Reading and setting configuration
29 29 $ echo "[ui]" >> $HGRCPATH
30 30 $ echo "username = user1" >> $HGRCPATH
31 31 $ $NO_FALLBACK rhg config ui.username
32 32 user1
33 33 $ echo "[ui]" >> .hg/hgrc
34 34 $ echo "username = user2" >> .hg/hgrc
35 35 $ $NO_FALLBACK rhg config ui.username
36 36 user2
37 37 $ $NO_FALLBACK rhg --config ui.username=user3 config ui.username
38 38 user3
39 39
40 40 Unwritable file descriptor
41 41 $ $NO_FALLBACK rhg root > /dev/full
42 42 abort: No space left on device (os error 28)
43 43 [255]
44 44
45 45 Deleted repository
46 46 $ rm -rf `pwd`
47 47 $ $NO_FALLBACK rhg root
48 48 abort: error getting current working directory: $ENOENT$
49 49 [255]
50 50
51 51 Listing tracked files
52 52 $ cd $TESTTMP
53 53 $ hg init repository
54 54 $ cd repository
55 55 $ for i in 1 2 3; do
56 56 > echo $i >> file$i
57 57 > hg add file$i
58 58 > done
59 59 > hg commit -m "commit $i" -q
60 60
61 61 Listing tracked files from root
62 62 $ $NO_FALLBACK rhg files
63 63 file1
64 64 file2
65 65 file3
66 66
67 67 Listing tracked files from subdirectory
68 68 $ mkdir -p path/to/directory
69 69 $ cd path/to/directory
70 70 $ $NO_FALLBACK rhg files
71 71 ../../../file1
72 72 ../../../file2
73 73 ../../../file3
74 74
75 75 Listing tracked files through broken pipe
76 76 $ $NO_FALLBACK rhg files | head -n 1
77 77 ../../../file1
78 78
79 79 Debuging data in inline index
80 80 $ cd $TESTTMP
81 81 $ rm -rf repository
82 82 $ hg init repository
83 83 $ cd repository
84 84 $ for i in 1 2 3 4 5 6; do
85 85 > echo $i >> file-$i
86 86 > hg add file-$i
87 87 > hg commit -m "Commit $i" -q
88 88 > done
89 89 $ $NO_FALLBACK rhg debugdata -c 2
90 90 8d0267cb034247ebfa5ee58ce59e22e57a492297
91 91 test
92 92 0 0
93 93 file-3
94 94
95 95 Commit 3 (no-eol)
96 96 $ $NO_FALLBACK rhg debugdata -m 2
97 97 file-1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
98 98 file-2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
99 99 file-3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
100 100
101 101 Debuging with full node id
102 102 $ $NO_FALLBACK rhg debugdata -c `hg log -r 0 -T '{node}'`
103 103 d1d1c679d3053e8926061b6f45ca52009f011e3f
104 104 test
105 105 0 0
106 106 file-1
107 107
108 108 Commit 1 (no-eol)
109 109
110 110 Specifying revisions by changeset ID
111 111 $ hg log -T '{node}\n'
112 112 c6ad58c44207b6ff8a4fbbca7045a5edaa7e908b
113 113 d654274993d0149eecc3cc03214f598320211900
114 114 f646af7e96481d3a5470b695cf30ad8e3ab6c575
115 115 cf8b83f14ead62b374b6e91a0e9303b85dfd9ed7
116 116 91c6f6e73e39318534dc415ea4e8a09c99cd74d6
117 117 6ae9681c6d30389694d8701faf24b583cf3ccafe
118 118 $ $NO_FALLBACK rhg files -r cf8b83
119 119 file-1
120 120 file-2
121 121 file-3
122 122 $ $NO_FALLBACK rhg cat -r cf8b83 file-2
123 123 2
124 124 $ $NO_FALLBACK rhg cat -r c file-2
125 125 abort: ambiguous revision identifier: c
126 126 [255]
127 127 $ $NO_FALLBACK rhg cat -r d file-2
128 128 2
129 129
130 130 Cat files
131 131 $ cd $TESTTMP
132 132 $ rm -rf repository
133 133 $ hg init repository
134 134 $ cd repository
135 135 $ echo "original content" > original
136 136 $ hg add original
137 137 $ hg commit -m "add original" original
138 138 $ $NO_FALLBACK rhg cat -r 0 original
139 139 original content
140 140 Cat copied file should not display copy metadata
141 141 $ hg copy original copy_of_original
142 142 $ hg commit -m "add copy of original"
143 143 $ $NO_FALLBACK rhg cat -r 1 copy_of_original
144 144 original content
145 145
146 146 Fallback to Python
147 147 $ $NO_FALLBACK rhg cat original
148 148 unsupported feature: `rhg cat` without `--rev` / `-r`
149 149 [252]
150 150 $ rhg cat original
151 151 original content
152 152
153 $ FALLBACK_EXE="$RHG_FALLBACK_EXECUTABLE"
154 $ unset RHG_FALLBACK_EXECUTABLE
155 $ rhg cat original
156 abort: 'rhg.on-unsupported=fallback' without 'rhg.fallback-executable' set.
157 [255]
158 $ RHG_FALLBACK_EXECUTABLE="$FALLBACK_EXE"
159 $ export RHG_FALLBACK_EXECUTABLE
160
153 161 $ rhg cat original --config rhg.fallback-executable=false
154 162 [1]
155 163
156 164 $ rhg cat original --config rhg.fallback-executable=hg-non-existent
157 165 tried to fall back to a 'hg-non-existent' sub-process but got error $ENOENT$
158 166 unsupported feature: `rhg cat` without `--rev` / `-r`
159 167 [252]
160 168
161 169 $ rhg cat original --config rhg.fallback-executable=rhg
162 170 Blocking recursive fallback. The 'rhg.fallback-executable = rhg' config points to `rhg` itself.
163 171 unsupported feature: `rhg cat` without `--rev` / `-r`
164 172 [252]
165 173
166 174 Requirements
167 175 $ $NO_FALLBACK rhg debugrequirements
168 176 dotencode
169 177 fncache
170 178 generaldelta
171 179 revlogv1
172 180 sparserevlog
173 181 store
174 182
175 183 $ echo indoor-pool >> .hg/requires
176 184 $ $NO_FALLBACK rhg files
177 185 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
178 186 [252]
179 187
180 188 $ $NO_FALLBACK rhg cat -r 1 copy_of_original
181 189 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
182 190 [252]
183 191
184 192 $ $NO_FALLBACK rhg debugrequirements
185 193 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
186 194 [252]
187 195
188 196 $ echo -e '\xFF' >> .hg/requires
189 197 $ $NO_FALLBACK rhg debugrequirements
190 198 abort: parse error in 'requires' file
191 199 [255]
192 200
193 201 Persistent nodemap
194 202 $ cd $TESTTMP
195 203 $ rm -rf repository
196 204 $ hg init repository
197 205 $ cd repository
198 206 $ $NO_FALLBACK rhg debugrequirements | grep nodemap
199 207 [1]
200 208 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
201 209 $ hg id -r tip
202 210 c3ae8dec9fad tip
203 211 $ ls .hg/store/00changelog*
204 212 .hg/store/00changelog.d
205 213 .hg/store/00changelog.i
206 214 $ $NO_FALLBACK rhg files -r c3ae8dec9fad
207 215 of
208 216
209 217 $ cd $TESTTMP
210 218 $ rm -rf repository
211 219 $ hg --config format.use-persistent-nodemap=True init repository
212 220 $ cd repository
213 221 $ $NO_FALLBACK rhg debugrequirements | grep nodemap
214 222 persistent-nodemap
215 223 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
216 224 $ hg id -r tip
217 225 c3ae8dec9fad tip
218 226 $ ls .hg/store/00changelog*
219 227 .hg/store/00changelog-*.nd (glob)
220 228 .hg/store/00changelog.d
221 229 .hg/store/00changelog.i
222 230 .hg/store/00changelog.n
223 231
224 232 Specifying revisions by changeset ID
225 233 $ $NO_FALLBACK rhg files -r c3ae8dec9fad
226 234 of
227 235 $ $NO_FALLBACK rhg cat -r c3ae8dec9fad of
228 236 r5000
229 237
230 238 Crate a shared repository
231 239
232 240 $ echo "[extensions]" >> $HGRCPATH
233 241 $ echo "share = " >> $HGRCPATH
234 242
235 243 $ cd $TESTTMP
236 244 $ hg init repo1
237 245 $ echo a > repo1/a
238 246 $ hg -R repo1 commit -A -m'init'
239 247 adding a
240 248
241 249 $ hg share repo1 repo2
242 250 updating working directory
243 251 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 252
245 253 And check that basic rhg commands work with sharing
246 254
247 255 $ $NO_FALLBACK rhg files -R repo2
248 256 repo2/a
249 257 $ $NO_FALLBACK rhg -R repo2 cat -r 0 repo2/a
250 258 a
251 259
252 260 Same with relative sharing
253 261
254 262 $ hg share repo2 repo3 --relative
255 263 updating working directory
256 264 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
257 265
258 266 $ $NO_FALLBACK rhg files -R repo3
259 267 repo3/a
260 268 $ $NO_FALLBACK rhg -R repo3 cat -r 0 repo3/a
261 269 a
262 270
263 271 Same with share-safe
264 272
265 273 $ echo "[format]" >> $HGRCPATH
266 274 $ echo "use-share-safe = True" >> $HGRCPATH
267 275
268 276 $ cd $TESTTMP
269 277 $ hg init repo4
270 278 $ cd repo4
271 279 $ echo a > a
272 280 $ hg commit -A -m'init'
273 281 adding a
274 282
275 283 $ cd ..
276 284 $ hg share repo4 repo5
277 285 updating working directory
278 286 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
279 287
280 288 And check that basic rhg commands work with sharing
281 289
282 290 $ cd repo5
283 291 $ $NO_FALLBACK rhg files
284 292 a
285 293 $ $NO_FALLBACK rhg cat -r 0 a
286 294 a
287 295
288 296 The blackbox extension is supported
289 297
290 298 $ echo "[extensions]" >> $HGRCPATH
291 299 $ echo "blackbox =" >> $HGRCPATH
292 300 $ echo "[blackbox]" >> $HGRCPATH
293 301 $ echo "maxsize = 1" >> $HGRCPATH
294 302 $ $NO_FALLBACK rhg files > /dev/null
295 303 $ cat .hg/blackbox.log
296 304 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files exited 0 after 0.??? seconds (glob)
297 305 $ cat .hg/blackbox.log.1
298 306 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files (glob)
299 307
General Comments 0
You need to be logged in to leave comments. Login now