Print information about updated packages on cargo update

Closes #984.
This commit is contained in:
George Hilliard 2015-05-17 18:45:55 +02:00
parent fc66290f27
commit 492b5825c3
4 changed files with 119 additions and 11 deletions

View file

@ -1,9 +1,9 @@
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::path::Path;
use core::PackageId;
use core::registry::PackageRegistry;
use core::{Source, Resolve};
use core::{Source, Resolve, SourceId};
use core::resolver::Method;
use ops;
use sources::{PathSource};
@ -91,6 +91,33 @@ pub fn update_lockfile(manifest_path: &Path,
Method::Everything,
Some(&previous_resolve),
Some(&to_avoid)));
// Summarize what is changing for the user.
let print_change = |status: &str, msg: String| {
opts.config.shell().status(status, msg)
};
for (removed, added) in compare_dependency_graphs(&previous_resolve, &resolve) {
if removed.len() == 1 && added.len() == 1 {
if removed[0].source_id().is_git() {
try!(print_change("Updating", format!("{} -> #{}",
removed[0],
&added[0].source_id().precise().unwrap()[..8])));
} else {
try!(print_change("Updating", format!("{} -> v{}",
removed[0],
added[0].version())));
}
}
else {
for package in removed.iter() {
try!(print_change("Removing", format!("{}", package)));
}
for package in added.iter() {
try!(print_change("Adding", format!("{}", package)));
}
}
}
try!(ops::write_pkg_lockfile(&package, &resolve));
return Ok(());
@ -108,4 +135,46 @@ pub fn update_lockfile(manifest_path: &Path,
None => {}
}
}
fn compare_dependency_graphs<'a>(previous_resolve: &'a Resolve,
resolve: &'a Resolve) ->
Vec<(Vec<&'a PackageId>, Vec<&'a PackageId>)> {
// Map (package name, package source) to (removed versions, added versions).
fn changes_key<'a>(dep: &'a PackageId) -> (&'a str, &'a SourceId) {
(dep.name(), dep.source_id())
}
fn vec_subtract<T>(a: &[T], b: &[T]) -> Vec<T>
where T: Ord + Clone {
let mut result = a.to_owned();
let mut b = b.to_owned();
b.sort();
result.retain(|x| b.binary_search(x).is_err());
result
}
let mut changes = HashMap::new();
for dep in previous_resolve.iter() {
changes.insert(changes_key(dep), (vec![dep], vec![]));
}
for dep in resolve.iter() {
let (_, ref mut added) = *changes.entry(changes_key(dep))
.or_insert_with(|| (vec![], vec![]));
added.push(dep);
}
for (_, v) in changes.iter_mut() {
let (ref mut old, ref mut new) = *v;
let removed = vec_subtract(old, new);
let added = vec_subtract(new, old);
*old = removed;
*new = added;
}
// Sort the packages by their names.
let mut packages: Vec<_> = changes.keys().map(|x| *x).collect();
packages.sort();
packages.iter().map(|k| changes[k].clone()).collect()
}
}

View file

@ -522,6 +522,8 @@ pub static RUNNING: &'static str = " Running";
pub static COMPILING: &'static str = " Compiling";
pub static FRESH: &'static str = " Fresh";
pub static UPDATING: &'static str = " Updating";
pub static ADDING: &'static str = " Adding";
pub static REMOVING: &'static str = " Removing";
pub static DOCTEST: &'static str = " Doc-tests";
pub static PACKAGING: &'static str = " Packaging";
pub static DOWNLOADING: &'static str = " Downloading";

View file

@ -539,9 +539,12 @@ test!(recompilation {
// Update the dependency and carry on!
assert_that(p.cargo("update"),
execs().with_stdout(&format!("{} git repository `{}`",
execs().with_stdout(&format!("{} git repository `{}`\n\
{} bar v0.5.0 ([..]) -> #[..]\n\
",
UPDATING,
git_project.url())));
git_project.url(),
UPDATING)));
println!("going for the last compile");
assert_that(p.cargo("build"),
execs().with_stdout(&format!("{} bar v0.5.0 ({}#[..])\n\
@ -657,9 +660,12 @@ test!(update_with_shared_deps {
assert_that(p.cargo("update")
.arg("-p").arg("dep1")
.arg("--aggressive"),
execs().with_stdout(&format!("{} git repository `{}`",
execs().with_stdout(&format!("{} git repository `{}`\n\
{} bar v0.5.0 ([..]) -> #[..]\n\
",
UPDATING,
git_project.url())));
git_project.url(),
UPDATING)));
// Make sure we still only compile one version of the git repo
println!("build");
@ -782,8 +788,12 @@ test!(two_deps_only_update_one {
assert_that(project.cargo("update")
.arg("-p").arg("dep1"),
execs()
.with_stdout(&format!("{} git repository `{}`\n",
UPDATING, git1.url()))
.with_stdout(&format!("{} git repository `{}`\n\
{} dep1 v0.5.0 ([..]) -> #[..]\n\
",
UPDATING,
git1.url(),
UPDATING))
.with_stderr(""));
});
@ -941,9 +951,12 @@ test!(dep_with_changed_submodule {
assert_that(project.cargo("update").arg("-v"),
execs()
.with_stderr("")
.with_stdout(&format!("{} git repository `{}`",
.with_stdout(&format!("{} git repository `{}`\n\
{} dep1 v0.5.0 ([..]) -> #[..]\n\
",
UPDATING,
git_project.url())));
git_project.url(),
UPDATING)));
println!("last run");
assert_that(project.cargo("run"), execs()

View file

@ -3,7 +3,7 @@ use std::io::prelude::*;
use cargo::util::process;
use support::{project, execs, cargo_dir};
use support::{UPDATING, DOWNLOADING, COMPILING, PACKAGING, VERIFYING};
use support::{UPDATING, DOWNLOADING, COMPILING, PACKAGING, VERIFYING, ADDING, REMOVING};
use support::paths::{self, CargoPathExt};
use support::registry as r;
use support::git;
@ -476,6 +476,7 @@ test!(update_lockfile {
.arg("-p").arg("bar").arg("--precise").arg("0.0.2"),
execs().with_status(0).with_stdout(&format!("\
{updating} registry `[..]`
{updating} bar v0.0.1 (registry file://[..]) -> v0.0.2
", updating = UPDATING)));
println!("0.0.2 build");
@ -492,6 +493,7 @@ test!(update_lockfile {
.arg("-p").arg("bar"),
execs().with_status(0).with_stdout(&format!("\
{updating} registry `[..]`
{updating} bar v0.0.2 (registry file://[..]) -> v0.0.3
", updating = UPDATING)));
println!("0.0.3 build");
@ -502,6 +504,27 @@ test!(update_lockfile {
{compiling} foo v0.0.1 ({dir})
", downloading = DOWNLOADING, compiling = COMPILING,
dir = p.url())));
println!("new dependencies update");
r::mock_pkg("bar", "0.0.4", &[("spam", "0.2.5", "")]);
r::mock_pkg("spam", "0.2.5", &[]);
assert_that(p.cargo("update")
.arg("-p").arg("bar"),
execs().with_status(0).with_stdout(&format!("\
{updating} registry `[..]`
{updating} bar v0.0.3 (registry file://[..]) -> v0.0.4
{adding} spam v0.2.5 (registry file://[..])
", updating = UPDATING, adding = ADDING)));
println!("new dependencies update");
r::mock_pkg("bar", "0.0.5", &[]);
assert_that(p.cargo("update")
.arg("-p").arg("bar"),
execs().with_status(0).with_stdout(&format!("\
{updating} registry `[..]`
{updating} bar v0.0.4 (registry file://[..]) -> v0.0.5
{removing} spam v0.2.5 (registry file://[..])
", updating = UPDATING, removing = REMOVING)));
});
test!(dev_dependency_not_used {
@ -760,6 +783,7 @@ test!(update_transitive_dependency {
execs().with_status(0)
.with_stdout(format!("\
{updating} registry `[..]`
{updating} b v0.1.0 (registry [..]) -> v0.1.1
", updating = UPDATING)));
assert_that(p.cargo("build"),