@@ -4,6 +4,7 @@ use std::path::{Path, PathBuf};
4
4
use anyhow:: { Context , Result } ;
5
5
use duct:: cmd;
6
6
use serde:: Deserialize ;
7
+ use std:: io;
7
8
8
9
use crate :: builder:: compile:: CmdSpec ;
9
10
@@ -279,22 +280,20 @@ fn symlink_encore_dev(app_root: &Path, encore_dev_path: &Path) -> Result<()> {
279
280
let node_mod_dst = node_modules. join ( "encore.dev" ) ;
280
281
281
282
// If the node_modules directory exists, symlink the encore.dev package.
282
- if let Ok ( meta) = node_mod_dst. symlink_metadata ( ) {
283
- // Is this a symlink?
284
- if meta. is_symlink ( ) {
285
- // If the symlink is already pointing to our desired target, we're done.
286
- if let Ok ( target) = std:: fs:: read_link ( & node_mod_dst) {
287
- if target == encore_dev_path {
288
- log:: info!( "encore.dev symlink already points to the local runtime, skipping." ) ;
289
- return Ok ( ( ) ) ;
290
- }
283
+ if let Ok ( target) = read_symlink ( & node_mod_dst) {
284
+ if let Some ( target) = target {
285
+ if target == encore_dev_path {
286
+ log:: info!( "encore.dev symlink already points to the local runtime, skipping." ) ;
287
+ return Ok ( ( ) ) ;
291
288
}
292
289
293
290
// It's a symlink pointing elsewhere. Remove it.
294
- symlink :: remove_symlink_auto ( & node_mod_dst) . with_context ( || {
291
+ delete_symlink ( & node_mod_dst) . with_context ( || {
295
292
format ! ( "remove existing encore.dev symlink at {:?}" , node_mod_dst)
296
293
} ) ?;
297
- } else {
294
+ }
295
+
296
+ if node_mod_dst. exists ( ) {
298
297
// It's not a symlink. Remove the directory so we can add a symlink.
299
298
std:: fs:: remove_dir_all ( & node_mod_dst) . with_context ( || {
300
299
format ! ( "remove existing encore.dev directory at {:?}" , node_mod_dst)
@@ -304,9 +303,58 @@ fn symlink_encore_dev(app_root: &Path, encore_dev_path: &Path) -> Result<()> {
304
303
305
304
// Create the symlink if the node_modules directory exists.
306
305
if node_modules. exists ( ) {
307
- symlink :: symlink_dir ( encore_dev_path, & node_mod_dst)
306
+ create_symlink ( encore_dev_path, & node_mod_dst)
308
307
. with_context ( || format ! ( "symlink encore.dev directory at {:?}" , node_mod_dst) ) ?;
309
308
}
310
-
311
309
Ok ( ( ) )
312
310
}
311
+
312
+ #[ cfg( not( windows) ) ]
313
+ fn create_symlink ( src : & Path , dst : & Path ) -> io:: Result < ( ) > {
314
+ symlink:: symlink_dir ( src, dst)
315
+ }
316
+
317
+ #[ cfg( windows) ]
318
+ fn create_symlink ( src : & Path , dst : & Path ) -> io:: Result < ( ) > {
319
+ symlink:: symlink_dir ( src, dst) . or_else ( |_| junction:: create ( src, & dst) )
320
+ }
321
+
322
+ #[ cfg( not( windows) ) ]
323
+ fn read_symlink ( src : & Path ) -> io:: Result < Option < PathBuf > > {
324
+ if let Ok ( meta) = src. symlink_metadata ( ) {
325
+ if meta. is_symlink ( ) {
326
+ return std:: fs:: read_link ( src) . map ( Some ) ;
327
+ }
328
+ }
329
+ Ok ( None )
330
+ }
331
+
332
+ #[ cfg( windows) ]
333
+ fn read_symlink ( src : & Path ) -> io:: Result < Option < PathBuf > > {
334
+ if let Ok ( meta) = src. symlink_metadata ( ) {
335
+ // Is this a symlink?
336
+ if meta. is_symlink ( ) {
337
+ return std:: fs:: read_link ( src) . map ( Some ) ;
338
+ }
339
+ }
340
+
341
+ // Check if it's a junction.
342
+ if junction:: exists ( src) ? {
343
+ return junction:: get_target ( src) . map ( Some ) ;
344
+ }
345
+
346
+ Ok ( None )
347
+ }
348
+
349
+ #[ cfg( not( windows) ) ]
350
+ fn delete_symlink ( src : & Path ) -> io:: Result < ( ) > {
351
+ symlink:: remove_symlink_auto ( src)
352
+ }
353
+
354
+ #[ cfg( windows) ]
355
+ fn delete_symlink ( src : & Path ) -> io:: Result < ( ) > {
356
+ if let Ok ( _) = symlink:: remove_symlink_auto ( src) {
357
+ return Ok ( ( ) ) ;
358
+ }
359
+ junction:: delete ( src)
360
+ }
0 commit comments