Show More
@@ -505,9 +505,9 b' checksum = "e2abad23fbc42b3700f2f279844d' | |||||
505 |
|
505 | |||
506 | [[package]] |
|
506 | [[package]] | |
507 | name = "libc" |
|
507 | name = "libc" | |
508 |
version = "0.2. |
|
508 | version = "0.2.124" | |
509 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
509 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
510 | checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" |
|
510 | checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" | |
511 |
|
511 | |||
512 | [[package]] |
|
512 | [[package]] | |
513 | name = "libm" |
|
513 | name = "libm" | |
@@ -949,6 +949,7 b' dependencies = [' | |||||
949 | "micro-timer", |
|
949 | "micro-timer", | |
950 | "regex", |
|
950 | "regex", | |
951 | "users", |
|
951 | "users", | |
|
952 | "which", | |||
952 | ] |
|
953 | ] | |
953 |
|
954 | |||
954 | [[package]] |
|
955 | [[package]] | |
@@ -1151,6 +1152,17 b' source = "registry+https://github.com/ru' | |||||
1151 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" |
|
1152 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" | |
1152 |
|
1153 | |||
1153 | [[package]] |
|
1154 | [[package]] | |
|
1155 | name = "which" | |||
|
1156 | version = "4.2.5" | |||
|
1157 | source = "registry+https://github.com/rust-lang/crates.io-index" | |||
|
1158 | checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" | |||
|
1159 | dependencies = [ | |||
|
1160 | "either", | |||
|
1161 | "lazy_static", | |||
|
1162 | "libc", | |||
|
1163 | ] | |||
|
1164 | ||||
|
1165 | [[package]] | |||
1154 | name = "winapi" |
|
1166 | name = "winapi" | |
1155 | version = "0.3.9" |
|
1167 | version = "0.3.9" | |
1156 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1168 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -17,3 +17,6 b' pub const UNSUCCESSFUL: ExitCode = 1;' | |||||
17 |
|
17 | |||
18 | /// Command or feature not implemented by rhg |
|
18 | /// Command or feature not implemented by rhg | |
19 | pub const UNIMPLEMENTED: ExitCode = 252; |
|
19 | pub const UNIMPLEMENTED: ExitCode = 252; | |
|
20 | ||||
|
21 | /// The fallback path is not valid | |||
|
22 | pub const INVALID_FALLBACK: ExitCode = 253; |
@@ -21,3 +21,4 b' regex = "1.3.9"' | |||||
21 | env_logger = "0.7.1" |
|
21 | env_logger = "0.7.1" | |
22 | format-bytes = "0.3.0" |
|
22 | format-bytes = "0.3.0" | |
23 | users = "0.11.0" |
|
23 | users = "0.11.0" | |
|
24 | which = "4.2.5" |
@@ -29,6 +29,9 b' pub enum CommandError {' | |||||
29 | /// `rhg` may attempt to silently fall back to Python-based `hg`, which |
|
29 | /// `rhg` may attempt to silently fall back to Python-based `hg`, which | |
30 | /// may or may not support this feature. |
|
30 | /// may or may not support this feature. | |
31 | UnsupportedFeature { message: Vec<u8> }, |
|
31 | UnsupportedFeature { message: Vec<u8> }, | |
|
32 | /// The fallback executable does not exist (or has some other problem if | |||
|
33 | /// we end up being more precise about broken fallbacks). | |||
|
34 | InvalidFallback { path: Vec<u8>, err: String }, | |||
32 | } |
|
35 | } | |
33 |
|
36 | |||
34 | impl CommandError { |
|
37 | impl CommandError { |
@@ -13,6 +13,7 b' use hg::utils::files::{get_bytes_from_os' | |||||
13 | use hg::utils::SliceExt; |
|
13 | use hg::utils::SliceExt; | |
14 | use std::collections::HashSet; |
|
14 | use std::collections::HashSet; | |
15 | use std::ffi::OsString; |
|
15 | use std::ffi::OsString; | |
|
16 | use std::os::unix::prelude::CommandExt; | |||
16 | use std::path::PathBuf; |
|
17 | use std::path::PathBuf; | |
17 | use std::process::Command; |
|
18 | use std::process::Command; | |
18 |
|
19 | |||
@@ -365,12 +366,14 b' fn exit_code(' | |||||
365 | } |
|
366 | } | |
366 | } |
|
367 | } | |
367 | Err(CommandError::Unsuccessful) => exit_codes::UNSUCCESSFUL, |
|
368 | Err(CommandError::Unsuccessful) => exit_codes::UNSUCCESSFUL, | |
368 |
|
||||
369 | // Exit with a specific code and no error message to let a potential |
|
369 | // Exit with a specific code and no error message to let a potential | |
370 | // wrapper script fallback to Python-based Mercurial. |
|
370 | // wrapper script fallback to Python-based Mercurial. | |
371 | Err(CommandError::UnsupportedFeature { .. }) => { |
|
371 | Err(CommandError::UnsupportedFeature { .. }) => { | |
372 | exit_codes::UNIMPLEMENTED |
|
372 | exit_codes::UNIMPLEMENTED | |
373 | } |
|
373 | } | |
|
374 | Err(CommandError::InvalidFallback { .. }) => { | |||
|
375 | exit_codes::INVALID_FALLBACK | |||
|
376 | } | |||
374 | } |
|
377 | } | |
375 | } |
|
378 | } | |
376 |
|
379 | |||
@@ -415,6 +418,17 b' fn exit(' | |||||
415 | } else { |
|
418 | } else { | |
416 | log::debug!("falling back (see trace-level log)"); |
|
419 | log::debug!("falling back (see trace-level log)"); | |
417 | log::trace!("{}", local_to_utf8(message)); |
|
420 | log::trace!("{}", local_to_utf8(message)); | |
|
421 | if let Err(err) = which::which(executable_path) { | |||
|
422 | exit_no_fallback( | |||
|
423 | ui, | |||
|
424 | OnUnsupported::Abort, | |||
|
425 | Err(CommandError::InvalidFallback { | |||
|
426 | path: executable.to_owned(), | |||
|
427 | err: err.to_string(), | |||
|
428 | }), | |||
|
429 | use_detailed_exit_code, | |||
|
430 | ) | |||
|
431 | } | |||
418 | // `args` is now `argv[1..]` since we’ve already consumed |
|
432 | // `args` is now `argv[1..]` since we’ve already consumed | |
419 | // `argv[0]` |
|
433 | // `argv[0]` | |
420 | let mut command = Command::new(executable_path); |
|
434 | let mut command = Command::new(executable_path); | |
@@ -422,19 +436,19 b' fn exit(' | |||||
422 | if let Some(initial) = initial_current_dir { |
|
436 | if let Some(initial) = initial_current_dir { | |
423 | command.current_dir(initial); |
|
437 | command.current_dir(initial); | |
424 | } |
|
438 | } | |
425 | let result = command.status(); |
|
439 | // We don't use subprocess because proper signal handling is harder | |
426 | match result { |
|
440 | // and we don't want to keep `rhg` around after a fallback anyway. | |
427 | Ok(status) => std::process::exit( |
|
441 | // For example, if `rhg` is run in the background and falls back to | |
428 | status.code().unwrap_or(exit_codes::ABORT), |
|
442 | // `hg` which, in turn, waits for a signal, we'll get stuck if | |
429 | ), |
|
443 | // we're doing plain subprocess. | |
430 | Err(error) => { |
|
444 | // | |
431 | let _ = ui.write_stderr(&format_bytes!( |
|
445 | // If `exec` returns, we can only assume our process is very broken | |
432 | b"tried to fall back to a '{}' sub-process but got error {}\n", |
|
446 | // (see its documentation), so only try to forward the error code | |
433 | executable, format_bytes::Utf8(error) |
|
447 | // when exiting. | |
434 | )); |
|
448 | let err = command.exec(); | |
435 | on_unsupported = OnUnsupported::Abort |
|
449 | std::process::exit( | |
436 | } |
|
450 | err.raw_os_error().unwrap_or(exit_codes::ABORT), | |
437 |
|
|
451 | ); | |
438 | } |
|
452 | } | |
439 | } |
|
453 | } | |
440 | exit_no_fallback(ui, on_unsupported, result, use_detailed_exit_code) |
|
454 | exit_no_fallback(ui, on_unsupported, result, use_detailed_exit_code) | |
@@ -471,6 +485,13 b' fn exit_no_fallback(' | |||||
471 | OnUnsupported::Fallback { .. } => unreachable!(), |
|
485 | OnUnsupported::Fallback { .. } => unreachable!(), | |
472 | } |
|
486 | } | |
473 | } |
|
487 | } | |
|
488 | Err(CommandError::InvalidFallback { path, err }) => { | |||
|
489 | let _ = ui.write_stderr(&format_bytes!( | |||
|
490 | b"abort: invalid fallback '{}': {}\n", | |||
|
491 | path, | |||
|
492 | err.as_bytes(), | |||
|
493 | )); | |||
|
494 | } | |||
474 | } |
|
495 | } | |
475 | std::process::exit(exit_code(&result, use_detailed_exit_code)) |
|
496 | std::process::exit(exit_code(&result, use_detailed_exit_code)) | |
476 | } |
|
497 | } |
@@ -179,15 +179,8 b' Fallback to Python' | |||||
179 | [1] |
|
179 | [1] | |
180 |
|
180 | |||
181 | $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=hg-non-existent |
|
181 | $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=hg-non-existent | |
182 | tried to fall back to a 'hg-non-existent' sub-process but got error $ENOENT$ |
|
182 | abort: invalid fallback 'hg-non-existent': cannot find binary path | |
183 | unsupported feature: error: Found argument '--exclude' which wasn't expected, or isn't valid in this context |
|
183 | [253] | |
184 |
|
||||
185 | USAGE: |
|
|||
186 | rhg cat [OPTIONS] <FILE>... |
|
|||
187 |
|
||||
188 | For more information try --help |
|
|||
189 |
|
||||
190 | [252] |
|
|||
191 |
|
184 | |||
192 | $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=rhg |
|
185 | $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=rhg | |
193 | Blocking recursive fallback. The 'rhg.fallback-executable = rhg' config points to `rhg` itself. |
|
186 | Blocking recursive fallback. The 'rhg.fallback-executable = rhg' config points to `rhg` itself. |
General Comments 0
You need to be logged in to leave comments.
Login now