@@ -4,6 +4,7 @@ use std::path::{Path, PathBuf};
44use anyhow:: { Context , Result } ;
55use duct:: cmd;
66use serde:: Deserialize ;
7+ use std:: io;
78
89use crate :: builder:: compile:: CmdSpec ;
910
@@ -279,22 +280,20 @@ fn symlink_encore_dev(app_root: &Path, encore_dev_path: &Path) -> Result<()> {
279280 let node_mod_dst = node_modules. join ( "encore.dev" ) ;
280281
281282 // 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 ( ( ) ) ;
291288 }
292289
293290 // 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 ( || {
295292 format ! ( "remove existing encore.dev symlink at {:?}" , node_mod_dst)
296293 } ) ?;
297- } else {
294+ }
295+
296+ if node_mod_dst. exists ( ) {
298297 // It's not a symlink. Remove the directory so we can add a symlink.
299298 std:: fs:: remove_dir_all ( & node_mod_dst) . with_context ( || {
300299 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<()> {
304303
305304 // Create the symlink if the node_modules directory exists.
306305 if node_modules. exists ( ) {
307- symlink :: symlink_dir ( encore_dev_path, & node_mod_dst)
306+ create_symlink ( encore_dev_path, & node_mod_dst)
308307 . with_context ( || format ! ( "symlink encore.dev directory at {:?}" , node_mod_dst) ) ?;
309308 }
310-
311309 Ok ( ( ) )
312310}
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