44Not intended to be used outside compas* packages.
55"""
66import os
7- import shutil
8- import sys
7+ import re
98import tempfile
9+ import shutil
1010import subprocess
11+ import sys
1112
1213try :
1314 NotADirectoryError
@@ -16,10 +17,12 @@ class NotADirectoryError(Exception):
1617 pass
1718
1819PY3 = sys .version_info [0 ] == 3
20+ SYMLINK_REGEX = re .compile (r"\n.*\<SYMLINKD\>\s(.*)\s\[(.*)\]\r" )
1921
2022
2123__all__ = [
2224 'absjoin' ,
25+ 'realpath' ,
2326 'create_symlink' ,
2427 'create_symlinks' ,
2528 'remove_symlink' ,
@@ -252,6 +255,48 @@ def absjoin(*parts):
252255 return os .path .abspath (os .path .join (* parts ))
253256
254257
258+ def realpath (path ):
259+ """Return the canonical path of the specified filename, eliminating any symbolic links encountered in the path.
260+
261+ This function uses Python's stdlib `os.path.realpath` in most cases,
262+ except when inside IronPython because (guess what?) it is broken and
263+ doesn't really eliminate sym links, so, we fallback to a different
264+ way to identifying symlinks in that situation."""
265+ if not PY3 and is_ironpython ():
266+ if is_windows ():
267+ return _realpath_ipy_win (path )
268+ else :
269+ return _realpath_ipy_posix (path )
270+
271+ return os .path .realpath (path )
272+
273+
274+ def _realpath_ipy_win (path ):
275+ dirname = os .path .basename (path )
276+ parent_path = os .path .join (path , '..' )
277+
278+ args = 'dir /c "{}" /Al' .format (parent_path )
279+ process = subprocess .Popen (args , shell = True , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
280+
281+ output , _error = process .communicate ()
282+ matches = SYMLINK_REGEX .finditer (output )
283+ for match in matches :
284+ match_name = match .groups ()[0 ].strip ()
285+ match_link = match .groups ()[1 ]
286+
287+ if match_name == dirname :
288+ return match_link
289+
290+ return ValueError ('path not found: {}' .format (path ))
291+
292+
293+ def _realpath_ipy_posix (path ):
294+ args = 'readlink -f "{}"' .format (path )
295+ process = subprocess .Popen (args , shell = True , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
296+ output , _error = process .communicate ()
297+ return output
298+
299+
255300# Cache whatever symlink function works (native or polyfill)
256301_os_symlink = None
257302
0 commit comments