##// END OF EJS Templates
dirstate-v2: Enforce data size read from the docket file...
dirstate-v2: Enforce data size read from the docket file The data file may not be shorter than its size given by the docket. It may be longer, but additional data is ignored. Differential Revision: https://phab.mercurial-scm.org/D11089

File last commit:

r48199:6e49769b default
r48475:48aec076 default
Show More
main.rs
588 lines | 19.3 KiB | application/rls-services+xml | RustLexer
Antoine Cezar
rhg: Add debug timing...
r46101 extern crate log;
Simon Sapin
rhg: Group values passed to every sub-command into a struct...
r47334 use crate::ui::Ui;
Antoine Cezar
rhg: add a limited `rhg root` subcommand...
r45593 use clap::App;
use clap::AppSettings;
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253 use clap::Arg;
Antoine Cezar
rhg: add a limited `rhg debugdata` subcommand...
r46100 use clap::ArgMatches;
Simon Sapin
rhg: Fall back to Python if unsupported extensions are enabled...
r47467 use format_bytes::{format_bytes, join};
Pulkit Goyal
rhg: read [paths] for `--repository` value...
r48196 use hg::config::{Config, ConfigSource};
Pulkit Goyal
rhg: add exit code to HgError::Abort()...
r48199 use hg::exit_codes;
Simon Sapin
rhg: Move `Repo` object creation into `main()`...
r47335 use hg::repo::{Repo, RepoError};
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes};
use hg::utils::SliceExt;
use std::ffi::OsString;
use std::path::PathBuf;
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 use std::process::Command;
Antoine Cezar
rhg: add a limited `rhg root` subcommand...
r45593
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 mod blackbox;
Antoine Cezar
rhg: add Command trait for subcommands implemented by rhg...
r45515 mod error;
Antoine Cezar
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`...
r45592 mod ui;
Antoine Cezar
rhg: add a limited `rhg debugdata` subcommand...
r46100 use error::CommandError;
Antoine Cezar
rhg: add rhg crate...
r45503
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 fn main_with_result(
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 process_start_time: &blackbox::ProcessStartTime,
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 ui: &ui::Ui,
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 repo: Result<&Repo, &NoRepoInCwdError>,
config: &Config,
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 ) -> Result<(), CommandError> {
Simon Sapin
rhg: Fall back to Python if unsupported extensions are enabled...
r47467 check_extensions(config)?;
Antoine Cezar
rhg: add a limited `rhg debugdata` subcommand...
r46100 let app = App::new("rhg")
Simon Sapin
rhg: Use clap’s support for global CLI arguments...
r47351 .global_setting(AppSettings::AllowInvalidUtf8)
Simon Sapin
rhg: Fall back to Python for --version...
r47480 .global_setting(AppSettings::DisableVersion)
Antoine Cezar
rhg: add a limited `rhg root` subcommand...
r45593 .setting(AppSettings::SubcommandRequired)
.setting(AppSettings::VersionlessSubcommands)
Simon Sapin
rhg: Use clap’s support for global CLI arguments...
r47351 .arg(
Arg::with_name("repository")
.help("repository root directory")
.short("-R")
.long("--repository")
.value_name("REPO")
.takes_value(true)
// Both ok: `hg -R ./foo log` or `hg log -R ./foo`
.global(true),
)
.arg(
Arg::with_name("config")
.help("set/override config option (use 'section.name=value')")
.long("--config")
.value_name("CONFIG")
.takes_value(true)
.global(true)
// Ok: `--config section.key1=val --config section.key2=val2`
.multiple(true)
// Not ok: `--config section.key1=val section.key2=val2`
.number_of_values(1),
)
Simon Sapin
rhg: Add support for --cwd...
r47470 .arg(
Arg::with_name("cwd")
.help("change working directory")
.long("--cwd")
.value_name("DIR")
.takes_value(true)
.global(true),
)
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252 .version("0.0.1");
let app = add_subcommand_args(app);
Antoine Cezar
rhg: add a limited `rhg root` subcommand...
r45593
Simon Sapin
rhg: Remove error message on unsupported CLI arguments...
r47333 let matches = app.clone().get_matches_safe()?;
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252 let (subcommand_name, subcommand_matches) = matches.subcommand();
let run = subcommand_run_fn(subcommand_name)
.expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
Simon Sapin
rhg: Group values passed to every sub-command into a struct...
r47334 let subcommand_args = subcommand_matches
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
Antoine Cezar
rhg: add a limited `rhg root` subcommand...
r45593
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 let invocation = CliInvocation {
Simon Sapin
rhg: Group values passed to every sub-command into a struct...
r47334 ui,
subcommand_args,
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 config,
repo,
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 };
let blackbox = blackbox::Blackbox::new(&invocation, process_start_time)?;
blackbox.log_command_start();
let result = run(&invocation);
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 blackbox.log_command_end(exit_code(
&result,
// TODO: show a warning or combine with original error if `get_bool`
// returns an error
config
.get_bool(b"ui", b"detailed-exit-code")
.unwrap_or(false),
));
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 result
Simon Sapin
rhg: Remove error message on unsupported CLI arguments...
r47333 }
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252
Simon Sapin
rhg: Remove error message on unsupported CLI arguments...
r47333 fn main() {
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 // Run this first, before we find out if the blackbox extension is even
// enabled, in order to include everything in-between in the duration
// measurements. Reading config files can be slow if they’re on NFS.
let process_start_time = blackbox::ProcessStartTime::now();
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 env_logger::init();
Simon Sapin
rhg: Move `Repo` object creation into `main()`...
r47335 let ui = ui::Ui::new();
Simon Sapin
rhg: Remove error message on unsupported CLI arguments...
r47333
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 let early_args = EarlyArgs::parse(std::env::args_os());
Simon Sapin
rhg: Add support for --cwd...
r47470
let initial_current_dir = early_args.cwd.map(|cwd| {
let cwd = get_path_from_bytes(&cwd);
std::env::current_dir()
.and_then(|initial| {
std::env::set_current_dir(cwd)?;
Ok(initial)
})
.unwrap_or_else(|error| {
exit(
&None,
&ui,
OnUnsupported::Abort,
Err(CommandError::abort(format!(
"abort: {}: '{}'",
error,
cwd.display()
))),
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 false,
Simon Sapin
rhg: Add support for --cwd...
r47470 )
})
});
Pulkit Goyal
rhg: split non_repo_config and `--config` loading in different functions...
r48198 let mut non_repo_config =
Config::load_non_repo().unwrap_or_else(|error| {
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 // Normally this is decided based on config, but we don’t have that
// available. As of this writing config loading never returns an
// "unsupported" error but that is not enforced by the type system.
let on_unsupported = OnUnsupported::Abort;
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 exit(
&initial_current_dir,
&ui,
on_unsupported,
Err(error.into()),
false,
)
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 });
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423
Pulkit Goyal
rhg: split non_repo_config and `--config` loading in different functions...
r48198 non_repo_config
.load_cli_args_config(early_args.config)
.unwrap_or_else(|error| {
exit(
&initial_current_dir,
&ui,
OnUnsupported::from_config(&ui, &non_repo_config),
Err(error.into()),
non_repo_config
.get_bool(b"ui", b"detailed-exit-code")
.unwrap_or(false),
)
});
Simon Sapin
rhg: Fall back to Python on --repository with an URL...
r47463 if let Some(repo_path_bytes) = &early_args.repo {
lazy_static::lazy_static! {
static ref SCHEME_RE: regex::bytes::Regex =
// Same as `_matchscheme` in `mercurial/util.py`
regex::bytes::Regex::new("^[a-zA-Z0-9+.\\-]+:").unwrap();
}
if SCHEME_RE.is_match(&repo_path_bytes) {
exit(
Simon Sapin
rhg: Add support for --cwd...
r47470 &initial_current_dir,
Simon Sapin
rhg: Fall back to Python on --repository with an URL...
r47463 &ui,
Simon Sapin
rhg: Remove `rhg.fallback-executable=hg` default configuration...
r47482 OnUnsupported::from_config(&ui, &non_repo_config),
Simon Sapin
rhg: Fall back to Python on --repository with an URL...
r47463 Err(CommandError::UnsupportedFeature {
message: format_bytes!(
b"URL-like --repository {}",
repo_path_bytes
),
}),
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 // TODO: show a warning or combine with original error if
// `get_bool` returns an error
non_repo_config
.get_bool(b"ui", b"detailed-exit-code")
.unwrap_or(false),
Simon Sapin
rhg: Fall back to Python on --repository with an URL...
r47463 )
}
}
Pulkit Goyal
rhg: read [paths] for `--repository` value...
r48196 let repo_arg = early_args.repo.unwrap_or(Vec::new());
let repo_path: Option<PathBuf> = {
if repo_arg.is_empty() {
None
} else {
let local_config = {
if std::env::var_os("HGRCSKIPREPO").is_none() {
Pulkit Goyal
rhg: look for repository in ancestors also instead of cwd only...
r48197 // TODO: handle errors from find_repo_root
if let Ok(current_dir_path) = Repo::find_repo_root() {
Pulkit Goyal
rhg: read [paths] for `--repository` value...
r48196 let config_files = vec![
ConfigSource::AbsPath(
current_dir_path.join(".hg/hgrc"),
),
ConfigSource::AbsPath(
current_dir_path.join(".hg/hgrc-not-shared"),
),
];
// TODO: handle errors from
// `load_from_explicit_sources`
Config::load_from_explicit_sources(config_files).ok()
} else {
None
}
} else {
None
}
};
let non_repo_config_val = {
let non_repo_val = non_repo_config.get(b"paths", &repo_arg);
match &non_repo_val {
Some(val) if val.len() > 0 => home::home_dir()
.unwrap_or_else(|| PathBuf::from("~"))
.join(get_path_from_bytes(val))
.canonicalize()
// TODO: handle error and make it similar to python
// implementation maybe?
.ok(),
_ => None,
}
};
let config_val = match &local_config {
None => non_repo_config_val,
Some(val) => {
let local_config_val = val.get(b"paths", &repo_arg);
match &local_config_val {
Some(val) if val.len() > 0 => {
// presence of a local_config assures that
// current_dir
// wont result in an Error
let canpath = hg::utils::current_dir()
.unwrap()
.join(get_path_from_bytes(val))
.canonicalize();
canpath.ok().or(non_repo_config_val)
}
_ => non_repo_config_val,
}
}
};
config_val.or(Some(get_path_from_bytes(&repo_arg).to_path_buf()))
}
};
let repo_result = match Repo::find(&non_repo_config, repo_path.to_owned())
{
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 Ok(repo) => Ok(repo),
Err(RepoError::NotFound { at }) if repo_path.is_none() => {
// Not finding a repo is not fatal yet, if `-R` was not given
Err(NoRepoInCwdError { cwd: at })
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 }
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 Err(error) => exit(
Simon Sapin
rhg: Add support for --cwd...
r47470 &initial_current_dir,
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 &ui,
Simon Sapin
rhg: Remove `rhg.fallback-executable=hg` default configuration...
r47482 OnUnsupported::from_config(&ui, &non_repo_config),
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 Err(error.into()),
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 // TODO: show a warning or combine with original error if
// `get_bool` returns an error
non_repo_config
.get_bool(b"ui", b"detailed-exit-code")
.unwrap_or(false),
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 ),
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 };
let config = if let Ok(repo) = &repo_result {
repo.config()
} else {
&non_repo_config
};
Simon Sapin
rhg: Remove `rhg.fallback-executable=hg` default configuration...
r47482 let on_unsupported = OnUnsupported::from_config(&ui, config);
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423
let result = main_with_result(
&process_start_time,
&ui,
repo_result.as_ref(),
config,
);
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 exit(
&initial_current_dir,
&ui,
on_unsupported,
result,
// TODO: show a warning or combine with original error if `get_bool`
// returns an error
config
.get_bool(b"ui", b"detailed-exit-code")
.unwrap_or(false),
)
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 }
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 fn exit_code(
result: &Result<(), CommandError>,
use_detailed_exit_code: bool,
) -> i32 {
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 match result {
Pulkit Goyal
rhg: add exit code to HgError::Abort()...
r48199 Ok(()) => exit_codes::OK,
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 Err(CommandError::Abort {
message: _,
detailed_exit_code,
}) => {
if use_detailed_exit_code {
*detailed_exit_code
} else {
Pulkit Goyal
rhg: add exit code to HgError::Abort()...
r48199 exit_codes::ABORT
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 }
}
Pulkit Goyal
rhg: add exit code to HgError::Abort()...
r48199 Err(CommandError::Unsuccessful) => exit_codes::UNSUCCESSFUL,
Simon Sapin
rhg: Simplify CommandError based on its use...
r47174
// Exit with a specific code and no error message to let a potential
// wrapper script fallback to Python-based Mercurial.
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 Err(CommandError::UnsupportedFeature { .. }) => {
Pulkit Goyal
rhg: add exit code to HgError::Abort()...
r48199 exit_codes::UNIMPLEMENTED
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 }
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 }
Antoine Cezar
rhg: add rhg crate...
r45503 }
Antoine Cezar
rhg: add a limited `rhg debugdata` subcommand...
r46100
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 fn exit(
Simon Sapin
rhg: Add support for --cwd...
r47470 initial_current_dir: &Option<PathBuf>,
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 ui: &Ui,
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 mut on_unsupported: OnUnsupported,
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 result: Result<(), CommandError>,
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 use_detailed_exit_code: bool,
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 ) -> ! {
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 if let (
OnUnsupported::Fallback { executable },
Err(CommandError::UnsupportedFeature { .. }),
) = (&on_unsupported, &result)
{
let mut args = std::env::args_os();
let executable_path = get_path_from_bytes(&executable);
let this_executable = args.next().expect("exepcted argv[0] to exist");
if executable_path == &PathBuf::from(this_executable) {
// Avoid spawning infinitely many processes until resource
// exhaustion.
let _ = ui.write_stderr(&format_bytes!(
b"Blocking recursive fallback. The 'rhg.fallback-executable = {}' config \
points to `rhg` itself.\n",
executable
));
on_unsupported = OnUnsupported::Abort
} else {
// `args` is now `argv[1..]` since we’ve already consumed `argv[0]`
Simon Sapin
rhg: Add support for --cwd...
r47470 let mut command = Command::new(executable_path);
command.args(args);
if let Some(initial) = initial_current_dir {
command.current_dir(initial);
}
let result = command.status();
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 match result {
Ok(status) => std::process::exit(
Pulkit Goyal
rhg: add exit code to HgError::Abort()...
r48199 status.code().unwrap_or(exit_codes::ABORT),
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 ),
Err(error) => {
let _ = ui.write_stderr(&format_bytes!(
b"tried to fall back to a '{}' sub-process but got error {}\n",
executable, format_bytes::Utf8(error)
));
on_unsupported = OnUnsupported::Abort
}
}
}
}
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 exit_no_fallback(ui, on_unsupported, result, use_detailed_exit_code)
Simon Sapin
rhg: Remove `rhg.fallback-executable=hg` default configuration...
r47482 }
fn exit_no_fallback(
ui: &Ui,
on_unsupported: OnUnsupported,
result: Result<(), CommandError>,
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 use_detailed_exit_code: bool,
Simon Sapin
rhg: Remove `rhg.fallback-executable=hg` default configuration...
r47482 ) -> ! {
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 match &result {
Ok(_) => {}
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 Err(CommandError::Unsuccessful) => {}
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 Err(CommandError::Abort {
message,
detailed_exit_code: _,
}) => {
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 if !message.is_empty() {
// Ignore errors when writing to stderr, we’re already exiting
// with failure code so there’s not much more we can do.
Simon Sapin
rhg: Align config file parse error formatting with Python...
r47465 let _ = ui.write_stderr(&format_bytes!(b"{}\n", message));
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 }
}
Err(CommandError::UnsupportedFeature { message }) => {
match on_unsupported {
OnUnsupported::Abort => {
let _ = ui.write_stderr(&format_bytes!(
b"unsupported feature: {}\n",
message
));
}
OnUnsupported::AbortSilent => {}
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 OnUnsupported::Fallback { .. } => unreachable!(),
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 }
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 }
}
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 std::process::exit(exit_code(&result, use_detailed_exit_code))
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 }
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252 macro_rules! subcommands {
($( $command: ident )+) => {
mod commands {
$(
pub mod $command;
)+
}
fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
app
$(
Simon Sapin
rhg: Use clap’s support for global CLI arguments...
r47351 .subcommand(commands::$command::args())
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252 )+
}
Simon Sapin
rhg: Parse system and user configuration at program start...
r47213
Simon Sapin
rhg: Group values passed to every sub-command into a struct...
r47334 pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>;
fn subcommand_run_fn(name: &str) -> Option<RunFn> {
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252 match name {
$(
stringify!($command) => Some(commands::$command::run),
)+
_ => None,
}
Antoine Cezar
rhg: add a limited `rhg cat -r` subcommand...
r46113 }
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252 };
Antoine Cezar
rhg: add a limited `rhg debugdata` subcommand...
r46100 }
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252
subcommands! {
cat
debugdata
debugrequirements
files
root
Simon Sapin
rhg: add limited support for the `config` sub-command...
r47255 config
Georges Racinet
rhg: Initial support for the 'status' command...
r47578 status
Simon Sapin
rhg: Replace subcommand boilerplate with a macro...
r47252 }
Georges Racinet
rhg: Initial support for the 'status' command...
r47578
Simon Sapin
rhg: Group values passed to every sub-command into a struct...
r47334 pub struct CliInvocation<'a> {
ui: &'a Ui,
subcommand_args: &'a ArgMatches<'a>,
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 config: &'a Config,
Simon Sapin
rhg: Move `Repo` object creation into `main()`...
r47335 /// References inside `Result` is a bit peculiar but allow
/// `invocation.repo?` to work out with `&CliInvocation` since this
/// `Result` type is `Copy`.
repo: Result<&'a Repo, &'a NoRepoInCwdError>,
}
struct NoRepoInCwdError {
cwd: PathBuf,
Simon Sapin
rhg: Group values passed to every sub-command into a struct...
r47334 }
Simon Sapin
rhg: Move `Repo` object creation into `main()`...
r47335
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 /// CLI arguments to be parsed "early" in order to be able to read
/// configuration before using Clap. Ideally we would also use Clap for this,
/// see <https://github.com/clap-rs/clap/discussions/2366>.
///
/// These arguments are still declared when we do use Clap later, so that Clap
/// does not return an error for their presence.
struct EarlyArgs {
/// Values of all `--config` arguments. (Possibly none)
config: Vec<Vec<u8>>,
/// Value of the `-R` or `--repository` argument, if any.
repo: Option<Vec<u8>>,
Simon Sapin
rhg: Add support for --cwd...
r47470 /// Value of the `--cwd` argument, if any.
cwd: Option<Vec<u8>>,
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 }
impl EarlyArgs {
fn parse(args: impl IntoIterator<Item = OsString>) -> Self {
let mut args = args.into_iter().map(get_bytes_from_os_str);
let mut config = Vec::new();
let mut repo = None;
Simon Sapin
rhg: Add support for --cwd...
r47470 let mut cwd = None;
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 // Use `while let` instead of `for` so that we can also call
// `args.next()` inside the loop.
while let Some(arg) = args.next() {
if arg == b"--config" {
if let Some(value) = args.next() {
config.push(value)
}
} else if let Some(value) = arg.drop_prefix(b"--config=") {
config.push(value.to_owned())
}
Simon Sapin
rhg: Add support for --cwd...
r47470 if arg == b"--cwd" {
if let Some(value) = args.next() {
cwd = Some(value)
}
} else if let Some(value) = arg.drop_prefix(b"--cwd=") {
cwd = Some(value.to_owned())
}
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 if arg == b"--repository" || arg == b"-R" {
if let Some(value) = args.next() {
repo = Some(value)
}
} else if let Some(value) = arg.drop_prefix(b"--repository=") {
repo = Some(value.to_owned())
} else if let Some(value) = arg.drop_prefix(b"-R") {
repo = Some(value.to_owned())
}
Simon Sapin
rhg: Move `Repo` object creation into `main()`...
r47335 }
Simon Sapin
rhg: Add support for --cwd...
r47470 Self { config, repo, cwd }
Simon Sapin
rhg: Move `Repo` object creation into `main()`...
r47335 }
}
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424
/// What to do when encountering some unsupported feature.
///
/// See `HgError::UnsupportedFeature` and `CommandError::UnsupportedFeature`.
enum OnUnsupported {
/// Print an error message describing what feature is not supported,
/// and exit with code 252.
Abort,
/// Silently exit with code 252.
AbortSilent,
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 /// Try running a Python implementation
Fallback { executable: Vec<u8> },
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 }
impl OnUnsupported {
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 const DEFAULT: Self = OnUnsupported::Abort;
Simon Sapin
rhg: Remove `rhg.fallback-executable=hg` default configuration...
r47482 fn from_config(ui: &Ui, config: &Config) -> Self {
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 match config
.get(b"rhg", b"on-unsupported")
.map(|value| value.to_ascii_lowercase())
.as_deref()
{
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 Some(b"abort") => OnUnsupported::Abort,
Some(b"abort-silent") => OnUnsupported::AbortSilent,
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 Some(b"fallback") => OnUnsupported::Fallback {
executable: config
.get(b"rhg", b"fallback-executable")
Simon Sapin
rhg: Remove `rhg.fallback-executable=hg` default configuration...
r47482 .unwrap_or_else(|| {
exit_no_fallback(
ui,
Self::Abort,
Err(CommandError::abort(
"abort: 'rhg.on-unsupported=fallback' without \
'rhg.fallback-executable' set."
)),
Pulkit Goyal
rhg: add support for detailed exit code for ConfigParseError...
r47576 false,
Simon Sapin
rhg: Remove `rhg.fallback-executable=hg` default configuration...
r47482 )
})
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 .to_owned(),
},
None => Self::DEFAULT,
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 Some(_) => {
// TODO: warn about unknown config value
Simon Sapin
rhg: Add support for automatic fallback to Python...
r47425 Self::DEFAULT
Simon Sapin
rhg: Add a `rhg.on-unsupported` configuration key...
r47424 }
}
}
}
Simon Sapin
rhg: Fall back to Python if unsupported extensions are enabled...
r47467
const SUPPORTED_EXTENSIONS: &[&[u8]] = &[b"blackbox", b"share"];
fn check_extensions(config: &Config) -> Result<(), CommandError> {
let enabled = config.get_section_keys(b"extensions");
let mut unsupported = enabled;
for supported in SUPPORTED_EXTENSIONS {
unsupported.remove(supported);
}
Simon Sapin
rhg: Add an allow-list of ignored extensions...
r47468 if let Some(ignored_list) =
config.get_simple_list(b"rhg", b"ignored-extensions")
{
for ignored in ignored_list {
unsupported.remove(ignored);
}
}
Simon Sapin
rhg: Fall back to Python if unsupported extensions are enabled...
r47467 if unsupported.is_empty() {
Ok(())
} else {
Err(CommandError::UnsupportedFeature {
message: format_bytes!(
Simon Sapin
rhg: Add an allow-list of ignored extensions...
r47468 b"extensions: {} (consider adding them to 'rhg.ignored-extensions' config)",
Simon Sapin
rhg: Fall back to Python if unsupported extensions are enabled...
r47467 join(unsupported, b", ")
),
})
}
}