2
2
3
3
use std:: {
4
4
collections:: HashMap ,
5
- fs,
6
5
path:: { Path , PathBuf } ,
7
6
} ;
8
7
8
+ use fs_err as fs;
9
+
9
10
use drop_bomb:: DropBomb ;
10
- use rattler_conda_types:: { package:: PathsJson , PackageName , PrefixRecord } ;
11
+ use rattler_conda_types:: {
12
+ package:: { IndexJson , PathsEntry } ,
13
+ PackageName , PrefixRecord ,
14
+ } ;
11
15
12
16
/// A registry for clobbering files
13
17
/// The registry keeps track of all files that are installed by a package and
14
18
/// can be used to rename files that are already installed by another package.
15
- #[ derive( Debug ) ]
16
19
pub struct ClobberRegistry {
17
20
paths_registry : HashMap < PathBuf , usize > ,
18
21
clobbers : HashMap < PathBuf , Vec < usize > > ,
@@ -103,10 +106,11 @@ impl ClobberRegistry {
103
106
/// will "unclobber" the files after all packages have been installed.
104
107
pub fn register_paths (
105
108
& mut self ,
106
- name : & PackageName ,
107
- paths_json : & PathsJson ,
109
+ index_json : & IndexJson ,
110
+ computed_paths : & Vec < ( PathsEntry , PathBuf ) > ,
108
111
) -> HashMap < PathBuf , PathBuf > {
109
112
let mut clobber_paths = HashMap :: new ( ) ;
113
+ let name = & index_json. name . clone ( ) ;
110
114
111
115
// check if we have the package name already registered
112
116
let name_idx = if let Some ( idx) = self . package_names . iter ( ) . position ( |n| n == name) {
@@ -116,25 +120,51 @@ impl ClobberRegistry {
116
120
self . package_names . len ( ) - 1
117
121
} ;
118
122
119
- for entry in paths_json. paths . iter ( ) {
120
- let path = entry. relative_path . clone ( ) ;
121
-
123
+ // let entry_points = if index_json.noarch.is_python() {
124
+ // let mut res = Vec::new();
125
+ // if let (Some(link_json), Some(python_info)) = (link_json, python_info) {
126
+ // // register entry points
127
+ // if let NoArchLinks::Python(entry_points) = &link_json.noarch {
128
+ // for entry_point in &entry_points.entry_points {
129
+ // if python_info.platform.is_windows() {
130
+ // let relative_path_script_py = python_info
131
+ // .bin_dir
132
+ // .join(format!("{}-script.py", &entry_point.command));
133
+ // let relative_path_script_exe = python_info
134
+ // .bin_dir
135
+ // .join(format!("{}.exe", &entry_point.command));
136
+ // res.push(relative_path_script_py);
137
+ // res.push(relative_path_script_exe);
138
+ // } else {
139
+ // let file = python_info.bin_dir.join(&entry_point.command);
140
+ // res.push(file);
141
+ // }
142
+ // }
143
+ // }
144
+ // }
145
+ // res
146
+ // } else {
147
+ // Vec::new()
148
+ // };
149
+
150
+ for ( _, path) in computed_paths {
122
151
// if we find an entry, we have a clobbering path!
123
- if let Some ( e) = self . paths_registry . get ( & path) {
152
+ if let Some ( e) = self . paths_registry . get ( path) {
124
153
if e == & name_idx {
125
154
// A name cannot appear twice in an environment.
126
155
// We get into this case if a package is updated (removed and installed again with a new version)
127
156
continue ;
128
157
}
129
- let new_path = Self :: clobber_name ( & path, & self . package_names [ name_idx] ) ;
158
+ let new_path = Self :: clobber_name ( path, & self . package_names [ name_idx] ) ;
130
159
self . clobbers
131
160
. entry ( path. clone ( ) )
132
161
. or_insert_with ( || vec ! [ * e] )
133
162
. push ( name_idx) ;
134
163
135
- clobber_paths. insert ( path, new_path) ;
164
+ // We insert the non-renamed path here
165
+ clobber_paths. insert ( path. clone ( ) , new_path) ;
136
166
} else {
137
- self . paths_registry . insert ( path, name_idx) ;
167
+ self . paths_registry . insert ( path. clone ( ) , name_idx) ;
138
168
}
139
169
}
140
170
@@ -170,7 +200,7 @@ impl ClobberRegistry {
170
200
let winner = sorted_clobbered_by. last ( ) . expect ( "No winner found" ) ;
171
201
172
202
if winner. 1 == clobbered_by_names[ 0 ] {
173
- tracing:: debug !(
203
+ tracing:: info !(
174
204
"clobbering decision: keep {} from {:?}" ,
175
205
path. display( ) ,
176
206
winner
@@ -181,7 +211,10 @@ impl ClobberRegistry {
181
211
let loser_name = & clobbered_by_names[ 0 ] ;
182
212
let loser_path = Self :: clobber_name ( path, loser_name) ;
183
213
184
- fs:: rename ( target_prefix. join ( path) , target_prefix. join ( & loser_path) ) ?;
214
+ if let Err ( e) = fs:: rename ( target_prefix. join ( path) , target_prefix. join ( & loser_path) ) {
215
+ tracing:: info!( "could not rename file: {}" , e) ;
216
+ continue ;
217
+ }
185
218
186
219
let loser_idx = sorted_clobbered_by
187
220
. iter ( )
@@ -196,7 +229,7 @@ impl ClobberRegistry {
196
229
true ,
197
230
) ;
198
231
199
- tracing:: debug !(
232
+ tracing:: info !(
200
233
"clobbering decision: remove {} from {:?}" ,
201
234
path. display( ) ,
202
235
loser_name
@@ -208,13 +241,13 @@ impl ClobberRegistry {
208
241
209
242
let winner_path = Self :: clobber_name ( path, & winner. 1 ) ;
210
243
211
- tracing:: debug !(
244
+ tracing:: info !(
212
245
"clobbering decision: choose {} from {:?}" ,
213
246
path. display( ) ,
214
247
winner
215
248
) ;
216
249
217
- std :: fs:: rename ( target_prefix. join ( & winner_path) , target_prefix. join ( path) ) ?;
250
+ fs:: rename ( target_prefix. join ( & winner_path) , target_prefix. join ( path) ) ?;
218
251
219
252
let winner_prefix_record = rename_path_in_prefix_record (
220
253
sorted_prefix_records[ winner. 0 ] ,
@@ -275,12 +308,14 @@ mod tests {
275
308
use std:: {
276
309
fs,
277
310
path:: { Path , PathBuf } ,
311
+ str:: FromStr ,
278
312
} ;
279
313
280
314
use futures:: TryFutureExt ;
281
315
use rand:: seq:: SliceRandom ;
282
316
use rattler_conda_types:: {
283
317
package:: IndexJson , PackageRecord , Platform , PrefixRecord , RepoDataRecord ,
318
+ Version ,
284
319
} ;
285
320
use rattler_digest:: { Md5 , Sha256 } ;
286
321
use rattler_networking:: retry_policies:: default_retry_policy;
@@ -289,12 +324,13 @@ mod tests {
289
324
290
325
use crate :: {
291
326
get_test_data_dir,
292
- install:: { transaction, unlink_package, InstallDriver , InstallOptions } ,
327
+ install:: { transaction, unlink_package, InstallDriver , InstallOptions , PythonInfo } ,
293
328
package_cache:: PackageCache ,
294
329
} ;
295
330
296
331
fn get_repodata_record ( filename : & str ) -> RepoDataRecord {
297
332
let path = fs:: canonicalize ( get_test_data_dir ( ) . join ( filename) ) . unwrap ( ) ;
333
+ print ! ( "{:?}" , path) ;
298
334
let index_json = read_package_file :: < IndexJson > ( & path) . unwrap ( ) ;
299
335
300
336
// find size and hash
@@ -465,6 +501,18 @@ mod tests {
465
501
]
466
502
}
467
503
504
+ fn test_python_noarch_operations ( ) -> Vec < TransactionOperation < PrefixRecord , RepoDataRecord > > {
505
+ let repodata_record_1 =
506
+ get_repodata_record ( "clobber/clobber-pynoarch-1-0.1.0-pyh4616a5c_0.tar.bz2" ) ;
507
+ let repodata_record_2 =
508
+ get_repodata_record ( "clobber/clobber-pynoarch-2-0.1.0-pyh4616a5c_0.tar.bz2" ) ;
509
+
510
+ vec ! [
511
+ TransactionOperation :: Install ( repodata_record_1) ,
512
+ TransactionOperation :: Install ( repodata_record_2) ,
513
+ ]
514
+ }
515
+
468
516
fn test_operations_nested ( ) -> Vec < TransactionOperation < PrefixRecord , RepoDataRecord > > {
469
517
let repodata_record_1 =
470
518
get_repodata_record ( "clobber/clobber-nested-1-0.1.0-h4616a5c_0.tar.bz2" ) ;
@@ -502,6 +550,8 @@ mod tests {
502
550
. collect :: < Vec < _ > > ( ) ;
503
551
504
552
assert_eq ! ( files. len( ) , expected_files. len( ) ) ;
553
+ println ! ( "{:?}" , files) ;
554
+
505
555
for file in files {
506
556
assert ! ( expected_files. contains( & file. file_name( ) . unwrap( ) . to_string_lossy( ) . as_ref( ) ) ) ;
507
557
}
@@ -929,6 +979,7 @@ mod tests {
929
979
platform : Platform :: current ( ) ,
930
980
} ;
931
981
982
+ let prefix_records = PrefixRecord :: collect_from_prefix ( target_prefix. path ( ) ) . unwrap ( ) ;
932
983
let install_driver = InstallDriver :: new ( 100 , Some ( & prefix_records) ) ;
933
984
934
985
execute_transaction (
@@ -948,5 +999,82 @@ mod tests {
948
999
fs:: read_to_string( target_prefix. path( ) . join( "clobber.txt" ) ) . unwrap( ) ,
949
1000
"clobber-3 v2\n "
950
1001
) ;
1002
+
1003
+ let update_ops = test_operations_update ( ) ;
1004
+
1005
+ // remove one of the clobbering files
1006
+ let transaction = transaction:: Transaction :: < PrefixRecord , RepoDataRecord > {
1007
+ operations : vec ! [ TransactionOperation :: Install ( update_ops[ 0 ] . clone( ) ) ] ,
1008
+ python_info : None ,
1009
+ current_python_info : None ,
1010
+ platform : Platform :: current ( ) ,
1011
+ } ;
1012
+
1013
+ let prefix_records = PrefixRecord :: collect_from_prefix ( target_prefix. path ( ) ) . unwrap ( ) ;
1014
+ let install_driver = InstallDriver :: new ( 100 , Some ( & prefix_records) ) ;
1015
+
1016
+ execute_transaction (
1017
+ transaction,
1018
+ target_prefix. path ( ) ,
1019
+ & reqwest_middleware:: ClientWithMiddleware :: from ( reqwest:: Client :: new ( ) ) ,
1020
+ & cache,
1021
+ & install_driver,
1022
+ & InstallOptions :: default ( ) ,
1023
+ )
1024
+ . await ;
1025
+
1026
+ assert_check_files (
1027
+ target_prefix. path ( ) ,
1028
+ & [ "clobber.txt" , "clobber.txt__clobber-from-clobber-3" ] ,
1029
+ ) ;
1030
+
1031
+ // content of clobber.txt
1032
+ assert_eq ! (
1033
+ fs:: read_to_string( target_prefix. path( ) . join( "clobber.txt" ) ) . unwrap( ) ,
1034
+ "clobber-1 v2\n "
1035
+ ) ;
1036
+ }
1037
+
1038
+ #[ tokio:: test]
1039
+ async fn test_clobber_python_noarch ( ) {
1040
+ // Create a transaction
1041
+ let operations = test_python_noarch_operations ( ) ;
1042
+
1043
+ let python_info =
1044
+ PythonInfo :: from_version ( & Version :: from_str ( "3.11.0" ) . unwrap ( ) , Platform :: current ( ) )
1045
+ . unwrap ( ) ;
1046
+ let transaction = transaction:: Transaction :: < PrefixRecord , RepoDataRecord > {
1047
+ operations,
1048
+ python_info : Some ( python_info. clone ( ) ) ,
1049
+ current_python_info : Some ( python_info. clone ( ) ) ,
1050
+ platform : Platform :: current ( ) ,
1051
+ } ;
1052
+
1053
+ // execute transaction
1054
+ let target_prefix = tempfile:: tempdir ( ) . unwrap ( ) ;
1055
+
1056
+ let packages_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
1057
+ let cache = PackageCache :: new ( packages_dir. path ( ) ) ;
1058
+
1059
+ let mut install_options = InstallOptions :: default ( ) ;
1060
+ install_options. python_info = Some ( python_info. clone ( ) ) ;
1061
+
1062
+ execute_transaction (
1063
+ transaction,
1064
+ target_prefix. path ( ) ,
1065
+ & reqwest_middleware:: ClientWithMiddleware :: from ( reqwest:: Client :: new ( ) ) ,
1066
+ & cache,
1067
+ & InstallDriver :: default ( ) ,
1068
+ & install_options,
1069
+ )
1070
+ . await ;
1071
+
1072
+ // check that the files are there
1073
+ assert_check_files (
1074
+ & target_prefix
1075
+ . path ( )
1076
+ . join ( "lib/python3.11/site-packages/clobber" ) ,
1077
+ & [ "clobber.py" , "clobber.py__clobber-from-clobber-pynoarch-2" ] ,
1078
+ ) ;
951
1079
}
952
1080
}
0 commit comments