Skip to content

Commit

Permalink
Auto merge of #2679 - sbeckeriv:alias, r=alexcrichton
Browse files Browse the repository at this point in the history
Command alias or Alias command #1091

Dearest Reviewer,

This pull request closes #1091 which is a request to support aliases.
This is not as powerful as something like git's alias, however, I think
it sticks true to the original request.

I high jack the processing of the args. After a few flags are checked
and the args are parsed I check the config file for alias.COMMAND. If it
is there I split it like args does and replace args[1] (the original
command) with the alias command and its 'flags'.

As an extra measure I output the alias command with warn. I would be
willing to drop that or put it behind a verbose flag. Also the docs have
been updated.

Thanks!
Becker

<img width="784" alt="screen shot 2016-05-12 at 10 23 59 am" src="https://cloud.githubusercontent.com/assets/12170/15226012/d18a3336-1835-11e6-94c9-875a63a79856.png">
  • Loading branch information
bors committed Jul 13, 2016
2 parents 1cd19a2 + 66739f1 commit 61885fb
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 3 deletions.
52 changes: 49 additions & 3 deletions src/bin/cargo.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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=[..]")
);
}

0 comments on commit 61885fb

Please sign in to comment.