Skip to content

Commit 497c297

Browse files
committed
support installing multiple crates
1 parent f2084b7 commit 497c297

File tree

1 file changed

+53
-9
lines changed

1 file changed

+53
-9
lines changed

src/cargo/ops/cargo_install.rs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use std::env;
44
use std::ffi::OsString;
55
use std::fs::{self, File};
66
use std::io::prelude::*;
7-
use std::io::SeekFrom;
7+
use std::io::{self, SeekFrom};
88
use std::path::{Path, PathBuf};
99
use std::sync::Arc;
10+
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
1011

1112
use semver::Version;
1213
use tempdir::TempDir;
@@ -55,36 +56,75 @@ impl Drop for Transaction {
5556
}
5657

5758
pub fn install(root: Option<&str>,
59+
krates: Vec<&str>,
60+
source_id: &SourceId,
61+
vers: Option<&str>,
62+
opts: &ops::CompileOptions,
63+
force: bool) -> CargoResult<()> {
64+
let root = resolve_root(root, opts.config)?;
65+
let map = SourceConfigMap::new(opts.config)?;
66+
67+
if krates.is_empty() {
68+
install_one(root, map, None, source_id, vers, opts, force)
69+
} else {
70+
let mut success = vec![];
71+
let mut errors = vec![];
72+
for krate in krates {
73+
let root = root.clone();
74+
let map = map.clone();
75+
match install_one(root, map, Some(krate), source_id, vers, opts, force) {
76+
Ok(()) => success.push(krate),
77+
Err(e) => errors.push(format!("{}: {}", krate, e))
78+
}
79+
}
80+
81+
writeln!(io::stderr(),
82+
"\n\nSUMMARY\n\nSuccessfully installed: {}\n\nErrors:\n\t{}",
83+
success.join(", "),
84+
errors.join("\n\t"))?;
85+
86+
Ok(())
87+
}
88+
}
89+
90+
fn install_one(root: Filesystem,
91+
map: SourceConfigMap,
5892
krate: Option<&str>,
5993
source_id: &SourceId,
6094
vers: Option<&str>,
6195
opts: &ops::CompileOptions,
6296
force: bool) -> CargoResult<()> {
97+
98+
static ALREADY_UPDATED: AtomicBool = ATOMIC_BOOL_INIT;
99+
let needs_update = !ALREADY_UPDATED.load(Ordering::SeqCst);
100+
63101
let config = opts.config;
64-
let root = resolve_root(root, config)?;
65-
let map = SourceConfigMap::new(config)?;
102+
66103
let (pkg, source) = if source_id.is_git() {
67104
select_pkg(GitSource::new(source_id, config),
68-
krate, vers, config, &mut |git| git.read_packages())?
105+
krate, vers, config, needs_update,
106+
&mut |git| git.read_packages())?
69107
} else if source_id.is_path() {
70-
let path = source_id.url().to_file_path().ok()
71-
.expect("path sources must have a valid path");
108+
let path = source_id.url().to_file_path()
109+
.map_err(|()| CargoError::from("path sources must have a valid path"))?;
72110
let mut src = PathSource::new(&path, source_id, config);
73111
src.update().chain_err(|| {
74112
format!("`{}` is not a crate root; specify a crate to \
75113
install from crates.io, or use --path or --git to \
76114
specify an alternate source", path.display())
77115
})?;
78116
select_pkg(PathSource::new(&path, source_id, config),
79-
krate, vers, config, &mut |path| path.read_packages())?
117+
krate, vers, config, needs_update,
118+
&mut |path| path.read_packages())?
80119
} else {
81120
select_pkg(map.load(source_id)?,
82-
krate, vers, config,
121+
krate, vers, config, needs_update,
83122
&mut |_| Err("must specify a crate to install from \
84123
crates.io, or use --path or --git to \
85124
specify alternate source".into()))?
86125
};
87126

127+
ALREADY_UPDATED.store(true, Ordering::SeqCst);
88128

89129
let mut td_opt = None;
90130
let overidden_target_dir = if source_id.is_path() {
@@ -267,11 +307,15 @@ fn select_pkg<'a, T>(mut source: T,
267307
name: Option<&str>,
268308
vers: Option<&str>,
269309
config: &Config,
310+
needs_update: bool,
270311
list_all: &mut FnMut(&mut T) -> CargoResult<Vec<Package>>)
271312
-> CargoResult<(Package, Box<Source + 'a>)>
272313
where T: Source + 'a
273314
{
274-
source.update()?;
315+
if needs_update {
316+
source.update()?;
317+
}
318+
275319
match name {
276320
Some(name) => {
277321
let vers = match vers {

0 commit comments

Comments
 (0)