55mod hash;
66mod installed_package;
77mod srcref;
8+ #[ cfg( any( test, feature = "testing" ) ) ]
9+ pub mod test;
10+ pub mod traits;
811
912use std:: collections:: HashSet ;
13+ use std:: path:: Path ;
1014use std:: path:: PathBuf ;
1115use std:: sync:: RwLock ;
1216
@@ -35,6 +39,12 @@ const METADATA_FILENAME: &str = ".metadata";
3539/// the DESCRIPTION `Build:` timestamp being different).
3640const ONE_WEEK : TimeDelta = TimeDelta :: weeks ( 1 ) ;
3741
42+ impl crate :: traits:: PackageCache for PackageCache {
43+ fn get ( & self , package : & str ) -> Option < PathBuf > {
44+ self . get ( package)
45+ }
46+ }
47+
3848/// A cache of extracted R package sources
3949///
4050/// # On disk layout
@@ -109,12 +119,13 @@ const ONE_WEEK: TimeDelta = TimeDelta::weeks(1);
109119///
110120/// [`get`]: PackageCache::get
111121/// [`clean`]: PackageCache::clean
122+ #[ derive( Debug ) ]
112123pub struct PackageCache {
113- /// Path to `R` binary
124+ /// Path to an R executable
114125 r : PathBuf ,
115126
116- /// Set of R library paths
117- r_libpaths : Vec < PathBuf > ,
127+ /// Library paths to consider
128+ library_paths : Vec < PathBuf > ,
118129
119130 /// On disk cache directory root
120131 cache_root : file_lock:: Filesystem ,
@@ -148,7 +159,7 @@ struct Metadata {
148159}
149160
150161impl PackageCache {
151- pub fn new ( r : PathBuf , r_libpaths : Vec < PathBuf > ) -> anyhow:: Result < Self > {
162+ pub fn new ( r : PathBuf , library_paths : Vec < PathBuf > ) -> anyhow:: Result < Self > {
152163 let cache_root = file_lock:: Filesystem :: new ( crate :: fs:: sources_dir ( ) ?) ;
153164 cache_root. create_dir ( ) ?;
154165
@@ -165,7 +176,7 @@ impl PackageCache {
165176
166177 Ok ( Self {
167178 r,
168- r_libpaths ,
179+ library_paths ,
169180 cache_root,
170181 cache_root_lock,
171182 source_unavailable : RwLock :: new ( HashSet :: new ( ) ) ,
@@ -188,7 +199,7 @@ impl PackageCache {
188199 }
189200
190201 fn get_result ( & self , package : & str ) -> anyhow:: Result < Option < PathBuf > > {
191- let Some ( package) = InstalledPackage :: find ( package, & self . r_libpaths ) ? else {
202+ let Some ( package) = InstalledPackage :: find ( package, & self . library_paths ) ? else {
192203 // Not even installed
193204 return Ok ( None ) ;
194205 } ;
@@ -212,9 +223,9 @@ impl PackageCache {
212223 // Write path
213224 let result = if matches ! ( package. description( ) . priority, Some ( Priority :: Base ) ) {
214225 // R version to download is the same as the base package version
215- self . try_populate_base ( & package. description ( ) . version )
226+ self . try_populate_base ( & package. description ( ) . version , & self . library_paths )
216227 } else {
217- self . try_populate ( & package)
228+ self . try_populate ( & package, & self . r , & self . library_paths )
218229 } ;
219230
220231 match result {
@@ -245,7 +256,11 @@ impl PackageCache {
245256 }
246257 }
247258
248- fn try_populate_base ( & self , version : & str ) -> anyhow:: Result < bool > {
259+ fn try_populate_base < P : AsRef < Path > > (
260+ & self ,
261+ version : & str ,
262+ library_paths : & [ P ] ,
263+ ) -> anyhow:: Result < bool > {
249264 // Download the R sources in their entirety
250265 let Some ( bytes) = crate :: base:: download ( version) ? else {
251266 log:: trace!( "No R source tarball on CRAN for version {version}" ) ;
@@ -254,7 +269,7 @@ impl PackageCache {
254269
255270 // Populate all base packages from the download
256271 for package in crate :: base:: BASE_PACKAGES {
257- let Some ( package) = InstalledPackage :: find ( package, & self . r_libpaths ) ? else {
272+ let Some ( package) = InstalledPackage :: find ( package, library_paths ) ? else {
258273 // It would be very odd to not find a base package
259274 return Ok ( false ) ;
260275 } ;
@@ -304,14 +319,24 @@ impl PackageCache {
304319 ) ?;
305320 }
306321
322+ crate :: fs:: copy_as_readonly (
323+ package. index_path ( ) ,
324+ destination_lock. parent ( ) . join ( "INDEX" ) ,
325+ ) ?;
326+
307327 // Last! `.metadata` is the completion sentinel.
308328 self . write_metadata ( package, & destination_lock) ?;
309329
310330 Ok ( ( ) )
311331 }
312332
313333 /// Writes `DESCRIPTION`, `NAMESPACE`, and `R/` to the cache entry, if possible
314- fn try_populate ( & self , package : & InstalledPackage ) -> anyhow:: Result < bool > {
334+ fn try_populate < P : AsRef < Path > , Q : AsRef < Path > > (
335+ & self ,
336+ package : & InstalledPackage ,
337+ r : P ,
338+ library_paths : & [ Q ] ,
339+ ) -> anyhow:: Result < bool > {
315340 // Take per-key exclusive lock
316341 let destination = self . cache_root . join ( package. key ( ) ) ;
317342 destination. create_dir ( ) ?;
@@ -326,7 +351,7 @@ impl PackageCache {
326351 // writing `.metadata`.
327352 destination_lock. remove_siblings ( ) ?;
328353
329- if !self . write_r_files ( package, & destination_lock) ? {
354+ if !self . write_r_files ( package, r , library_paths , & destination_lock) ? {
330355 return Ok ( false ) ;
331356 }
332357
@@ -338,25 +363,31 @@ impl PackageCache {
338363 package. namespace_path ( ) ,
339364 destination_lock. parent ( ) . join ( "NAMESPACE" ) ,
340365 ) ?;
366+ crate :: fs:: copy_as_readonly (
367+ package. index_path ( ) ,
368+ destination_lock. parent ( ) . join ( "INDEX" ) ,
369+ ) ?;
341370
342371 // Last! Only write `.metadata` if all other writes succeed. It is our completion sentinal.
343372 self . write_metadata ( package, & destination_lock) ?;
344373
345374 Ok ( true )
346375 }
347376
348- fn write_r_files (
377+ fn write_r_files < P : AsRef < Path > , Q : AsRef < Path > > (
349378 & self ,
350379 package : & InstalledPackage ,
380+ r : P ,
381+ library_paths : & [ Q ] ,
351382 destination_lock : & FileLock ,
352383 ) -> anyhow:: Result < bool > {
353384 // Try caching from srcref
354385 match crate :: srcref:: cache_srcref (
355386 package. name ( ) ,
356387 & package. description ( ) . version ,
357388 destination_lock,
358- & self . r ,
359- & self . r_libpaths ,
389+ r,
390+ library_paths ,
360391 ) {
361392 Ok ( true ) => {
362393 log:: trace!(
@@ -515,22 +546,3 @@ impl PackageCache {
515546 Ok ( ( ) )
516547 }
517548}
518-
519- // // For local testing
520- // #[cfg(test)]
521- // mod tests {
522- // use std::path::PathBuf;
523- //
524- // use crate::PackageCache;
525- //
526- // #[test]
527- // fn testit() {
528- // let r_script_path = PathBuf::from("/usr/local/bin/Rscript");
529- // let r_libpaths = vec![
530- // PathBuf::from("/Users/davis/Library/R/arm64/4.5/library"),
531- // PathBuf::from("/Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/library"),
532- // ];
533- // let cache = PackageCache::new(r_script_path, r_libpaths).unwrap();
534- // cache.get("utils");
535- // }
536- // }
0 commit comments