Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Command alias or Alias command #1091 #2679

Merged
merged 1 commit into from Jul 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 49 additions & 3 deletions src/bin/cargo.rs
Expand Up @@ -7,13 +7,14 @@ extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::{Path,PathBuf};

use cargo::core::shell::Verbosity;
use cargo::execute_main_without_stdin;
use cargo::util::{self, CliResult, lev_distance, Config, human};
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult};
use cargo::util::CliError;
use cargo::util::process_builder::process;

Expand Down Expand Up @@ -138,7 +139,7 @@ fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
return Ok(None)
}

let args = match &flags.arg_command[..] {
let mut args = match &flags.arg_command[..] {
// For the commands `cargo` and `cargo help`, re-execute ourselves as
// `cargo -h` so we can go through the normal process of printing the
// help message.
Expand Down Expand Up @@ -166,9 +167,30 @@ fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
// For all other invocations, we're of the form `cargo foo args...`. We
// use the exact environment arguments to preserve tokens like `--` for
// example.
_ => env::args().collect(),
_ => {
let mut default_alias = HashMap::new();
default_alias.insert("b", "build".to_string());
default_alias.insert("t", "test".to_string());
default_alias.insert("r", "run".to_string());
let mut args: Vec<String> = env::args().collect();
if let Some(new_command) = default_alias.get(&args[1][..]){
args[1] = new_command.clone();
}
args
}
};

let alias_list = try!(aliased_command(&config, &args[1]));
if let Some(alias_command) = alias_list {
// Replace old command with new command and flags
let chain = args.iter().take(1)
.chain(alias_command.iter())
.chain(args.iter().skip(2))
.map(|s| s.to_string())
.collect();
args = chain;
}

macro_rules! cmd{
($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
config.shell().set_verbosity(Verbosity::Verbose);
Expand All @@ -186,6 +208,30 @@ fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
Ok(None)
}

fn aliased_command(config: &Config, command: &String) -> CargoResult<Option<Vec<String>>> {
let alias_name = format!("alias.{}", command);
let mut result = Ok(None);
match config.get_string(&alias_name) {
Ok(value) => {
if let Some(record) = value {
let alias_commands = record.val.split_whitespace()
.map(|s| s.to_string())
.collect();
result = Ok(Some(alias_commands));
}
},
Err(_) => {
let value = try!(config.get_list(&alias_name));
if let Some(record) = value {
let alias_commands: Vec<String> = record.val.iter()
.map(|s| s.0.to_string()).collect();
result = Ok(Some(alias_commands));
}
}
}
result
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
let cmds = list_commands(config);
// Only consider candidates with a lev_distance of 3 or less so we don't
Expand Down
9 changes: 9 additions & 0 deletions src/doc/config.md
Expand Up @@ -93,6 +93,15 @@ color = 'auto' # whether cargo colorizes output
# Network configuration
[net]
retry = 2 # number of times a network call will automatically retried

# Alias cargo commands. The first 3 aliases are built in. If your
command requires grouped whitespace use the list format.
[alias]
b = "build"
t = "test"
r = "run"
rr = "run --release"
space_example = ["run", "--release", "--", "\"command list\""]
```

# Environment Variables
Expand Down
103 changes: 103 additions & 0 deletions tests/cargo_alias_config.rs
@@ -0,0 +1,103 @@
extern crate cargotest;
extern crate hamcrest;
use cargotest::support::{project, execs, basic_bin_manifest};
use hamcrest::{assert_that};

#[test]
fn alias_incorrect_config_type() {
let p = project("foo")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", r#"
fn main() {
}"#)
.file(".cargo/config",r#"
[alias]
b-cargo-test = 5
"#);;

assert_that(p.cargo_process("b-cargo-test").arg("-v"),
execs().with_status(101).
with_stderr_contains("[ERROR] invalid configuration \
for key `alias.b-cargo-test`
expected a list, but found a integer in [..]"));
}


#[test]
fn alias_default_config_overrides_config() {
let p = project("foo")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", r#"
fn main() {
}"#)
.file(".cargo/config",r#"
[alias]
b = "not_build"
"#);;

assert_that(p.cargo_process("b").arg("-v"),
execs().with_status(0).
with_stderr_contains("[COMPILING] foo v0.5.0 [..]"));
}

#[test]
fn alias_config() {
let p = project("foo")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", r#"
fn main() {
}"#)
.file(".cargo/config",r#"
[alias]
b-cargo-test = "build"
"#);;

assert_that(p.cargo_process("b-cargo-test").arg("-v"),
execs().with_status(0).
with_stderr_contains("[COMPILING] foo v0.5.0 [..]
[RUNNING] `rustc [..] --crate-name foo --crate-type \
bin -g --out-dir [..] --emit=dep-info,link -L dependency=[..]\
-L dependency=[..]"));
}

#[test]
fn alias_list_test() {
let p = project("foo")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", r#"
fn main() {
}"#)
.file(".cargo/config",r#"
[alias]
b-cargo-test = ["build", "--release"]
"#);;

assert_that(p.cargo_process("b-cargo-test").arg("-v"),
execs().with_status(0).
with_stderr_contains("[COMPILING] foo v0.5.0 [..]").
with_stderr_contains("[RUNNING] `rustc [..] --crate-name foo \
--crate-type bin -C opt-level=3 --out-dir [..]\
--emit=dep-info,link -L dependency=[..]")
);
}

#[test]
fn alias_with_flags_config() {
let p = project("foo")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", r#"
fn main() {
}"#)
.file(".cargo/config",r#"
[alias]
b-cargo-test = "build --release"
"#);;

assert_that(p.cargo_process("b-cargo-test").arg("-v"),
execs().with_status(0).
with_stderr_contains("[COMPILING] foo v0.5.0 [..]").
with_stderr_contains("[RUNNING] `rustc [..] --crate-name foo \
--crate-type bin -C opt-level=3 --out-dir [..]\
--emit=dep-info,link -L dependency=[..]")
);
}