mirror of
https://github.com/rust-lang/cargo
synced 2024-10-14 11:42:22 +00:00
Implement cargo-update
This commit is contained in:
parent
07c3c89c6f
commit
620b2fe1b5
|
@ -83,5 +83,9 @@ test = false
|
|||
name = "cargo-generate-lockfile"
|
||||
test = false
|
||||
|
||||
[[bin]]
|
||||
name = "cargo-update"
|
||||
test = false
|
||||
|
||||
[[test]]
|
||||
name = "tests"
|
||||
|
|
|
@ -26,7 +26,7 @@ Options:
|
|||
-j N, --jobs N The number of jobs to run in parallel
|
||||
--release Build artifacts in release mode, with optimizations
|
||||
--target TRIPLE Build for the target triple
|
||||
-u, --update-remotes Update all remote packages before compiling
|
||||
-u, --update-remotes Deprecated option, use `cargo update` instead
|
||||
--manifest-path PATH Path to the manifest to compile
|
||||
-v, --verbose Use verbose output
|
||||
", flag_jobs: Option<uint>, flag_target: Option<String>,
|
||||
|
|
|
@ -23,7 +23,7 @@ Options:
|
|||
-h, --help Print this message
|
||||
--no-deps Don't build documentation for dependencies
|
||||
-j N, --jobs N The number of jobs to run in parallel
|
||||
-u, --update-remotes Update all remote packages before compiling
|
||||
-u, --update-remotes Deprecated option, use `cargo update` instead
|
||||
--manifest-path PATH Path to the manifest to document
|
||||
-v, --verbose Use verbose output
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ Usage:
|
|||
Options:
|
||||
-h, --help Print this message
|
||||
-j N, --jobs N The number of jobs to run in parallel
|
||||
-u, --update-remotes Update all remote packages before compiling
|
||||
-u, --update-remotes Deprecated option, use `cargo update` instead
|
||||
--manifest-path PATH Path to the manifest to execute
|
||||
-v, --verbose Use verbose output
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Usage:
|
|||
Options:
|
||||
-h, --help Print this message
|
||||
-j N, --jobs N The number of jobs to run in parallel
|
||||
-u, --update-remotes Update all remote packages before compiling
|
||||
-u, --update-remotes Deprecated option, use `cargo update` instead
|
||||
--manifest-path PATH Path to the manifest to build tests for
|
||||
-v, --verbose Use verbose output
|
||||
|
||||
|
|
51
src/bin/cargo-update.rs
Normal file
51
src/bin/cargo-update.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
#![feature(phase)]
|
||||
|
||||
extern crate serialize;
|
||||
extern crate cargo;
|
||||
extern crate docopt;
|
||||
#[phase(plugin)] extern crate docopt_macros;
|
||||
#[phase(plugin, link)] extern crate log;
|
||||
|
||||
use std::os;
|
||||
use cargo::ops;
|
||||
use cargo::{execute_main_without_stdin};
|
||||
use cargo::core::MultiShell;
|
||||
use cargo::util::{CliResult, CliError};
|
||||
use cargo::util::important_paths::find_root_manifest_for_cwd;
|
||||
|
||||
docopt!(Options, "
|
||||
Update dependencies as recorded in the local lock file.
|
||||
|
||||
Usage:
|
||||
cargo-update [options] [<name>]
|
||||
|
||||
Options:
|
||||
-h, --help Print this message
|
||||
--manifest-path PATH Path to the manifest to compile
|
||||
-v, --verbose Use verbose output
|
||||
|
||||
This command requires that a `Cargo.lock` already exists as generated by
|
||||
`cargo build` or related commands.
|
||||
|
||||
If <name> is specified, then a conservative update of the lockfile will be
|
||||
performed. This means that only the dependency <name> (and all of its transitive
|
||||
dependencies) will be updated. All other dependencies will remain locked at
|
||||
their currently recorded versions.
|
||||
|
||||
If <name> is not specified, then all dependencies will be re-resolved and
|
||||
updated.
|
||||
", flag_manifest_path: Option<String>, arg_name: Option<String>)
|
||||
|
||||
fn main() {
|
||||
execute_main_without_stdin(execute, false);
|
||||
}
|
||||
|
||||
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
debug!("executing; cmd=cargo-update; args={}", os::args());
|
||||
shell.set_verbose(options.flag_verbose);
|
||||
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
|
||||
|
||||
ops::update_lockfile(&root, shell, options.arg_name)
|
||||
.map(|_| None).map_err(|err| CliError::from_boxed(err, 101))
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ Some common cargo commands are:
|
|||
new Create a new cargo project
|
||||
run Build and execute src/main.rs
|
||||
test Run the tests
|
||||
update Update dependencies listed in Cargo.lock
|
||||
|
||||
See 'cargo help <command>' for more information on a specific command.
|
||||
")
|
||||
|
|
|
@ -24,16 +24,14 @@
|
|||
|
||||
use std::os;
|
||||
use std::collections::HashMap;
|
||||
use std::io::File;
|
||||
use serialize::Decodable;
|
||||
use rstoml = toml;
|
||||
|
||||
use core::registry::PackageRegistry;
|
||||
use core::{MultiShell, Source, SourceId, PackageSet, Target, PackageId, Resolve, resolver};
|
||||
use core::{MultiShell, Source, SourceId, PackageSet, Target, PackageId};
|
||||
use core::resolver;
|
||||
use ops;
|
||||
use sources::{PathSource};
|
||||
use util::config::{Config, ConfigValue};
|
||||
use util::{CargoResult, Wrap, config, internal, human, ChainError, toml};
|
||||
use util::{CargoResult, Wrap, config, internal, human, ChainError};
|
||||
use util::profile;
|
||||
|
||||
pub struct CompileOptions<'a> {
|
||||
|
@ -51,6 +49,11 @@ pub fn compile(manifest_path: &Path,
|
|||
|
||||
log!(4, "compile; manifest-path={}", manifest_path.display());
|
||||
|
||||
if options.update {
|
||||
return Err(human("The -u flag has been deprecated, please use the \
|
||||
`cargo update` command instead"));
|
||||
}
|
||||
|
||||
let mut source = PathSource::for_path(&manifest_path.dir_path());
|
||||
|
||||
try!(source.update());
|
||||
|
@ -76,7 +79,7 @@ pub fn compile(manifest_path: &Path,
|
|||
|
||||
let mut registry = PackageRegistry::new(&mut config);
|
||||
|
||||
let resolved = match try!(load_lockfile(&lockfile, source_id)) {
|
||||
let resolved = match try!(ops::load_lockfile(&lockfile, source_id)) {
|
||||
Some(r) => {
|
||||
try!(registry.add_sources(r.iter().map(|p| {
|
||||
p.get_source_id().clone()
|
||||
|
@ -145,21 +148,6 @@ pub fn compile(manifest_path: &Path,
|
|||
Ok(test_executables)
|
||||
}
|
||||
|
||||
fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
|
||||
// If there is no lockfile, return none.
|
||||
let mut f = match File::open(path) {
|
||||
Ok(f) => f,
|
||||
Err(_) => return Ok(None)
|
||||
};
|
||||
|
||||
let s = try!(f.read_to_string());
|
||||
|
||||
let table = rstoml::Table(try!(toml::parse(s.as_slice(), path)));
|
||||
let mut d = rstoml::Decoder::new(table);
|
||||
let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap();
|
||||
Ok(Some(try!(v.to_resolve(sid))))
|
||||
}
|
||||
|
||||
fn source_ids_from_config(configs: &HashMap<String, config::ConfigValue>,
|
||||
cur_path: Path) -> CargoResult<Vec<SourceId>> {
|
||||
debug!("loaded config; configs={}", configs);
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
#![warn(warnings)]
|
||||
use std::collections::HashSet;
|
||||
use std::io::File;
|
||||
|
||||
use serialize::Encodable;
|
||||
use toml::{mod, Encoder};
|
||||
use serialize::{Encodable, Decodable};
|
||||
use toml::Encoder;
|
||||
use rstoml = toml;
|
||||
|
||||
use core::registry::PackageRegistry;
|
||||
use core::{MultiShell, Source, Resolve, resolver, Package};
|
||||
use core::{MultiShell, Source, Resolve, resolver, Package, SourceId};
|
||||
use core::PackageId;
|
||||
use sources::{PathSource};
|
||||
use util::config::{Config};
|
||||
use util::{CargoResult};
|
||||
use util::{CargoResult, toml, human};
|
||||
|
||||
pub fn generate_lockfile(manifest_path: &Path,
|
||||
shell: &mut MultiShell,
|
||||
|
@ -43,9 +47,80 @@ pub fn write_resolve(pkg: &Package, resolve: &Resolve) -> CargoResult<()> {
|
|||
let mut e = Encoder::new();
|
||||
resolve.encode(&mut e).unwrap();
|
||||
|
||||
let out = toml::Table(e.toml).to_string();
|
||||
let out = rstoml::Table(e.toml).to_string();
|
||||
let loc = pkg.get_root().join("Cargo.lock");
|
||||
try!(File::create(&loc).write_str(out.as_slice()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_lockfile(manifest_path: &Path,
|
||||
shell: &mut MultiShell,
|
||||
to_update: Option<String>) -> CargoResult<()> {
|
||||
let mut source = PathSource::for_path(&manifest_path.dir_path());
|
||||
try!(source.update());
|
||||
let package = try!(source.get_root_package());
|
||||
|
||||
let lockfile = package.get_root().join("Cargo.lock");
|
||||
let source_id = package.get_package_id().get_source_id();
|
||||
let resolve = match try!(load_lockfile(&lockfile, source_id)) {
|
||||
Some(resolve) => resolve,
|
||||
None => return Err(human("A Cargo.lock must exist before it is updated"))
|
||||
};
|
||||
|
||||
let mut config = try!(Config::new(shell, true, None, None));
|
||||
let mut registry = PackageRegistry::new(&mut config);
|
||||
|
||||
let sources = match to_update {
|
||||
Some(name) => {
|
||||
let mut to_avoid = HashSet::new();
|
||||
match resolve.deps(package.get_package_id()) {
|
||||
Some(deps) => {
|
||||
for dep in deps.filter(|d| d.get_name() == name.as_slice()) {
|
||||
fill_with_deps(&resolve, dep, &mut to_avoid);
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
resolve.iter().filter(|pkgid| !to_avoid.contains(pkgid))
|
||||
.map(|pkgid| pkgid.get_source_id().clone()).collect()
|
||||
}
|
||||
None => package.get_source_ids(),
|
||||
};
|
||||
try!(registry.add_sources(sources));
|
||||
|
||||
let resolve = try!(resolver::resolve(package.get_package_id(),
|
||||
package.get_dependencies(),
|
||||
&mut registry));
|
||||
|
||||
try!(write_resolve(&package, &resolve));
|
||||
return Ok(());
|
||||
|
||||
fn fill_with_deps<'a>(resolve: &'a Resolve, dep: &'a PackageId,
|
||||
set: &mut HashSet<&'a PackageId>) {
|
||||
if !set.insert(dep) { return }
|
||||
match resolve.deps(dep) {
|
||||
Some(mut deps) => {
|
||||
for dep in deps {
|
||||
fill_with_deps(resolve, dep, set);
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
|
||||
// If there is no lockfile, return none.
|
||||
let mut f = match File::open(path) {
|
||||
Ok(f) => f,
|
||||
Err(_) => return Ok(None)
|
||||
};
|
||||
|
||||
let s = try!(f.read_to_string());
|
||||
|
||||
let table = rstoml::Table(try!(toml::parse(s.as_slice(), path)));
|
||||
let mut d = rstoml::Decoder::new(table);
|
||||
let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap();
|
||||
Ok(Some(try!(v.to_resolve(sid))))
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ pub use self::cargo_run::run;
|
|||
pub use self::cargo_new::{new, NewOptions};
|
||||
pub use self::cargo_doc::{doc, DocOptions};
|
||||
pub use self::cargo_generate_lockfile::{generate_lockfile, write_resolve};
|
||||
pub use self::cargo_generate_lockfile::{update_lockfile, load_lockfile};
|
||||
|
||||
mod cargo_clean;
|
||||
mod cargo_compile;
|
||||
|
|
|
@ -161,18 +161,16 @@ impl<'a, 'b> Source for GitSource<'a, 'b> {
|
|||
self.reference.as_slice());
|
||||
let should_update = self.config.update_remotes() || actual_rev.is_err();
|
||||
|
||||
let repo = if should_update {
|
||||
let (repo, actual_rev) = if should_update {
|
||||
try!(self.config.shell().status("Updating",
|
||||
format!("git repository `{}`", self.remote.get_location())));
|
||||
|
||||
log!(5, "updating git source `{}`", self.remote);
|
||||
try!(self.remote.checkout(&self.db_path))
|
||||
let repo = try!(self.remote.checkout(&self.db_path));
|
||||
let rev = try!(repo.rev_for(self.reference.as_slice()));
|
||||
(repo, rev)
|
||||
} else {
|
||||
self.remote.db_at(&self.db_path)
|
||||
};
|
||||
let actual_rev = match actual_rev {
|
||||
Ok(rev) => rev,
|
||||
Err(..) => try!(repo.rev_for(self.reference.as_slice())),
|
||||
(self.remote.db_at(&self.db_path), actual_rev.unwrap())
|
||||
};
|
||||
|
||||
try!(repo.copy_to(actual_rev.clone(), &self.checkout_path));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::io::{fs, File};
|
||||
use std::io::File;
|
||||
|
||||
use support::{ProjectBuilder, ResultTest, project, execs, main_file, paths};
|
||||
use support::{cargo_dir};
|
||||
|
@ -544,11 +544,14 @@ test!(recompilation {
|
|||
FRESH, git_project.root().display(),
|
||||
FRESH, p.root().display())));
|
||||
|
||||
assert_that(p.process(cargo_dir().join("cargo-build")).arg("-u"),
|
||||
execs().with_stdout(format!("{} git repository `file:{}`\n\
|
||||
{} bar v0.5.0 (file:{}#[..])\n\
|
||||
assert_that(p.process(cargo_dir().join("cargo-update")),
|
||||
execs().with_stdout(format!("{} git repository `file:{}`",
|
||||
UPDATING,
|
||||
git_project.root().display())));
|
||||
|
||||
assert_that(p.process(cargo_dir().join("cargo-build")),
|
||||
execs().with_stdout(format!("{} bar v0.5.0 (file:{}#[..])\n\
|
||||
{} foo v0.5.0 (file:{})\n",
|
||||
UPDATING, git_project.root().display(),
|
||||
FRESH, git_project.root().display(),
|
||||
FRESH, p.root().display())));
|
||||
|
||||
|
@ -558,23 +561,22 @@ test!(recompilation {
|
|||
git_project.process("git").args(["commit", "-m", "test"]).exec_with_output()
|
||||
.assert();
|
||||
|
||||
assert_that(p.process(cargo_dir().join("cargo-build")).arg("-u"),
|
||||
execs().with_stdout(format!("{} git repository `file:{}`\n\
|
||||
{} bar v0.5.0 (file:{}#[..])\n\
|
||||
println!("compile after commit");
|
||||
assert_that(p.process(cargo_dir().join("cargo-build")),
|
||||
execs().with_stdout(format!("{} bar v0.5.0 (file:{}#[..])\n\
|
||||
{} foo v0.5.0 (file:{})\n",
|
||||
UPDATING, git_project.root().display(),
|
||||
FRESH, git_project.root().display(),
|
||||
FRESH, p.root().display())));
|
||||
|
||||
println!("one last time");
|
||||
|
||||
// Remove the lockfile and make sure that we update
|
||||
fs::unlink(&p.root().join("Cargo.lock")).assert();
|
||||
assert_that(p.process(cargo_dir().join("cargo-build")).arg("-u"),
|
||||
execs().with_stdout(format!("{} git repository `file:{}`\n\
|
||||
{} bar v0.5.0 (file:{}#[..])\n\
|
||||
// Update the dependency and carry on!
|
||||
assert_that(p.process(cargo_dir().join("cargo-update")),
|
||||
execs().with_stdout(format!("{} git repository `file:{}`",
|
||||
UPDATING,
|
||||
git_project.root().display())));
|
||||
println!("going for the last compile");
|
||||
assert_that(p.process(cargo_dir().join("cargo-build")),
|
||||
execs().with_stdout(format!("{} bar v0.5.0 (file:{}#[..])\n\
|
||||
{} foo v0.5.0 (file:{})\n",
|
||||
UPDATING, git_project.root().display(),
|
||||
COMPILING, git_project.root().display(),
|
||||
COMPILING, p.root().display())));
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue