diff --git a/Cargo.lock b/Cargo.lock index 2072ce4021..ce3c338bfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,7 +113,7 @@ version = "0.3.0-beta.1" dependencies = [ "assert_cli 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_proxy 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -132,7 +132,7 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1107,7 +1107,7 @@ dependencies = [ "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" -"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537" +"checksum cargo_metadata 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f410f43295c912ae1328de55e5c050dbef882c17b836f5ed41cc8b96c40d6cc5" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" diff --git a/Cargo.toml b/Cargo.toml index 4478c28306..2584e41926 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ repository = "killercup/cargo-edit" repository = "killercup/cargo-edit" [dependencies] -cargo_metadata = "0.3.0" +cargo_metadata = "0.4.1" docopt = "0.8" env_proxy = "0.2" error-chain = "0.11.0" diff --git a/src/bin/upgrade/main.rs b/src/bin/upgrade/main.rs index 13ea59fbea..40daf202b2 100644 --- a/src/bin/upgrade/main.rs +++ b/src/bin/upgrade/main.rs @@ -11,12 +11,12 @@ extern crate error_chain; extern crate serde_derive; extern crate toml_edit; -use std::collections::HashMap; -use std::path::Path; +use std::collections::HashSet; +use std::path::{Path, PathBuf}; use std::process; extern crate cargo_edit; -use cargo_edit::{get_latest_dependency, Dependency, Manifest}; +use cargo_edit::{find, get_latest_dependency, Dependency, LocalManifest}; mod errors { error_chain!{ @@ -37,12 +37,13 @@ Upgrade all dependencies in a manifest file to the latest version. Usage: cargo upgrade [options] - cargo upgrade [options] ... + cargo upgrade [options] ... [--precise ] cargo upgrade (-h | --help) cargo upgrade (-V | --version) Options: --all Upgrade all packages in the workspace. + --precise PRECISE Upgrade dependencies to exactly PRECISE. --manifest-path PATH Path to the manifest to upgrade. --allow-prerelease Include prerelease versions when fetching from crates.io (e.g. '0.6.0-alpha'). Defaults to false. @@ -59,9 +60,11 @@ be supplied in the presence of a virtual manifest. /// Docopts input args. #[derive(Debug, Deserialize)] struct Args { - /// `--dependency -d ` + /// `...` arg_dependency: Vec, - /// `--manifest-path ` + /// `--precise PRECISE` + flag_precise: Option, + /// `--manifest-path PATH` flag_manifest_path: Option, /// `--version` flag_version: bool, @@ -71,121 +74,136 @@ struct Args { flag_allow_prerelease: bool, } -fn is_version_dependency(dep: &toml_edit::Item) -> bool { - dep["git"].is_none() && dep["path"].is_none() -} +/// A collection of manifests. +struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>); -/// Upgrade the specified manifest. Use the closure provided to get the new dependency versions. -fn upgrade_manifest_using_dependencies( - manifest_path: &Option, - only_update: &[String], - new_dependency: F, -) -> Result<()> -where - F: Fn(&String) -> cargo_edit::Result, -{ - let manifest_path = manifest_path.as_ref().map(From::from); - let mut manifest = Manifest::open(&manifest_path)?; - - for (table_path, table) in manifest.get_sections() { - let table_like = table.as_table_like().expect("bug in get_sections"); - for (name, old_value) in table_like.iter() { - let owned = name.to_owned(); - if (only_update.is_empty() || only_update.contains(&owned)) - && is_version_dependency(old_value) - { - let latest_version = new_dependency(&owned)?; - - manifest.update_table_entry(&table_path, &latest_version)?; - } - } - } +impl Manifests { + /// Get all manifests in the workspace. + fn get_all(manifest_path: &Option) -> Result { + let manifest_path = manifest_path.clone().map(PathBuf::from); - let mut file = Manifest::find_file(&manifest_path)?; - manifest - .write_to_file(&mut file) - .chain_err(|| "Failed to write new manifest contents") -} + cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true) + .chain_err(|| "Failed to get workspace metadata")? + .packages + .into_iter() + .map(|package| { + Ok(( + LocalManifest::try_new(Path::new(&package.manifest_path))?, + package, + )) + }) + .collect::>>() + .map(Manifests) + } -fn upgrade_manifest( - manifest_path: &Option, - only_update: &[String], - allow_prerelease: bool, -) -> Result<()> { - upgrade_manifest_using_dependencies(manifest_path, only_update, |name| { - get_latest_dependency(name, allow_prerelease) - }) -} + /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is + /// provided. + fn get_local_one(manifest_path: &Option) -> Result { + let manifest_path = manifest_path.clone().map(PathBuf::from); + let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into(); -fn upgrade_manifest_from_cache( - manifest_path: &Option, - only_update: &[String], - new_deps: &HashMap, -) -> Result<()> { - upgrade_manifest_using_dependencies( - manifest_path, - only_update, - |name| Ok(new_deps[name].clone()), - ) -} + let manifest = LocalManifest::find(&manifest_path)?; -/// Get a list of the paths of all the (non-virtual) manifests in the workspace. -fn get_workspace_manifests(manifest_path: &Option) -> Result> { - Ok( - cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true) - .chain_err(|| "Failed to get metadata")? - .packages + let packages = cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true) + .chain_err(|| "Invalid manifest")? + .packages; + let package = packages .iter() - .map(|p| p.manifest_path.clone()) - .collect(), - ) -} + .find(|p| p.manifest_path == resolved_manifest_path) + // If we have successfully got metadata, but our manifest path does not correspond to a + // package, we must have been called against a virtual manifest. + .chain_err(|| "Found virtual manifest, but this command requires running against an \ + actual package in this workspace. Try adding `--all`.")?; -/// Look up all current direct crates.io dependencies in the workspace. Then get the latest version -/// for each. -fn get_new_workspace_deps( - manifest_path: &Option, - only_update: &[String], - allow_prerelease: bool, -) -> Result> { - let mut new_deps = HashMap::new(); - - cargo_metadata::metadata_deps(manifest_path.as_ref().map(|p| Path::new(p)), true) - .chain_err(|| "Failed to get metadata")? - .packages - .iter() - .flat_map(|package| package.dependencies.to_owned()) - .filter(|dependency| { - only_update.is_empty() || only_update.contains(&dependency.name) - }) - .map(|dependency| { - if !new_deps.contains_key(&dependency.name) { - new_deps.insert( - dependency.name.clone(), - get_latest_dependency(&dependency.name, allow_prerelease)?, - ); - } - Ok(()) - }) - .collect::>>()?; + Ok(Manifests(vec![(manifest, package.to_owned())])) + } - Ok(new_deps) -} + /// Get the combined set of dependencies of the manifests. + fn get_dependencies(&self, only_update: &[String]) -> Dependencies { + /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency. + fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool { + match dependency.source { + // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a + // dependency has the 'registry' kind. + Some(ref s) => s.splitn(2, '+').next() == Some("registry"), + _ => false, + } + } -fn upgrade_workspace_manifests( - manifest_path: &Option, - only_update: &[String], - allow_prerelease: bool, -) -> Result<()> { - let new_deps = get_new_workspace_deps(manifest_path, only_update, allow_prerelease)?; + Dependencies( + self.0 + .iter() + .flat_map(|&(_, ref package)| package.dependencies.clone()) + .filter(|dependency| { + only_update.is_empty() || only_update.contains(&dependency.name) + }) + .filter(is_version_dep) + .map(|dependency| { + // Convert manually from one dependency format to another. Ideally, this would + // be done by implementing `From`. However, that would require pulling in + // `cargo::SourceId::from_url`, which would entail pulling the entirety of + // cargo. + Dependency::new(&dependency.name) + .set_optional(dependency.optional) + .set_version(&dependency.req.to_string()) + }) + .collect(), + ) + } - get_workspace_manifests(manifest_path).and_then(|manifests| { - for manifest in manifests { - upgrade_manifest_from_cache(&Some(manifest), only_update, &new_deps)? + /// Upgrade the manifests on disk. They will upgrade using the new dependencies provided. + fn upgrade(self, upgraded_deps: &Dependencies) -> Result<()> { + for (mut manifest, _) in self.0 { + for dependency in &upgraded_deps.0 { + manifest.upgrade(dependency)?; + } } Ok(()) - }) + } +} + +/// This represents the version dependencies of the manifests that `cargo-upgrade` will upgrade. +struct Dependencies(HashSet); + +impl Dependencies { + /// Transform the dependencies into their upgraded forms. If a version is specified, all + /// dependencies will get that version. + fn get_upgraded( + self, + precise: &Option, + allow_prerelease: bool, + ) -> Result { + self.0 + .into_iter() + .map(|dependency| { + if let Some(ref precise) = *precise { + Ok(dependency.set_version(precise)) + } else { + get_latest_dependency(&dependency.name, allow_prerelease) + .chain_err(|| "Failed to get new version") + } + }) + .collect::>() + .map(Dependencies) + } +} + +/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error +/// messages. +fn process(args: &Args) -> Result<()> { + let manifests = if args.flag_all { + Manifests::get_all(&args.flag_manifest_path) + } else { + Manifests::get_local_one(&args.flag_manifest_path) + }?; + + let existing_dependencies = manifests.get_dependencies(&args.arg_dependency.clone()); + + let upgraded_dependencies = + existing_dependencies.get_upgraded(&args.flag_precise, args.flag_allow_prerelease)?; + + manifests.upgrade(&upgraded_dependencies) } fn main() { @@ -198,21 +216,7 @@ fn main() { process::exit(0); } - let output = if args.flag_all { - upgrade_workspace_manifests( - &args.flag_manifest_path, - &args.arg_dependency, - args.flag_allow_prerelease, - ) - } else { - upgrade_manifest( - &args.flag_manifest_path, - &args.arg_dependency, - args.flag_allow_prerelease, - ) - }; - - if let Err(err) = output { + if let Err(err) = process(&args) { eprintln!("Command failed due to unhandled error: {}\n", err); for e in err.iter().skip(1) { diff --git a/src/lib.rs b/src/lib.rs index 91f50d8e44..ed729f7fa3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces, unused_qualifications)] +extern crate cargo_metadata; extern crate env_proxy; #[macro_use] extern crate error_chain; @@ -26,4 +27,4 @@ pub use dependency::Dependency; pub use errors::*; pub use fetch::{get_crate_name_from_github, get_crate_name_from_gitlab, get_crate_name_from_path, get_latest_dependency}; -pub use manifest::Manifest; +pub use manifest::{find, LocalManifest, Manifest}; diff --git a/src/manifest.rs b/src/manifest.rs index 9cb33aa7d4..c9cd4dadf2 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -1,5 +1,6 @@ use std::fs::{self, File, OpenOptions}; use std::io::{Read, Write}; +use std::ops::Deref; use std::path::{Path, PathBuf}; use std::{env, str}; @@ -11,7 +12,7 @@ use dependency::Dependency; const MANIFEST_FILENAME: &str = "Cargo.toml"; -/// A Cargo Manifest +/// A Cargo manifest #[derive(Debug, Clone)] pub struct Manifest { /// Manifest contents as TOML data @@ -23,7 +24,7 @@ pub struct Manifest { /// If a manifest is specified, return that one. If a path is specified, perform a manifest search /// starting from there. If nothing is specified, start searching from the current directory /// (`cwd`). -fn find(specified: &Option) -> Result { +pub fn find(specified: &Option) -> Result { match *specified { Some(ref path) if fs::metadata(&path) @@ -336,6 +337,64 @@ impl str::FromStr for Manifest { } } +/// A Cargo manifest that is available locally. +#[derive(Debug)] +pub struct LocalManifest { + /// Path to the manifest + path: PathBuf, + /// Manifest contents + manifest: Manifest, +} + +impl Deref for LocalManifest { + type Target = Manifest; + + fn deref(&self) -> &Manifest { + &self.manifest + } +} + +impl LocalManifest { + /// Construct a `LocalManifest`. If no path is provided, make an educated guess as to which one + /// the user means. + pub fn find(path: &Option) -> Result { + let path = find(path)?; + Self::try_new(&path) + } + + /// Construct the `LocalManifest` corresponding to the `Path` provided. + pub fn try_new(path: &Path) -> Result { + let path = path.to_path_buf(); + Ok(LocalManifest { + manifest: Manifest::open(&Some(path.clone()))?, + path: path, + }) + } + + /// Get the `File` corresponding to this manifest. + fn get_file(&self) -> Result { + Manifest::find_file(&Some(self.path.clone())) + } + + /// Instruct this manifest to upgrade a single dependency. If this manifest does not have that + /// dependency, it does nothing. + pub fn upgrade(&mut self, dependency: &Dependency) -> Result<()> { + for (table_path, table) in self.get_sections() { + let table_like = table.as_table_like().expect("Unexpected non-table"); + for (name, _old_value) in table_like.iter() { + if name == dependency.name { + self.manifest + .update_table_entry(&table_path, dependency)?; + } + } + } + + let mut file = self.get_file()?; + self.write_to_file(&mut file) + .chain_err(|| "Failed to write new manifest contents") + } +} + #[cfg(test)] mod tests { use dependency::Dependency; diff --git a/tests/cargo-add.rs b/tests/cargo-add.rs index f06aab7db8..150e5b9adf 100644 --- a/tests/cargo-add.rs +++ b/tests/cargo-add.rs @@ -667,6 +667,9 @@ fn overwrite_dependency_test(first_command: &[&str], second_command: &[&str], ex let expected = r#"[package] name = "cargo-list-test-fixture" version = "0.0.0" + +[lib] +path = "dummy.rs" "#.to_string() + expected; let expected_dep: toml_edit::Document = expected.parse().expect("toml parse error"); assert_eq!(expected_dep.to_string(), toml.to_string()); diff --git a/tests/cargo-upgrade.rs b/tests/cargo-upgrade.rs index 0fafba4940..3541e4c3a4 100644 --- a/tests/cargo-upgrade.rs +++ b/tests/cargo-upgrade.rs @@ -9,6 +9,53 @@ use std::fs; mod utils; use utils::{clone_out_test, execute_command, get_toml}; +/// Helper function that copies the workspace test into a temporary directory. +pub fn copy_workspace_test() -> (tempdir::TempDir, String, Vec) { + // Create a temporary directory and copy in the root manifest, the dummy rust file, and + // workspace member manifests. + let tmpdir = tempdir::TempDir::new("upgrade_workspace") + .expect("failed to construct temporary directory"); + + let (root_manifest_path, workspace_manifest_paths) = { + // Helper to copy in files to the temporary workspace. The standard library doesn't have a + // good equivalent of `cp -r`, hence this oddity. + let copy_in = |dir, file| { + let file_path = tmpdir + .path() + .join(dir) + .join(file) + .to_str() + .unwrap() + .to_string(); + + fs::create_dir_all(tmpdir.path().join(dir)).unwrap(); + + fs::copy( + format!("tests/fixtures/workspace/{}/{}", dir, file), + &file_path, + ).unwrap_or_else(|err| panic!("could not copy test file: {}", err)); + + file_path + }; + + let root_manifest_path = copy_in(".", "Cargo.toml"); + copy_in(".", "dummy.rs"); + + let workspace_manifest_paths = ["one", "two", "implicit/three", "explicit/four"] + .iter() + .map(|member| copy_in(member, "Cargo.toml")) + .collect::>(); + + (root_manifest_path, workspace_manifest_paths) + }; + + ( + tmpdir, + root_manifest_path, + workspace_manifest_paths.to_owned(), + ) +} + // Verify that an upgraded Cargo.toml matches what we expect. #[test] fn upgrade_as_expected() { @@ -26,16 +73,16 @@ fn upgrade_as_expected() { fn upgrade_all() { let (_tmpdir, manifest) = clone_out_test("tests/fixtures/add/Cargo.toml.sample"); - // Setup manifest with the dependency `versioned-package@0.1.1` - execute_command(&["add", "versioned-package", "--vers", "0.1.1"], &manifest); + // Setup manifest with the dependency `docopt@0.8.0` + execute_command(&["add", "docopt", "--vers", "0.8.0"], &manifest); - // Now, upgrade `versioned-package` to the latest version + // Now, upgrade `docopt` to the latest version execute_command(&["upgrade"], &manifest); - // Verify that `versioned-package` has been updated successfully. + // Verify that `docopt` has been updated successfully. assert_eq!( - get_toml(&manifest)["dependencies"]["versioned-package"].as_str(), - Some("versioned-package--CURRENT_VERSION_TEST") + get_toml(&manifest)["dependencies"]["docopt"].as_str(), + Some("docopt--CURRENT_VERSION_TEST") ); } @@ -43,16 +90,16 @@ fn upgrade_all() { fn upgrade_all_allow_prerelease() { let (_tmpdir, manifest) = clone_out_test("tests/fixtures/add/Cargo.toml.sample"); - // Setup manifest with the dependency `versioned-package@0.1.1` - execute_command(&["add", "versioned-package", "--vers", "0.1.1"], &manifest); + // Setup manifest with `docopt` + execute_command(&["add", "docopt", "--vers", "0.8"], &manifest); - // Now, upgrade `versioned-package` to the latest version + // Now, upgrade `docopt` to the latest version execute_command(&["upgrade", "--allow-prerelease"], &manifest); - // Verify that `versioned-package` has been updated successfully. + // Verify that `docopt` has been updated successfully. assert_eq!( - get_toml(&manifest)["dependencies"]["versioned-package"].as_str(), - Some("versioned-package--PRERELEASE_VERSION_TEST") + get_toml(&manifest)["dependencies"]["docopt"].as_str(), + Some("docopt--PRERELEASE_VERSION_TEST") ); } @@ -60,33 +107,27 @@ fn upgrade_all_allow_prerelease() { fn upgrade_specified_only() { let (_tmpdir, manifest) = clone_out_test("tests/fixtures/add/Cargo.toml.sample"); - // Setup manifest with the dependencies `versioned-package` and `versioned-package-2` - execute_command(&["add", "versioned-package", "--vers", "0.1.1"], &manifest); - execute_command( - &["add", "versioned-package-2", "--vers", "0.1.1"], - &manifest, - ); + // Setup manifest with the dependencies `env_proxy` and `docopt` + execute_command(&["add", "docopt", "--vers", "0.8"], &manifest); + execute_command(&["add", "env_proxy", "--vers", "0.1.1"], &manifest); - // Update `versioned-package` to the latest version - execute_command(&["upgrade", "versioned-package"], &manifest); + // Update `docopt` to the latest version + execute_command(&["upgrade", "docopt"], &manifest); - // Verify that `versioned-package` was upgraded, but not `versioned-package-2` + // Verify that `docopt` was upgraded, but not `env_proxy` let dependencies = &get_toml(&manifest)["dependencies"]; assert_eq!( - dependencies["versioned-package"].as_str(), - Some("versioned-package--CURRENT_VERSION_TEST") - ); - assert_eq!( - dependencies["versioned-package-2"].as_str(), - Some("0.1.1") + dependencies["docopt"].as_str(), + Some("docopt--CURRENT_VERSION_TEST") ); + assert_eq!(dependencies["env_proxy"].as_str(), Some("0.1.1")); } #[test] fn fails_to_upgrade_missing_dependency() { let (_tmpdir, manifest) = clone_out_test("tests/fixtures/add/Cargo.toml.sample"); - // Update the non-existent `failure` to the latest version + // `failure` is not a dependency. Try to upgrade it anyway. execute_command(&["upgrade", "failure"], &manifest); // Verify that `failure` has not been added @@ -99,13 +140,7 @@ fn upgrade_optional_dependency() { // is correct. let (_tmpdir, manifest) = clone_out_test("tests/fixtures/add/Cargo.toml.sample"); execute_command( - &[ - "add", - "versioned-package", - "--vers", - ">=0.1.1", - "--optional", - ], + &["add", "docopt", "--vers", ">=0.1.1", "--optional"], &manifest, ); @@ -114,56 +149,42 @@ fn upgrade_optional_dependency() { // Dependency present afterwards - correct version, and still optional. let toml = get_toml(&manifest); - let val = &toml["dependencies"]["versioned-package"]; + let val = &toml["dependencies"]["docopt"]; assert_eq!( val["version"].as_str(), - Some("versioned-package--CURRENT_VERSION_TEST") + Some("docopt--CURRENT_VERSION_TEST") ); assert_eq!(val["optional"].as_bool(), Some(true)); } #[test] -fn upgrade_workspace() { - // Create a temporary directory and copy in the root manifest, the dummy rust file, and - // workspace member manifests. - let tmpdir = tempdir::TempDir::new("upgrade_workspace") - .expect("failed to construct temporary directory"); +fn upgrade_precise() { + let (_tmpdir, manifest) = clone_out_test("tests/fixtures/add/Cargo.toml.sample"); - // Helper to copy in files to the temporary workspace. The standard library doesn't have a good - // equivalent of `cp -r`, hence this oddity. - let copy_in = |dir, file| { - let file_path = tmpdir - .path() - .join(dir) - .join(file) - .to_str() - .unwrap() - .to_string(); - - fs::create_dir_all(tmpdir.path().join(dir)).unwrap(); - - fs::copy( - format!("tests/fixtures/workspace/{}/{}", dir, file), - &file_path, - ).unwrap_or_else(|err| panic!("could not copy test file: {}", err)); - - file_path - }; + // Setup manifest with `docopt` + execute_command(&["add", "docopt", "--vers", "0.8"], &manifest); + + // Now, upgrade `docopt` to the specified version. This version has never (and should never) be + // published. + execute_command(&["upgrade", "--precise", "a spurious version"], &manifest); - let root_manifest = copy_in(".", "Cargo.toml"); - copy_in(".", "dummy.rs"); + // Verify that `docopt` has been updated to the specified version. + assert_eq!( + get_toml(&manifest)["dependencies"]["docopt"].as_str(), + Some("a spurious version") + ); +} - let workspace_manifests = &["one", "two", "implicit/three", "explicit/four"] - .iter() - .map(|member| copy_in(member, "Cargo.toml")) - .collect::>(); +#[test] +fn upgrade_workspace() { + let (_tmpdir, root_manifest, workspace_manifests) = copy_workspace_test(); execute_command(&["upgrade", "--all"], &root_manifest); // All of the workspace members have `libc` as a dependency. for workspace_member in workspace_manifests { assert_eq!( - get_toml(workspace_member)["dependencies"]["libc"].as_str(), + get_toml(&workspace_member)["dependencies"]["libc"].as_str(), Some("libc--CURRENT_VERSION_TEST") ); } @@ -172,19 +193,17 @@ fn upgrade_workspace() { /// Detect if attempting to run against a workspace root and give a helpful warning. #[test] fn detect_workspace() { - let (_tmpdir, manifest) = clone_out_test("tests/fixtures/workspace/Cargo.toml"); + let (_tmpdir, root_manifest, _workspace_manifests) = copy_workspace_test(); assert_cli::Assert::command(&[ "target/debug/cargo-upgrade", "upgrade", "--manifest-path", - &manifest, + &root_manifest, ]).fails_with(1) .prints_error_exactly( - "Command failed due to unhandled error: Failed to write new manifest contents - -Caused by: Found virtual manifest, but this command requires running against an actual package in \ -this workspace.", + "Command failed due to unhandled error: Found virtual manifest, but this command \ + requires running against an actual package in this workspace. Try adding `--all`.", ) .unwrap(); } @@ -224,7 +243,7 @@ fn invalid_root_manifest() { "--manifest-path", &manifest, ]).fails_with(1) - .prints_error("Command failed due to unhandled error: Failed to get metadata") + .prints_error("Command failed due to unhandled error: Failed to get workspace metadata") .unwrap(); } diff --git a/tests/fixtures/add/Cargo.toml.sample b/tests/fixtures/add/Cargo.toml.sample index 5e20016d71..22345929a0 100644 --- a/tests/fixtures/add/Cargo.toml.sample +++ b/tests/fixtures/add/Cargo.toml.sample @@ -1,3 +1,6 @@ [package] name = "cargo-list-test-fixture" version = "0.0.0" + +[lib] +path = "dummy.rs" \ No newline at end of file diff --git a/tests/fixtures/upgrade/Cargo.toml.source b/tests/fixtures/upgrade/Cargo.toml.source index 35c20e79af..728c6c79a3 100644 --- a/tests/fixtures/upgrade/Cargo.toml.source +++ b/tests/fixtures/upgrade/Cargo.toml.source @@ -3,19 +3,15 @@ name = "None" version = "0.1.0" [lib] +path = "dummy.rs" [dependencies] -bar = { git = "https://github.com/foo/bar.git", version = "0.10" } -crates-io = { path = "src/crates-io", version = "0.10" } docopt = "0.8" -foo = { version = "0.7.0", features = ["serde"] } pad = "0.1" -serde_derive = { version = "1.0", optional = true, path = "../serde_derive" } -serde_derive_internals = { version = "=0.15.1", default-features = false, path = "../serde_derive_internals" } serde_json = "1.0" syn = { version = "0.11.10", default-features = false, features = ["parsing"] } tar = { version = "0.4", default-features = false } -winsftp = "0.4.0" +ftp = "2.2.1" [dependencies.semver] features = ["serde"] @@ -23,29 +19,23 @@ version = "0.7" [dev-dependencies] assert_cli = "0.2.0" -cargotest = { path = "tests/cargotest" } -serde_driver = { version = "1.0", path = "../serde_derive" } tempdir = "0.3" [build-dependencies] -serde = { version = "1.0", path = "../serde" } +serde = { version = "1.0", git= "https://github.com/serde-rs/serde.git" } [target.'cfg(unix)'.dependencies] openssl = "0.9" [target."x86_64/windows.json"] # let's make it an inline table -dependencies = { winhttp = "0.4.0" } +dependencies = { rget = "0.3.0" } -[target.'cfg(target_arch = "x86_64")'.dependencies] -native = { path = "native/x86_64" } - -[target.'cfg(unix)'.dev-dependencies] -mio = { version = "0.0.1", path = "../serde_derive" } -geo = { version = "0.2.1", default-features = false, features = ["green"] } +[target.'cfg(target_arch = "x86_64")'.dev-dependencies] +geo = { version = "0.7.0", default-features = false, features = ["postgis-integration"] } [target.foo.build-dependencies] -winsftp = "0.4.0" +ftp = "2.2.1" [features] default = [] diff --git a/tests/fixtures/upgrade/Cargo.toml.target b/tests/fixtures/upgrade/Cargo.toml.target index efd5f6cbc5..c0808d9963 100644 --- a/tests/fixtures/upgrade/Cargo.toml.target +++ b/tests/fixtures/upgrade/Cargo.toml.target @@ -3,19 +3,15 @@ name = "None" version = "0.1.0" [lib] +path = "dummy.rs" [dependencies] -bar = { git = "https://github.com/foo/bar.git", version = "0.10" } -crates-io = { path = "src/crates-io", version = "0.10" } docopt = "docopt--CURRENT_VERSION_TEST" -foo = { version = "foo--CURRENT_VERSION_TEST", features = ["serde"] } pad = "pad--CURRENT_VERSION_TEST" -serde_derive = { version = "1.0", optional = true, path = "../serde_derive" } -serde_derive_internals = { version = "=0.15.1", default-features = false, path = "../serde_derive_internals" } serde_json = "serde_json--CURRENT_VERSION_TEST" syn = { version = "syn--CURRENT_VERSION_TEST", default-features = false, features = ["parsing"] } tar = { version = "tar--CURRENT_VERSION_TEST", default-features = false } -winsftp = "winsftp--CURRENT_VERSION_TEST" +ftp = "ftp--CURRENT_VERSION_TEST" [dependencies.semver] features = ["serde"] @@ -23,29 +19,23 @@ version = "semver--CURRENT_VERSION_TEST" [dev-dependencies] assert_cli = "assert_cli--CURRENT_VERSION_TEST" -cargotest = { path = "tests/cargotest" } -serde_driver = { version = "1.0", path = "../serde_derive" } tempdir = "tempdir--CURRENT_VERSION_TEST" [build-dependencies] -serde = { version = "1.0", path = "../serde" } +serde = { version = "1.0", git= "https://github.com/serde-rs/serde.git" } [target.'cfg(unix)'.dependencies] openssl = "openssl--CURRENT_VERSION_TEST" [target."x86_64/windows.json"] # let's make it an inline table -dependencies = { winhttp = "winhttp--CURRENT_VERSION_TEST" } +dependencies = { rget = "rget--CURRENT_VERSION_TEST" } -[target.'cfg(target_arch = "x86_64")'.dependencies] -native = { path = "native/x86_64" } - -[target.'cfg(unix)'.dev-dependencies] -mio = { version = "0.0.1", path = "../serde_derive" } -geo = { version = "geo--CURRENT_VERSION_TEST", default-features = false, features = ["green"] } +[target.'cfg(target_arch = "x86_64")'.dev-dependencies] +geo = { version = "geo--CURRENT_VERSION_TEST", default-features = false, features = ["postgis-integration"] } [target.foo.build-dependencies] -winsftp = "winsftp--CURRENT_VERSION_TEST" +ftp = "ftp--CURRENT_VERSION_TEST" [features] default = []