Skip to content

Commit

Permalink
Auto merge of #5943 - dwijnand:fix-allow-staged, r=alexcrichton
Browse files Browse the repository at this point in the history
Add `--allow-staged` to `cargo fix`

Fixes #5737

This is @jljusten's branch, adapted to the testsuite changes in master.
Submitted as an alternative to #5910 to expedite #5737 resolution in time for Edition RC 1.
  • Loading branch information
bors committed Aug 29, 2018
2 parents b1209f8 + 8c2d0df commit 8b2082b
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 18 deletions.
6 changes: 6 additions & 0 deletions src/bin/cargo/commands/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ pub fn cli() -> App {
.long("allow-dirty")
.help("Fix code even if the working directory is dirty"),
)
.arg(
Arg::with_name("allow-staged")
.long("allow-staged")
.help("Fix code even if the working directory has staged changes"),
)
.after_help(
"\
This Cargo subcommmand will automatically take rustc's suggestions from
Expand Down Expand Up @@ -135,6 +140,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
compile_opts: opts,
allow_dirty: args.is_present("allow-dirty"),
allow_no_vcs: args.is_present("allow-no-vcs"),
allow_staged: args.is_present("allow-staged"),
broken_code: args.is_present("broken-code"),
})?;
Ok(())
Expand Down
45 changes: 32 additions & 13 deletions src/cargo/ops/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct FixOptions<'a> {
pub compile_opts: CompileOptions<'a>,
pub allow_dirty: bool,
pub allow_no_vcs: bool,
pub allow_staged: bool,
pub broken_code: bool,
}

Expand Down Expand Up @@ -87,39 +88,57 @@ fn check_version_control(opts: &FixOptions) -> CargoResult<()> {
error pass `--allow-no-vcs`")
}

if opts.allow_dirty {
if opts.allow_dirty && opts.allow_staged {
return Ok(())
}

let mut dirty_files = Vec::new();
let mut staged_files = Vec::new();
if let Ok(repo) = git2::Repository::discover(config.cwd()) {
let mut opts = git2::StatusOptions::new();
opts.include_ignored(false);
for status in repo.statuses(Some(&mut opts))?.iter() {
if status.status() != git2::Status::CURRENT {
if let Some(path) = status.path() {
dirty_files.push(path.to_string());
}
let mut repo_opts = git2::StatusOptions::new();
repo_opts.include_ignored(false);
for status in repo.statuses(Some(&mut repo_opts))?.iter() {
if let Some(path) = status.path() {
match status.status() {
git2::Status::CURRENT => (),
git2::Status::INDEX_NEW |
git2::Status::INDEX_MODIFIED |
git2::Status::INDEX_DELETED |
git2::Status::INDEX_RENAMED |
git2::Status::INDEX_TYPECHANGE =>
if !opts.allow_staged {
staged_files.push(path.to_string())
},
_ =>
if !opts.allow_dirty {
dirty_files.push(path.to_string())
},
};
}

}
}

if dirty_files.is_empty() {
if dirty_files.is_empty() && staged_files.is_empty() {
return Ok(())
}

let mut files_list = String::new();
for file in dirty_files {
files_list.push_str(" * ");
files_list.push_str(&file);
files_list.push_str("\n");
files_list.push_str(" (dirty)\n");
}
for file in staged_files {
files_list.push_str(" * ");
files_list.push_str(&file);
files_list.push_str(" (staged)\n");
}

bail!("the working directory of this project is detected as dirty, and \
bail!("the working directory of this project has uncommitted changes, and \
`cargo fix` can potentially perform destructive changes; if you'd \
like to suppress this error pass `--allow-dirty`, or commit the \
changes to these files:\n\
like to suppress this error pass `--allow-dirty`, `--allow-staged`, \
or commit the changes to these files:\n\
\n\
{}\n\
", files_list);
Expand Down
46 changes: 41 additions & 5 deletions tests/testsuite/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use support::git;
use support::is_nightly;
use support::{basic_manifest, project};

use std::io::Write;

#[test]
fn do_not_fix_broken_builds() {
let p = project()
Expand Down Expand Up @@ -725,19 +727,53 @@ fn warns_about_dirty_working_directory() {
.with_status(101)
.with_stderr(
"\
error: the working directory of this project is detected as dirty, and `cargo \
fix` can potentially perform destructive changes; if you'd like to \
suppress this error pass `--allow-dirty`, or commit the changes to \
these files:
error: the working directory of this project has uncommitted changes, \
and `cargo fix` can potentially perform destructive changes; if you'd \
like to suppress this error pass `--allow-dirty`, `--allow-staged`, or \
commit the changes to these files:
* src/lib.rs
* src/lib.rs (dirty)
",
).run();
p.cargo("fix --allow-dirty").run();
}

#[test]
fn warns_about_staged_working_directory() {
let p = project().file("src/lib.rs", "pub fn foo() {}").build();

let repo = git2::Repository::init(&p.root()).unwrap();
let mut cfg = t!(repo.config());
t!(cfg.set_str("user.email", "foo@bar.com"));
t!(cfg.set_str("user.name", "Foo Bar"));
drop(cfg);
git::add(&repo);
git::commit(&repo);
File::create(&p.root().join("src/lib.rs"))
.unwrap()
.write_all("pub fn bar() {}".to_string().as_bytes())
.unwrap();
git::add(&repo);

p.cargo("fix")
.with_status(101)
.with_stderr(
"\
error: the working directory of this project has uncommitted changes, \
and `cargo fix` can potentially perform destructive changes; if you'd \
like to suppress this error pass `--allow-dirty`, `--allow-staged`, or \
commit the changes to these files:
* src/lib.rs (staged)
",
).run();
p.cargo("fix --allow-staged").run();
}

#[test]
fn does_not_warn_about_clean_working_directory() {
let p = project().file("src/lib.rs", "pub fn foo() {}").build();
Expand Down

0 comments on commit 8b2082b

Please sign in to comment.