@@ -1177,7 +1177,7 @@ const
1177
1177
# # On Windows ``["exe", "cmd", "bat"]``, on Posix ``[""]``.
1178
1178
when defined (windows): [" exe" , " cmd" , " bat" ] else : [" " ]
1179
1179
1180
- proc findExe * (exe: string , followSymlinks: bool = true ;
1180
+ proc findExe * (exe: string , followSymlinks = true ;
1181
1181
extensions: openArray [string ]= ExeExts ): string {.
1182
1182
tags : [ReadDirEffect , ReadEnvEffect , ReadIOEffect ], noNimJs .} =
1183
1183
# # Searches for `exe` in the current working directory and then
@@ -1647,8 +1647,11 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
1647
1647
var res2 = setFileAttributesA (filename, res)
1648
1648
if res2 == - 1 'i32 : raiseOSError (osLastError (), $ (filename, permissions))
1649
1649
1650
- proc copyFile * (source, dest: string ) {.rtl , extern : " nos$1" ,
1651
- tags : [ReadIOEffect , WriteIOEffect ], noWeirdTarget .} =
1650
+ proc createSymlink * (src, dest: string ) {.tags : [ReadDirEffect , WriteIOEffect ], noWeirdTarget .}
1651
+ proc expandSymlink * (symlinkPath: string ): string {.tags : [ReadIOEffect ], noWeirdTarget .}
1652
+
1653
+ proc copyFile * (source, dest: string , followSymlinks = true ) {.rtl , extern : " nos$1" ,
1654
+ tags : [ReadDirEffect , ReadIOEffect , WriteIOEffect ], noWeirdTarget .} =
1652
1655
# # Copies a file from `source` to `dest`, where `dest.parentDir` must exist.
1653
1656
# #
1654
1657
# # If this fails, `OSError` is raised.
@@ -1668,11 +1671,11 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
1668
1671
# # will be preserved and the content overwritten.
1669
1672
# #
1670
1673
# # See also:
1671
- # # * `copyDir proc <#copyDir,string,string>`_
1674
+ # # * `copyDir proc <#copyDir,string,string,bool >`_
1672
1675
# # * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_
1673
1676
# # * `tryRemoveFile proc <#tryRemoveFile,string>`_
1674
1677
# # * `removeFile proc <#removeFile,string>`_
1675
- # # * `moveFile proc <#moveFile,string,string>`_
1678
+ # # * `moveFile proc <#moveFile,string,string,bool >`_
1676
1679
1677
1680
when defined (Windows ):
1678
1681
when useWinUnicode:
@@ -1682,34 +1685,37 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
1682
1685
else :
1683
1686
if copyFileA (source, dest, 0 'i32 ) == 0 'i32 : raiseOSError (osLastError (), $ (source, dest))
1684
1687
else :
1685
- # generic version of copyFile which works for any platform:
1686
- const bufSize = 8000 # better for memory manager
1687
- var d, s: File
1688
- if not open (s, source): raiseOSError (osLastError (), source)
1689
- if not open (d, dest, fmWrite):
1688
+ if not followSymlinks and source.checkSymlink:
1689
+ createSymlink (expandSymlink (source), dest)
1690
+ else :
1691
+ # generic version of copyFile which works for any platform:
1692
+ const bufSize = 8000 # better for memory manager
1693
+ var d, s: File
1694
+ if not open (s, source): raiseOSError (osLastError (), source)
1695
+ if not open (d, dest, fmWrite):
1696
+ close (s)
1697
+ raiseOSError (osLastError (), dest)
1698
+ var buf = alloc (bufSize)
1699
+ while true :
1700
+ var bytesread = readBuffer (s, buf, bufSize)
1701
+ if bytesread > 0 :
1702
+ var byteswritten = writeBuffer (d, buf, bytesread)
1703
+ if bytesread != byteswritten:
1704
+ dealloc (buf)
1705
+ close (s)
1706
+ close (d)
1707
+ raiseOSError (osLastError (), dest)
1708
+ if bytesread != bufSize: break
1709
+ dealloc (buf)
1690
1710
close (s)
1691
- raiseOSError (osLastError (), dest)
1692
- var buf = alloc (bufSize)
1693
- while true :
1694
- var bytesread = readBuffer (s, buf, bufSize)
1695
- if bytesread > 0 :
1696
- var byteswritten = writeBuffer (d, buf, bytesread)
1697
- if bytesread != byteswritten:
1698
- dealloc (buf)
1699
- close (s)
1700
- close (d)
1701
- raiseOSError (osLastError (), dest)
1702
- if bytesread != bufSize: break
1703
- dealloc (buf)
1704
- close (s)
1705
- flushFile (d)
1706
- close (d)
1707
-
1708
- proc copyFileToDir * (source, dir: string ) {.noWeirdTarget , since : (1 ,3 ,7 ).} =
1711
+ flushFile (d)
1712
+ close (d)
1713
+
1714
+ proc copyFileToDir * (source, dir: string , followSymlinks = true ) {.noWeirdTarget , since : (1 ,3 ,7 ).} =
1709
1715
# # Copies a file `source` into directory `dir`, which must exist.
1710
1716
if dir.len == 0 : # treating "" as "." is error prone
1711
1717
raise newException (ValueError , " dest is empty" )
1712
- copyFile (source, dir / source.lastPathPart)
1718
+ copyFile (source, dir / source.lastPathPart, followSymlinks = followSymlinks )
1713
1719
1714
1720
when not declared (ENOENT ) and not defined (Windows ):
1715
1721
when NoFakeVars :
@@ -1739,10 +1745,10 @@ proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirE
1739
1745
# # On Windows, ignores the read-only attribute.
1740
1746
# #
1741
1747
# # See also:
1742
- # # * `copyFile proc <#copyFile,string,string>`_
1748
+ # # * `copyFile proc <#copyFile,string,string,bool >`_
1743
1749
# # * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_
1744
1750
# # * `removeFile proc <#removeFile,string>`_
1745
- # # * `moveFile proc <#moveFile,string,string>`_
1751
+ # # * `moveFile proc <#moveFile,string,string,bool >`_
1746
1752
result = true
1747
1753
when defined (Windows ):
1748
1754
when useWinUnicode:
@@ -1772,10 +1778,10 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], n
1772
1778
# #
1773
1779
# # See also:
1774
1780
# # * `removeDir proc <#removeDir,string>`_
1775
- # # * `copyFile proc <#copyFile,string,string>`_
1781
+ # # * `copyFile proc <#copyFile,string,string,bool >`_
1776
1782
# # * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_
1777
1783
# # * `tryRemoveFile proc <#tryRemoveFile,string>`_
1778
- # # * `moveFile proc <#moveFile,string,string>`_
1784
+ # # * `moveFile proc <#moveFile,string,string,bool >`_
1779
1785
if not tryRemoveFile (file):
1780
1786
raiseOSError (osLastError (), file)
1781
1787
@@ -1802,8 +1808,8 @@ proc tryMoveFSObject(source, dest: string): bool {.noWeirdTarget.} =
1802
1808
raiseOSError (err, $ (source, dest, strerror (errno)))
1803
1809
return true
1804
1810
1805
- proc moveFile * (source, dest: string ) {.rtl , extern : " nos$1" ,
1806
- tags : [ReadIOEffect , WriteIOEffect ], noWeirdTarget .} =
1811
+ proc moveFile * (source, dest: string , followSymlinks = true ) {.rtl , extern : " nos$1" ,
1812
+ tags : [ReadDirEffect , ReadIOEffect , WriteIOEffect ], noWeirdTarget .} =
1807
1813
# # Moves a file from `source` to `dest`.
1808
1814
# #
1809
1815
# # If this fails, `OSError` is raised.
@@ -1812,16 +1818,16 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
1812
1818
# # Can be used to `rename files`:idx:.
1813
1819
# #
1814
1820
# # See also:
1815
- # # * `moveDir proc <#moveDir,string,string>`_
1816
- # # * `copyFile proc <#copyFile,string,string>`_
1821
+ # # * `moveDir proc <#moveDir,string,string,bool >`_
1822
+ # # * `copyFile proc <#copyFile,string,string,bool >`_
1817
1823
# # * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_
1818
1824
# # * `removeFile proc <#removeFile,string>`_
1819
1825
# # * `tryRemoveFile proc <#tryRemoveFile,string>`_
1820
1826
1821
1827
if not tryMoveFSObject (source, dest):
1822
1828
when not defined (windows):
1823
1829
# Fallback to copy & del
1824
- copyFile (source, dest)
1830
+ copyFile (source, dest, followSymlinks = followSymlinks )
1825
1831
try :
1826
1832
removeFile (source)
1827
1833
except :
@@ -2223,9 +2229,9 @@ proc removeDir*(dir: string, checkDir = false) {.rtl, extern: "nos$1", tags: [
2223
2229
# # * `removeFile proc <#removeFile,string>`_
2224
2230
# # * `existsOrCreateDir proc <#existsOrCreateDir,string>`_
2225
2231
# # * `createDir proc <#createDir,string>`_
2226
- # # * `copyDir proc <#copyDir,string,string>`_
2227
- # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_
2228
- # # * `moveDir proc <#moveDir,string,string>`_
2232
+ # # * `copyDir proc <#copyDir,string,string,bool >`_
2233
+ # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string,bool >`_
2234
+ # # * `moveDir proc <#moveDir,string,string,bool >`_
2229
2235
for kind, path in walkDir (dir, checkDir = checkDir):
2230
2236
case kind
2231
2237
of pcFile, pcLinkToFile, pcLinkToDir: removeFile (path)
@@ -2290,9 +2296,9 @@ proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1",
2290
2296
# # See also:
2291
2297
# # * `removeDir proc <#removeDir,string>`_
2292
2298
# # * `createDir proc <#createDir,string>`_
2293
- # # * `copyDir proc <#copyDir,string,string>`_
2294
- # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_
2295
- # # * `moveDir proc <#moveDir,string,string>`_
2299
+ # # * `copyDir proc <#copyDir,string,string,bool >`_
2300
+ # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string,bool >`_
2301
+ # # * `moveDir proc <#moveDir,string,string,bool >`_
2296
2302
result = not rawCreateDir (dir)
2297
2303
if result :
2298
2304
# path already exists - need to check that it is indeed a directory
@@ -2312,9 +2318,9 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
2312
2318
# # See also:
2313
2319
# # * `removeDir proc <#removeDir,string>`_
2314
2320
# # * `existsOrCreateDir proc <#existsOrCreateDir,string>`_
2315
- # # * `copyDir proc <#copyDir,string,string>`_
2316
- # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_
2317
- # # * `moveDir proc <#moveDir,string,string>`_
2321
+ # # * `copyDir proc <#copyDir,string,string,bool >`_
2322
+ # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string,bool >`_
2323
+ # # * `moveDir proc <#moveDir,string,string,bool >`_
2318
2324
var omitNext = false
2319
2325
when doslikeFileSystem:
2320
2326
omitNext = isAbsolute (dir)
@@ -2330,8 +2336,8 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
2330
2336
dir[^ 1 ] notin {DirSep , AltSep }:
2331
2337
discard existsOrCreateDir (dir)
2332
2338
2333
- proc copyDir * (source, dest: string ) {.rtl , extern : " nos$1" ,
2334
- tags : [WriteIOEffect , ReadIOEffect ], benign , noWeirdTarget .} =
2339
+ proc copyDir * (source, dest: string , followSymlinks = true ) {.rtl , extern : " nos$1" ,
2340
+ tags : [ReadDirEffect , ReadIOEffect , WriteIOEffect ], benign , noWeirdTarget .} =
2335
2341
# # Copies a directory from `source` to `dest`.
2336
2342
# #
2337
2343
# # If this fails, `OSError` is raised.
@@ -2341,46 +2347,47 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
2341
2347
# #
2342
2348
# # On other platforms created files and directories will inherit the
2343
2349
# # default permissions of a newly created file/directory for the user.
2344
- # # Use `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_
2350
+ # # Use `copyDirWithPermissions proc <#copyDirWithPermissions,string,string,bool >`_
2345
2351
# # to preserve attributes recursively on these platforms.
2346
2352
# #
2347
2353
# # See also:
2348
- # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_
2349
- # # * `copyFile proc <#copyFile,string,string>`_
2354
+ # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string,bool >`_
2355
+ # # * `copyFile proc <#copyFile,string,string,bool >`_
2350
2356
# # * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_
2351
2357
# # * `removeDir proc <#removeDir,string>`_
2352
2358
# # * `existsOrCreateDir proc <#existsOrCreateDir,string>`_
2353
2359
# # * `createDir proc <#createDir,string>`_
2354
- # # * `moveDir proc <#moveDir,string,string>`_
2360
+ # # * `moveDir proc <#moveDir,string,string,bool >`_
2355
2361
createDir (dest)
2356
2362
for kind, path in walkDir (source):
2357
2363
var noSource = splitPath (path).tail
2358
2364
case kind
2359
2365
of pcFile:
2360
- copyFile (path, dest / noSource)
2366
+ copyFile (path, dest / noSource, followSymlinks = followSymlinks )
2361
2367
of pcDir:
2362
- copyDir (path, dest / noSource)
2368
+ copyDir (path, dest / noSource, followSymlinks = followSymlinks )
2363
2369
else : discard
2364
2370
2365
- proc moveDir * (source, dest: string ) {.tags : [ReadIOEffect , WriteIOEffect ], noWeirdTarget .} =
2371
+ proc moveDir * (source, dest: string , followSymlinks = true ) {.tags : [ReadDirEffect , ReadIOEffect , WriteIOEffect ],
2372
+ noWeirdTarget .} =
2366
2373
# # Moves a directory from `source` to `dest`.
2367
2374
# #
2368
2375
# # If this fails, `OSError` is raised.
2369
2376
# #
2370
2377
# # See also:
2371
- # # * `moveFile proc <#moveFile,string,string>`_
2372
- # # * `copyDir proc <#copyDir,string,string>`_
2373
- # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_
2378
+ # # * `moveFile proc <#moveFile,string,string,bool >`_
2379
+ # # * `copyDir proc <#copyDir,string,string,bool >`_
2380
+ # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string,bool >`_
2374
2381
# # * `removeDir proc <#removeDir,string>`_
2375
2382
# # * `existsOrCreateDir proc <#existsOrCreateDir,string>`_
2376
2383
# # * `createDir proc <#createDir,string>`_
2377
2384
if not tryMoveFSObject (source, dest):
2378
2385
when not defined (windows):
2379
2386
# Fallback to copy & del
2380
- copyDir (source, dest)
2387
+ copyDir (source, dest, followSymlinks = followSymlinks )
2381
2388
removeDir (source)
2382
2389
2383
- proc createSymlink * (src, dest: string ) {.noWeirdTarget .} =
2390
+ proc createSymlink * (src, dest: string ) {.tags : [ ReadDirEffect , WriteIOEffect ], noWeirdTarget .} =
2384
2391
# # Create a symbolic link at `dest` which points to the item specified
2385
2392
# # by `src`. On most operating systems, will fail if a link already exists.
2386
2393
# #
@@ -2431,7 +2438,7 @@ proc createHardlink*(src, dest: string) {.noWeirdTarget.} =
2431
2438
raiseOSError (osLastError (), $ (src, dest))
2432
2439
2433
2440
proc copyFileWithPermissions * (source, dest: string ,
2434
- ignorePermissionErrors = true ) {.noWeirdTarget .} =
2441
+ ignorePermissionErrors = true , followSymlinks = true ) {.noWeirdTarget .} =
2435
2442
# # Copies a file from `source` to `dest` preserving file permissions.
2436
2443
# #
2437
2444
# # This is a wrapper proc around `copyFile <#copyFile,string,string>`_,
@@ -2450,12 +2457,12 @@ proc copyFileWithPermissions*(source, dest: string,
2450
2457
# #
2451
2458
# # See also:
2452
2459
# # * `copyFile proc <#copyFile,string,string>`_
2453
- # # * `copyDir proc <#copyDir,string,string>`_
2460
+ # # * `copyDir proc <#copyDir,string,string,bool >`_
2454
2461
# # * `tryRemoveFile proc <#tryRemoveFile,string>`_
2455
2462
# # * `removeFile proc <#removeFile,string>`_
2456
- # # * `moveFile proc <#moveFile,string,string>`_
2457
- # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_
2458
- copyFile (source, dest)
2463
+ # # * `moveFile proc <#moveFile,string,string,bool >`_
2464
+ # # * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string,bool >`_
2465
+ copyFile (source, dest, followSymlinks = followSymlinks )
2459
2466
when not defined (Windows ):
2460
2467
try :
2461
2468
setFilePermissions (dest, getFilePermissions (source))
@@ -2464,17 +2471,17 @@ proc copyFileWithPermissions*(source, dest: string,
2464
2471
raise
2465
2472
2466
2473
proc copyDirWithPermissions * (source, dest: string ,
2467
- ignorePermissionErrors = true ) {.rtl , extern : " nos$1" ,
2474
+ ignorePermissionErrors = true , followSymlinks = true ) {.rtl , extern : " nos$1" ,
2468
2475
tags : [WriteIOEffect , ReadIOEffect ], benign , noWeirdTarget .} =
2469
2476
# # Copies a directory from `source` to `dest` preserving file permissions.
2470
2477
# #
2471
2478
# # If this fails, `OSError` is raised. This is a wrapper proc around `copyDir
2472
- # # <#copyDir,string,string>`_ and `copyFileWithPermissions
2479
+ # # <#copyDir,string,string,bool >`_ and `copyFileWithPermissions
2473
2480
# # <#copyFileWithPermissions,string,string>`_ procs
2474
2481
# # on non-Windows platforms.
2475
2482
# #
2476
2483
# # On Windows this proc is just a wrapper for `copyDir proc
2477
- # # <#copyDir,string,string>`_ since that proc already copies attributes.
2484
+ # # <#copyDir,string,string,bool >`_ since that proc already copies attributes.
2478
2485
# #
2479
2486
# # On non-Windows systems permissions are copied after the file or directory
2480
2487
# # itself has been copied, which won't happen atomically and could lead to a
@@ -2483,11 +2490,11 @@ proc copyDirWithPermissions*(source, dest: string,
2483
2490
# # `OSError`.
2484
2491
# #
2485
2492
# # See also:
2486
- # # * `copyDir proc <#copyDir,string,string>`_
2493
+ # # * `copyDir proc <#copyDir,string,string,bool >`_
2487
2494
# # * `copyFile proc <#copyFile,string,string>`_
2488
2495
# # * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_
2489
2496
# # * `removeDir proc <#removeDir,string>`_
2490
- # # * `moveDir proc <#moveDir,string,string>`_
2497
+ # # * `moveDir proc <#moveDir,string,string,bool >`_
2491
2498
# # * `existsOrCreateDir proc <#existsOrCreateDir,string>`_
2492
2499
# # * `createDir proc <#createDir,string>`_
2493
2500
createDir (dest)
@@ -2501,9 +2508,9 @@ proc copyDirWithPermissions*(source, dest: string,
2501
2508
var noSource = splitPath (path).tail
2502
2509
case kind
2503
2510
of pcFile:
2504
- copyFileWithPermissions (path, dest / noSource, ignorePermissionErrors)
2511
+ copyFileWithPermissions (path, dest / noSource, ignorePermissionErrors, followSymlinks = followSymlinks )
2505
2512
of pcDir:
2506
- copyDirWithPermissions (path, dest / noSource, ignorePermissionErrors)
2513
+ copyDirWithPermissions (path, dest / noSource, ignorePermissionErrors, followSymlinks = followSymlinks )
2507
2514
else : discard
2508
2515
2509
2516
proc inclFilePermissions * (filename: string ,
@@ -2524,7 +2531,7 @@ proc exclFilePermissions*(filename: string,
2524
2531
# # setFilePermissions(filename, getFilePermissions(filename)-permissions)
2525
2532
setFilePermissions (filename, getFilePermissions (filename)- permissions)
2526
2533
2527
- proc expandSymlink * (symlinkPath: string ): string {.noWeirdTarget .} =
2534
+ proc expandSymlink * (symlinkPath: string ): string {.tags : [ ReadIOEffect ], noWeirdTarget .} =
2528
2535
# # Returns a string representing the path to which the symbolic link points.
2529
2536
# #
2530
2537
# # On Windows this is a noop, ``symlinkPath`` is simply returned.
0 commit comments