mirror of
https://github.com/facebook/sapling.git
synced 2025-01-07 14:10:42 +03:00
cliparser: make expand_aliases
take multiple args
Summary: This is the first step to support expanding things like `$1` in aliases. Reviewed By: kulshrax Differential Revision: D16530515 fbshipit-source-id: 3e81c92c2e2021b99815974f53286ec789ba0733
This commit is contained in:
parent
72e3fc1d9a
commit
c4aee9c2c6
@ -1049,7 +1049,7 @@ def _parse(ui, args):
|
||||
if args:
|
||||
try:
|
||||
replacement, aliases = cliparser.expandargs(
|
||||
ui._rcfg, commandnames, args[0], strict
|
||||
ui._rcfg, commandnames, [args[0]], strict
|
||||
)
|
||||
except cliparser.AmbiguousCommand as e:
|
||||
e.args[2].sort()
|
||||
|
@ -42,7 +42,7 @@ pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
|
||||
expand_args(
|
||||
config: config,
|
||||
command_names: Vec<String>,
|
||||
arg: String,
|
||||
args: Vec<String>,
|
||||
strict: bool = false
|
||||
)
|
||||
),
|
||||
@ -119,7 +119,7 @@ fn expand_args(
|
||||
py: Python,
|
||||
config: config,
|
||||
command_names: Vec<String>,
|
||||
arg: String,
|
||||
args: Vec<String>,
|
||||
strict: bool,
|
||||
) -> PyResult<(Vec<PyBytes>, Vec<PyBytes>)> {
|
||||
let mut alias_map = BTreeMap::new();
|
||||
@ -141,7 +141,7 @@ fn expand_args(
|
||||
}
|
||||
}
|
||||
|
||||
let (expanded_args, replaced_aliases) = expand_aliases(&alias_map, &command_map, arg, strict)
|
||||
let (expanded_args, replaced_aliases) = expand_aliases(&alias_map, &command_map, &args, strict)
|
||||
.map_err(|e| map_to_python_err(py, e))?;
|
||||
|
||||
let expanded_args: Vec<PyBytes> = expanded_args
|
||||
|
@ -412,9 +412,13 @@ impl Dispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
let (expanded, replaced) =
|
||||
expand_aliases(&alias_map, &command_map, first_arg.to_string(), false)
|
||||
.map_err(|_| DispatchError::AliasExpansionFailed)?;
|
||||
let (expanded, replaced) = expand_aliases(
|
||||
&alias_map,
|
||||
&command_map,
|
||||
&vec![first_arg.to_string()],
|
||||
false,
|
||||
)
|
||||
.map_err(|_| DispatchError::AliasExpansionFailed)?;
|
||||
|
||||
let mut new_args = Vec::new();
|
||||
|
||||
|
@ -16,7 +16,8 @@ use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
/// e.g. 'id' and 'identify'. If commands point to the same id they are assumed
|
||||
/// to be equivalent.
|
||||
///
|
||||
/// * `args` - The original arguments to resolve aliases from
|
||||
/// * `args` - The original arguments to resolve aliases from.
|
||||
/// The first argument should be the command name.
|
||||
///
|
||||
/// * `strict` - Decides if there should be strict or prefix matching ( True = no prefix matching )
|
||||
///
|
||||
@ -27,41 +28,45 @@ use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
pub fn expand_aliases(
|
||||
cfg: &BTreeMap<String, String>,
|
||||
command_map: &BTreeMap<String, usize>,
|
||||
mut arg: String,
|
||||
args: &[impl ToString],
|
||||
strict: bool,
|
||||
) -> Result<(Vec<String>, Vec<String>), ParseError> {
|
||||
let mut following_args = Vec::new();
|
||||
let mut replaced = Vec::new(); // keep track of what is replaced in-order
|
||||
let (mut command_name, command_args) = args
|
||||
.split_first()
|
||||
.map(|(n, a)| (n.to_string(), a.iter().map(ToString::to_string).collect()))
|
||||
.unwrap_or_else(Default::default);
|
||||
let mut following_args = vec![command_args];
|
||||
|
||||
if !strict {
|
||||
arg = replace_prefix(command_map, arg)?;
|
||||
command_name = replace_prefix(command_map, command_name)?;
|
||||
}
|
||||
|
||||
let mut visited = HashSet::new();
|
||||
|
||||
while let Some(alias) = cfg.get(&arg) {
|
||||
while let Some(alias) = cfg.get(&command_name) {
|
||||
let bad_alias = || ParseError::IllformedAlias {
|
||||
name: arg.clone(),
|
||||
name: command_name.clone(),
|
||||
value: alias.to_string(),
|
||||
};
|
||||
|
||||
if !visited.insert(arg.clone()) {
|
||||
return Err(ParseError::CircularReference { command_name: arg });
|
||||
if !visited.insert(command_name.clone()) {
|
||||
return Err(ParseError::CircularReference { command_name });
|
||||
}
|
||||
|
||||
let parts: Vec<String> = split(alias).ok_or_else(bad_alias)?;
|
||||
let (next_command_name, next_args) = parts.split_first().ok_or_else(bad_alias)?;
|
||||
let next_command_name = next_command_name.to_string();
|
||||
replaced.push(arg.clone());
|
||||
replaced.push(command_name.clone());
|
||||
following_args.push(next_args.iter().cloned().collect::<Vec<String>>());
|
||||
if next_command_name == arg {
|
||||
if next_command_name == command_name {
|
||||
break;
|
||||
} else {
|
||||
arg = next_command_name;
|
||||
command_name = next_command_name;
|
||||
}
|
||||
}
|
||||
|
||||
let expanded = std::iter::once(arg)
|
||||
let expanded = std::iter::once(command_name)
|
||||
.chain(following_args.into_iter().rev().flatten())
|
||||
.collect();
|
||||
|
||||
@ -138,8 +143,7 @@ mod tests {
|
||||
fn test_no_alias() {
|
||||
let cfg = BTreeMap::new();
|
||||
let command_map = BTreeMap::new();
|
||||
let (_expanded, replaced) =
|
||||
expand_aliases(&cfg, &command_map, "log".to_string(), false).unwrap();
|
||||
let (_expanded, replaced) = expand_aliases(&cfg, &command_map, &["log"], false).unwrap();
|
||||
assert!(replaced.len() == 0);
|
||||
}
|
||||
|
||||
@ -149,8 +153,7 @@ mod tests {
|
||||
cfg.insert("log".to_string(), "log -v".to_string());
|
||||
let command_map = BTreeMap::new();
|
||||
|
||||
let (expanded, replaced) =
|
||||
expand_aliases(&cfg, &command_map, "log".to_string(), false).unwrap();
|
||||
let (expanded, replaced) = expand_aliases(&cfg, &command_map, &["log"], false).unwrap();
|
||||
assert_eq!(expanded, vec!["log", "-v"]);
|
||||
assert_eq!(replaced, vec!["log"]);
|
||||
}
|
||||
@ -162,7 +165,7 @@ mod tests {
|
||||
command_map.insert("foo".to_string(), 0);
|
||||
command_map.insert("foobar".to_string(), 1);
|
||||
|
||||
if let Err(err) = expand_aliases(&cfg, &command_map, "fo".to_string(), false) {
|
||||
if let Err(err) = expand_aliases(&cfg, &command_map, &["fo"], false) {
|
||||
let msg = format!("{}", err);
|
||||
assert_eq!(msg, "Command fo is ambiguous");
|
||||
} else {
|
||||
@ -177,7 +180,7 @@ mod tests {
|
||||
command_map.insert("foo".to_string(), 0);
|
||||
command_map.insert("foobar".to_string(), 1);
|
||||
|
||||
if let Err(err) = expand_aliases(&cfg, &command_map, "fo".to_string(), false) {
|
||||
if let Err(err) = expand_aliases(&cfg, &command_map, &["fo"], false) {
|
||||
let msg = format!("{}", err);
|
||||
assert_eq!(msg, "Command fo is ambiguous");
|
||||
} else {
|
||||
@ -193,7 +196,7 @@ mod tests {
|
||||
command_map.insert("foobar".to_string(), 0);
|
||||
command_map.insert("foo".to_string(), 1);
|
||||
|
||||
if let Err(err) = expand_aliases(&cfg, &command_map, "fo".to_string(), false) {
|
||||
if let Err(err) = expand_aliases(&cfg, &command_map, &["fo"], false) {
|
||||
let msg = format!("{}", err);
|
||||
assert_eq!(msg, "Command fo is ambiguous");
|
||||
} else {
|
||||
@ -208,8 +211,7 @@ mod tests {
|
||||
command_map.insert("id".to_string(), 0);
|
||||
command_map.insert("identify".to_string(), 0);
|
||||
|
||||
let (expanded, _replaced) =
|
||||
expand_aliases(&cfg, &command_map, "i".to_string(), false).unwrap();
|
||||
let (expanded, _replaced) = expand_aliases(&cfg, &command_map, &["i"], false).unwrap();
|
||||
let element = expanded.get(0).unwrap();
|
||||
assert!((element == "id") || (element == "identify"));
|
||||
}
|
||||
@ -221,7 +223,7 @@ mod tests {
|
||||
cfg.insert("foo".to_string(), "log".to_string());
|
||||
cfg.insert("log".to_string(), "foo".to_string());
|
||||
|
||||
if let Err(err) = expand_aliases(&cfg, &command_map, "foo".to_string(), false) {
|
||||
if let Err(err) = expand_aliases(&cfg, &command_map, &["foo"], false) {
|
||||
let msg = format!("{}", err);
|
||||
assert_eq!(msg, "Alias foo resulted in a circular reference");
|
||||
} else {
|
||||
@ -237,8 +239,7 @@ mod tests {
|
||||
cfg.insert("b".to_string(), "c 2".to_string());
|
||||
cfg.insert("c".to_string(), "d 3".to_string());
|
||||
|
||||
let (expanded, _replaced) =
|
||||
expand_aliases(&cfg, &command_map, "a".to_string(), false).unwrap();
|
||||
let (expanded, _replaced) = expand_aliases(&cfg, &command_map, &["a"], false).unwrap();
|
||||
|
||||
assert_eq!(expanded, vec!["d", "3", "2", "1"]);
|
||||
}
|
||||
@ -253,8 +254,7 @@ mod tests {
|
||||
cfg.insert("log".to_string(), "log -v".to_string());
|
||||
let command_map = BTreeMap::new();
|
||||
|
||||
let (expanded, replaced) =
|
||||
expand_aliases(&cfg, &command_map, "foo".to_string(), false).unwrap();
|
||||
let (expanded, replaced) = expand_aliases(&cfg, &command_map, &["foo"], false).unwrap();
|
||||
|
||||
assert_eq!(expanded, vec!["log", "-v", "bar"]);
|
||||
assert_eq!(replaced, vec!["foo", "log"]);
|
||||
@ -269,8 +269,7 @@ mod tests {
|
||||
cfg.insert("bar".to_string(), "foo".to_string());
|
||||
let command_map = BTreeMap::new();
|
||||
|
||||
let (expanded, replaced) =
|
||||
expand_aliases(&cfg, &command_map, "bar".to_string(), false).unwrap();
|
||||
let (expanded, replaced) = expand_aliases(&cfg, &command_map, &["bar"], false).unwrap();
|
||||
|
||||
assert_eq!(expanded, vec!["foo", "-r", "foo", "-v", "foo", "foo"]);
|
||||
assert_eq!(replaced, vec!["bar", "foo"]);
|
||||
@ -282,7 +281,7 @@ mod tests {
|
||||
cfg.insert("nodef".to_string(), "".to_string());
|
||||
let command_map = BTreeMap::new();
|
||||
|
||||
expand_aliases(&cfg, &command_map, "nodef".to_string(), false).unwrap_err();
|
||||
expand_aliases(&cfg, &command_map, &["nodef"], false).unwrap_err();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user