177 .load_cli_args_config(early_args.config) |
177 .load_cli_args_config(early_args.config) |
178 .unwrap_or_else(|error| { |
178 .unwrap_or_else(|error| { |
179 exit( |
179 exit( |
180 &initial_current_dir, |
180 &initial_current_dir, |
181 &ui, |
181 &ui, |
182 OnUnsupported::from_config(&ui, &non_repo_config), |
182 OnUnsupported::from_config(&non_repo_config), |
183 Err(error.into()), |
183 Err(error.into()), |
184 non_repo_config |
184 non_repo_config |
185 .get_bool(b"ui", b"detailed-exit-code") |
185 .get_bool(b"ui", b"detailed-exit-code") |
186 .unwrap_or(false), |
186 .unwrap_or(false), |
187 ) |
187 ) |
195 } |
195 } |
196 if SCHEME_RE.is_match(&repo_path_bytes) { |
196 if SCHEME_RE.is_match(&repo_path_bytes) { |
197 exit( |
197 exit( |
198 &initial_current_dir, |
198 &initial_current_dir, |
199 &ui, |
199 &ui, |
200 OnUnsupported::from_config(&ui, &non_repo_config), |
200 OnUnsupported::from_config(&non_repo_config), |
201 Err(CommandError::UnsupportedFeature { |
201 Err(CommandError::UnsupportedFeature { |
202 message: format_bytes!( |
202 message: format_bytes!( |
203 b"URL-like --repository {}", |
203 b"URL-like --repository {}", |
204 repo_path_bytes |
204 repo_path_bytes |
205 ), |
205 ), |
285 Err(NoRepoInCwdError { cwd: at }) |
285 Err(NoRepoInCwdError { cwd: at }) |
286 } |
286 } |
287 Err(error) => exit( |
287 Err(error) => exit( |
288 &initial_current_dir, |
288 &initial_current_dir, |
289 &ui, |
289 &ui, |
290 OnUnsupported::from_config(&ui, &non_repo_config), |
290 OnUnsupported::from_config(&non_repo_config), |
291 Err(error.into()), |
291 Err(error.into()), |
292 // TODO: show a warning or combine with original error if |
292 // TODO: show a warning or combine with original error if |
293 // `get_bool` returns an error |
293 // `get_bool` returns an error |
294 non_repo_config |
294 non_repo_config |
295 .get_bool(b"ui", b"detailed-exit-code") |
295 .get_bool(b"ui", b"detailed-exit-code") |
360 OnUnsupported::Fallback { executable }, |
360 OnUnsupported::Fallback { executable }, |
361 Err(CommandError::UnsupportedFeature { .. }), |
361 Err(CommandError::UnsupportedFeature { .. }), |
362 ) = (&on_unsupported, &result) |
362 ) = (&on_unsupported, &result) |
363 { |
363 { |
364 let mut args = std::env::args_os(); |
364 let mut args = std::env::args_os(); |
|
365 let executable = match executable { |
|
366 None => { |
|
367 exit_no_fallback( |
|
368 ui, |
|
369 OnUnsupported::Abort, |
|
370 Err(CommandError::abort( |
|
371 "abort: 'rhg.on-unsupported=fallback' without \ |
|
372 'rhg.fallback-executable' set.", |
|
373 )), |
|
374 false, |
|
375 ); |
|
376 } |
|
377 Some(executable) => executable, |
|
378 }; |
365 let executable_path = get_path_from_bytes(&executable); |
379 let executable_path = get_path_from_bytes(&executable); |
366 let this_executable = args.next().expect("exepcted argv[0] to exist"); |
380 let this_executable = args.next().expect("exepcted argv[0] to exist"); |
367 if executable_path == &PathBuf::from(this_executable) { |
381 if executable_path == &PathBuf::from(this_executable) { |
368 // Avoid spawning infinitely many processes until resource |
382 // Avoid spawning infinitely many processes until resource |
369 // exhaustion. |
383 // exhaustion. |
372 points to `rhg` itself.\n", |
386 points to `rhg` itself.\n", |
373 executable |
387 executable |
374 )); |
388 )); |
375 on_unsupported = OnUnsupported::Abort |
389 on_unsupported = OnUnsupported::Abort |
376 } else { |
390 } else { |
377 // `args` is now `argv[1..]` since we’ve already consumed `argv[0]` |
391 // `args` is now `argv[1..]` since we’ve already consumed |
|
392 // `argv[0]` |
378 let mut command = Command::new(executable_path); |
393 let mut command = Command::new(executable_path); |
379 command.args(args); |
394 command.args(args); |
380 if let Some(initial) = initial_current_dir { |
395 if let Some(initial) = initial_current_dir { |
381 command.current_dir(initial); |
396 command.current_dir(initial); |
382 } |
397 } |
547 /// and exit with code 252. |
562 /// and exit with code 252. |
548 Abort, |
563 Abort, |
549 /// Silently exit with code 252. |
564 /// Silently exit with code 252. |
550 AbortSilent, |
565 AbortSilent, |
551 /// Try running a Python implementation |
566 /// Try running a Python implementation |
552 Fallback { executable: Vec<u8> }, |
567 Fallback { executable: Option<Vec<u8>> }, |
553 } |
568 } |
554 |
569 |
555 impl OnUnsupported { |
570 impl OnUnsupported { |
556 const DEFAULT: Self = OnUnsupported::Abort; |
571 const DEFAULT: Self = OnUnsupported::Abort; |
557 |
572 |
558 fn from_config(ui: &Ui, config: &Config) -> Self { |
573 fn from_config(config: &Config) -> Self { |
559 match config |
574 match config |
560 .get(b"rhg", b"on-unsupported") |
575 .get(b"rhg", b"on-unsupported") |
561 .map(|value| value.to_ascii_lowercase()) |
576 .map(|value| value.to_ascii_lowercase()) |
562 .as_deref() |
577 .as_deref() |
563 { |
578 { |
564 Some(b"abort") => OnUnsupported::Abort, |
579 Some(b"abort") => OnUnsupported::Abort, |
565 Some(b"abort-silent") => OnUnsupported::AbortSilent, |
580 Some(b"abort-silent") => OnUnsupported::AbortSilent, |
566 Some(b"fallback") => OnUnsupported::Fallback { |
581 Some(b"fallback") => OnUnsupported::Fallback { |
567 executable: config |
582 executable: config |
568 .get(b"rhg", b"fallback-executable") |
583 .get(b"rhg", b"fallback-executable") |
569 .unwrap_or_else(|| { |
584 .map(|x| x.to_owned()), |
570 exit_no_fallback( |
|
571 ui, |
|
572 Self::Abort, |
|
573 Err(CommandError::abort( |
|
574 "abort: 'rhg.on-unsupported=fallback' without \ |
|
575 'rhg.fallback-executable' set." |
|
576 )), |
|
577 false, |
|
578 ) |
|
579 }) |
|
580 .to_owned(), |
|
581 }, |
585 }, |
582 None => Self::DEFAULT, |
586 None => Self::DEFAULT, |
583 Some(_) => { |
587 Some(_) => { |
584 // TODO: warn about unknown config value |
588 // TODO: warn about unknown config value |
585 Self::DEFAULT |
589 Self::DEFAULT |