@@ -3,6 +3,7 @@ use futures::stream::FuturesUnordered;
3
3
use futures:: StreamExt ;
4
4
use itertools:: Itertools ;
5
5
use owo_colors:: OwoColorize ;
6
+ use rustc_hash:: FxHashSet ;
6
7
use std:: collections:: BTreeSet ;
7
8
use std:: fmt:: Write ;
8
9
use std:: path:: Path ;
@@ -63,7 +64,7 @@ pub(crate) async fn install(
63
64
. inspect ( |installation| debug ! ( "Found existing installation {}" , installation. key( ) ) )
64
65
. collect ( ) ;
65
66
let mut unfilled_requests = Vec :: new ( ) ;
66
- let mut uninstalled = Vec :: new ( ) ;
67
+ let mut uninstalled = FxHashSet :: default ( ) ;
67
68
for ( request, download_request) in requests. iter ( ) . zip ( download_requests) {
68
69
if matches ! ( requests. as_slice( ) , [ PythonRequest :: Default ] ) {
69
70
writeln ! ( printer. stderr( ) , "Searching for Python installations" ) ?;
@@ -89,7 +90,7 @@ pub(crate) async fn install(
89
90
) ?;
90
91
}
91
92
if reinstall {
92
- uninstalled. push ( installation. key ( ) . clone ( ) ) ;
93
+ uninstalled. insert ( installation. key ( ) ) ;
93
94
unfilled_requests. push ( download_request) ;
94
95
}
95
96
} else {
@@ -155,7 +156,7 @@ pub(crate) async fn install(
155
156
} ) ;
156
157
}
157
158
158
- let mut installed = vec ! [ ] ;
159
+ let mut installed = FxHashSet :: default ( ) ;
159
160
let mut errors = vec ! [ ] ;
160
161
while let Some ( ( key, result) ) = tasks. next ( ) . await {
161
162
match result {
@@ -166,7 +167,7 @@ pub(crate) async fn install(
166
167
DownloadResult :: Fetched ( path) => path,
167
168
} ;
168
169
169
- installed. push ( key. clone ( ) ) ;
170
+ installed. insert ( key) ;
170
171
171
172
// Ensure the installations have externally managed markers
172
173
let managed = ManagedPythonInstallation :: new ( path. clone ( ) ) ?;
@@ -180,7 +181,8 @@ pub(crate) async fn install(
180
181
}
181
182
182
183
if !installed. is_empty ( ) {
183
- if let [ installed] = installed. as_slice ( ) {
184
+ if installed. len ( ) == 1 {
185
+ let installed = installed. iter ( ) . next ( ) . unwrap ( ) ;
184
186
// Ex) "Installed Python 3.9.7 in 1.68s"
185
187
writeln ! (
186
188
printer. stderr( ) ,
@@ -194,29 +196,38 @@ pub(crate) async fn install(
194
196
) ?;
195
197
} else {
196
198
// Ex) "Installed 2 versions in 1.68s"
197
- let s = if installed. len ( ) == 1 { "" } else { "s" } ;
198
199
writeln ! (
199
200
printer. stderr( ) ,
200
201
"{}" ,
201
202
format!(
202
203
"Installed {} {}" ,
203
- format!( "{} version{s} " , installed. len( ) ) . bold( ) ,
204
+ format!( "{} versions " , installed. len( ) ) . bold( ) ,
204
205
format!( "in {}" , elapsed( start. elapsed( ) ) ) . dimmed( )
205
206
)
206
207
. dimmed( )
207
208
) ?;
208
209
}
209
210
211
+ let reinstalled = uninstalled
212
+ . intersection ( & installed)
213
+ . copied ( )
214
+ . collect :: < FxHashSet < _ > > ( ) ;
215
+ let uninstalled = uninstalled. difference ( & reinstalled) . copied ( ) ;
216
+ let installed = installed. difference ( & reinstalled) . copied ( ) ;
217
+
210
218
for event in uninstalled
211
- . into_iter ( )
212
219
. map ( |key| ChangeEvent {
213
- key,
220
+ key : key . clone ( ) ,
214
221
kind : ChangeEventKind :: Removed ,
215
222
} )
216
- . chain ( installed. into_iter ( ) . map ( |key| ChangeEvent {
217
- key,
223
+ . chain ( installed. map ( |key| ChangeEvent {
224
+ key : key . clone ( ) ,
218
225
kind : ChangeEventKind :: Added ,
219
226
} ) )
227
+ . chain ( reinstalled. iter ( ) . map ( |& key| ChangeEvent {
228
+ key : key. clone ( ) ,
229
+ kind : ChangeEventKind :: Reinstalled ,
230
+ } ) )
220
231
. sorted_unstable_by ( |a, b| a. key . cmp ( & b. key ) . then_with ( || a. kind . cmp ( & b. kind ) ) )
221
232
{
222
233
match event. kind {
@@ -226,6 +237,9 @@ pub(crate) async fn install(
226
237
ChangeEventKind :: Removed => {
227
238
writeln ! ( printer. stderr( ) , " {} {}" , "-" . red( ) , event. key. bold( ) ) ?;
228
239
}
240
+ ChangeEventKind :: Reinstalled => {
241
+ writeln ! ( printer. stderr( ) , " {} {}" , "~" . yellow( ) , event. key. bold( ) , ) ?;
242
+ }
229
243
}
230
244
}
231
245
}
0 commit comments