@@ -8,6 +8,10 @@ use serde::Deserialize;
88use serde_json:: Value as JsonValue ;
99use std:: fs;
1010use std:: io;
11+ #[ cfg( unix) ]
12+ use std:: os:: unix:: fs as unix_fs;
13+ #[ cfg( windows) ]
14+ use std:: os:: windows:: fs as windows_fs;
1115use std:: path:: Path ;
1216use std:: path:: PathBuf ;
1317
@@ -348,21 +352,58 @@ fn copy_dir_recursive(source: &Path, target: &Path) -> Result<(), PluginStoreErr
348352 entry. map_err ( |err| PluginStoreError :: io ( "failed to enumerate plugin source" , err) ) ?;
349353 let source_path = entry. path ( ) ;
350354 let target_path = target. join ( entry. file_name ( ) ) ;
351- let file_type = entry
352- . file_type ( )
355+ let metadata = fs:: symlink_metadata ( & source_path)
353356 . map_err ( |err| PluginStoreError :: io ( "failed to inspect plugin source entry" , err) ) ?;
357+ let file_type = metadata. file_type ( ) ;
354358
355359 if file_type. is_dir ( ) {
356360 copy_dir_recursive ( & source_path, & target_path) ?;
357361 } else if file_type. is_file ( ) {
358362 fs:: copy ( & source_path, & target_path)
359363 . map_err ( |err| PluginStoreError :: io ( "failed to copy plugin file" , err) ) ?;
364+ } else if file_type. is_symlink ( ) {
365+ copy_symlink ( & source_path, & target_path) ?;
360366 }
361367 }
362368
363369 Ok ( ( ) )
364370}
365371
372+ #[ cfg( unix) ]
373+ fn copy_symlink ( source : & Path , target : & Path ) -> Result < ( ) , PluginStoreError > {
374+ let link_target = fs:: read_link ( source)
375+ . map_err ( |err| PluginStoreError :: io ( "failed to read plugin symlink" , err) ) ?;
376+ unix_fs:: symlink ( link_target, target)
377+ . map_err ( |err| PluginStoreError :: io ( "failed to copy plugin symlink" , err) )
378+ }
379+
380+ #[ cfg( windows) ]
381+ fn copy_symlink ( source : & Path , target : & Path ) -> Result < ( ) , PluginStoreError > {
382+ let link_target = fs:: read_link ( source)
383+ . map_err ( |err| PluginStoreError :: io ( "failed to read plugin symlink" , err) ) ?;
384+ let resolved_target = if link_target. is_absolute ( ) {
385+ link_target. clone ( )
386+ } else {
387+ source
388+ . parent ( )
389+ . map ( |parent| parent. join ( & link_target) )
390+ . unwrap_or_else ( || link_target. clone ( ) )
391+ } ;
392+ let result = if resolved_target. is_dir ( ) {
393+ windows_fs:: symlink_dir ( link_target, target)
394+ } else {
395+ windows_fs:: symlink_file ( link_target, target)
396+ } ;
397+ result. map_err ( |err| PluginStoreError :: io ( "failed to copy plugin symlink" , err) )
398+ }
399+
400+ #[ cfg( not( any( unix, windows) ) ) ]
401+ fn copy_symlink ( _source : & Path , _target : & Path ) -> Result < ( ) , PluginStoreError > {
402+ Err ( PluginStoreError :: Invalid (
403+ "plugin symlinks are not supported on this platform" . to_string ( ) ,
404+ ) )
405+ }
406+
366407#[ cfg( test) ]
367408#[ path = "store_tests.rs" ]
368409mod tests;
0 commit comments