@@ -55,37 +55,107 @@ impl Drop for Transaction {
5555}
5656
5757pub fn install ( root : Option < & str > ,
58- krate : Option < & str > ,
58+ krates : Vec < & str > ,
5959 source_id : & SourceId ,
6060 vers : Option < & str > ,
6161 opts : & ops:: CompileOptions ,
6262 force : bool ) -> CargoResult < ( ) > {
63+ let root = resolve_root ( root, opts. config ) ?;
64+ let map = SourceConfigMap :: new ( opts. config ) ?;
65+
66+ let ( installed_anything, scheduled_error) = if krates. len ( ) <= 1 {
67+ install_one ( root. clone ( ) , map, krates. into_iter ( ) . next ( ) , source_id, vers, opts,
68+ force, true ) ?;
69+ ( true , false )
70+ } else {
71+ let mut succeeded = vec ! [ ] ;
72+ let mut failed = vec ! [ ] ;
73+ let mut first = true ;
74+ for krate in krates {
75+ let root = root. clone ( ) ;
76+ let map = map. clone ( ) ;
77+ match install_one ( root, map, Some ( krate) , source_id, vers, opts, force, first) {
78+ Ok ( ( ) ) => succeeded. push ( krate) ,
79+ Err ( e) => {
80+ :: handle_error ( e, & mut opts. config . shell ( ) ) ;
81+ failed. push ( krate)
82+ }
83+ }
84+ first = false ;
85+ }
86+
87+ let mut summary = vec ! [ ] ;
88+ if !succeeded. is_empty ( ) {
89+ summary. push ( format ! ( "Successfully installed {}!" , succeeded. join( ", " ) ) ) ;
90+ }
91+ if !failed. is_empty ( ) {
92+ summary. push ( format ! ( "Failed to install {} (see error(s) above)." , failed. join( ", " ) ) ) ;
93+ }
94+ if !succeeded. is_empty ( ) || !failed. is_empty ( ) {
95+ opts. config . shell ( ) . status ( "\n Summary:" , summary. join ( " " ) ) ?;
96+ }
97+
98+ ( !succeeded. is_empty ( ) , !failed. is_empty ( ) )
99+ } ;
100+
101+ if installed_anything {
102+ // Print a warning that if this directory isn't in PATH that they won't be
103+ // able to run these commands.
104+ let dst = metadata ( opts. config , & root) ?. parent ( ) . join ( "bin" ) ;
105+ let path = env:: var_os ( "PATH" ) . unwrap_or ( OsString :: new ( ) ) ;
106+ for path in env:: split_paths ( & path) {
107+ if path == dst {
108+ return Ok ( ( ) )
109+ }
110+ }
111+
112+ opts. config . shell ( ) . warn ( & format ! ( "be sure to add `{}` to your PATH to be \
113+ able to run the installed binaries",
114+ dst. display( ) ) ) ?;
115+ }
116+
117+ if scheduled_error {
118+ bail ! ( "some crates failed to install" ) ;
119+ }
120+
121+ Ok ( ( ) )
122+ }
123+
124+ fn install_one ( root : Filesystem ,
125+ map : SourceConfigMap ,
126+ krate : Option < & str > ,
127+ source_id : & SourceId ,
128+ vers : Option < & str > ,
129+ opts : & ops:: CompileOptions ,
130+ force : bool ,
131+ is_first_install : bool ) -> CargoResult < ( ) > {
132+
63133 let config = opts. config ;
64- let root = resolve_root ( root, config) ?;
65- let map = SourceConfigMap :: new ( config) ?;
134+
66135 let ( pkg, source) = if source_id. is_git ( ) {
67136 select_pkg ( GitSource :: new ( source_id, config) ,
68- krate, vers, config, & mut |git| git. read_packages ( ) ) ?
137+ krate, vers, config, is_first_install,
138+ & mut |git| git. read_packages ( ) ) ?
69139 } 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" ) ;
140+ let path = source_id. url ( ) . to_file_path ( )
141+ . map_err ( | ( ) | CargoError :: from ( "path sources must have a valid path" ) ) ? ;
72142 let mut src = PathSource :: new ( & path, source_id, config) ;
73143 src. update ( ) . chain_err ( || {
74144 format ! ( "`{}` is not a crate root; specify a crate to \
75145 install from crates.io, or use --path or --git to \
76146 specify an alternate source", path. display( ) )
77147 } ) ?;
78148 select_pkg ( PathSource :: new ( & path, source_id, config) ,
79- krate, vers, config, & mut |path| path. read_packages ( ) ) ?
149+ krate, vers, config, is_first_install,
150+ & mut |path| path. read_packages ( ) ) ?
80151 } else {
81152 select_pkg ( map. load ( source_id) ?,
82- krate, vers, config,
153+ krate, vers, config, is_first_install ,
83154 & mut |_| Err ( "must specify a crate to install from \
84155 crates.io, or use --path or --git to \
85156 specify alternate source". into ( ) ) ) ?
86157 } ;
87158
88-
89159 let mut td_opt = None ;
90160 let overidden_target_dir = if source_id. is_path ( ) {
91161 None
@@ -248,30 +318,22 @@ pub fn install(root: Option<&str>,
248318 fs:: remove_dir_all ( & target_dir) ?;
249319 }
250320
251- // Print a warning that if this directory isn't in PATH that they won't be
252- // able to run these commands.
253- let path = env:: var_os ( "PATH" ) . unwrap_or ( OsString :: new ( ) ) ;
254- for path in env:: split_paths ( & path) {
255- if path == dst {
256- return Ok ( ( ) )
257- }
258- }
259-
260- config. shell ( ) . warn ( & format ! ( "be sure to add `{}` to your PATH to be \
261- able to run the installed binaries",
262- dst. display( ) ) ) ?;
263321 Ok ( ( ) )
264322}
265323
266324fn select_pkg < ' a , T > ( mut source : T ,
267325 name : Option < & str > ,
268326 vers : Option < & str > ,
269327 config : & Config ,
328+ needs_update : bool ,
270329 list_all : & mut FnMut ( & mut T ) -> CargoResult < Vec < Package > > )
271330 -> CargoResult < ( Package , Box < Source + ' a > ) >
272331 where T : Source + ' a
273332{
274- source. update ( ) ?;
333+ if needs_update {
334+ source. update ( ) ?;
335+ }
336+
275337 match name {
276338 Some ( name) => {
277339 let vers = match vers {
0 commit comments