Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion src/cargo/ops/cargo_generate_lockfile.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::path::Path;

use core::PackageId;
Expand Down Expand Up @@ -89,6 +89,18 @@ pub fn update_lockfile(manifest_path: &Path,
Method::Everything,
Some(&previous_resolve),
Some(&to_avoid)));
for dep in compare_dependency_graphs(&previous_resolve, &resolve) {
let (status, msg) = match dep {
(None, Some(pkg)) => ("Adding", format!("{} v{}", pkg.name(), pkg.version())),
(Some(pkg), None) => ("Removing", format!("{} v{}", pkg.name(), pkg.version())),
(Some(pkg1), Some(pkg2)) => {
if pkg1.version() == pkg2.version() { continue }
("Updating", format!("{} v{} -> v{}", pkg1.name(), pkg1.version(), pkg2.version()))
}
(None, None) => continue,
};
try!(opts.config.shell().status(status, msg));
}
try!(ops::write_pkg_lockfile(&package, &resolve));
return Ok(());

Expand All @@ -106,4 +118,23 @@ pub fn update_lockfile(manifest_path: &Path,
None => {}
}
}

fn compare_dependency_graphs<'a>(previous_resolve: &'a Resolve,
resolve: &'a Resolve) ->
Vec<(Option<&'a PackageId>, Option<&'a PackageId>)> {
let mut changes = HashMap::new();
for dep in previous_resolve.iter() {
changes.insert(dep.name(), (Some(dep), None));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this may not be quite right as it's possible to have a few different situations:

  • There could be multiple packages in the graph with the same name, but from different sources.
  • There could be multiple versions of the same package in the graph, locked at different versions.

I think that this could be solved by having the key of the map being (&str, &SourceId) (e.g. .name() and .source()), and then the values would be (Vec<&PackageId>, Vec<&PackageId>) where the first element is all activated versions beforehand and the latter is all activated versions afterwards.

When the map is returned the left vector could represent "versions removed" and the right vector could represent "versions added". In the common case of updating a dep we'll remove one version and add one, but it could possibly be more complicated.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really possible to have multiple versions of the same package in the graph? Some time ago hyper depended indirectly on two different versions of openssl and cargo complained and did not build.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a special case because openssl was a system library (so only one is allowed), but in general multiple Rust libraries are indeed allowed.

}
for dep in resolve.iter() {
if !changes.contains_key(dep.name()) {
changes.insert(dep.name(), (None, None));
}
let value = changes.get_mut(dep.name()).unwrap();
value.1 = Some(dep);
}
let mut package_names: Vec<&str> = changes.keys().map(|x| *x).collect();
package_names.sort();
package_names.iter().map(|name| changes[name]).collect()
}
}
2 changes: 2 additions & 0 deletions tests/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,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";
Expand Down
26 changes: 25 additions & 1 deletion tests/test_cargo_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 -> v0.0.2
", updating = UPDATING)));

println!("0.0.2 build");
Expand All @@ -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 -> v0.0.3
", updating = UPDATING)));

println!("0.0.3 build");
Expand All @@ -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 -> v0.0.4
{adding} spam v0.2.5
", 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 -> v0.0.5
{removing} spam v0.2.5
", updating = UPDATING, removing = REMOVING)));
});

test!(dev_dependency_not_used {
Expand Down Expand Up @@ -760,6 +783,7 @@ test!(update_transitive_dependency {
execs().with_status(0)
.with_stdout(format!("\
{updating} registry `[..]`
{updating} b v0.1.0 -> v0.1.1
", updating = UPDATING)));

assert_that(p.cargo("build"),
Expand Down