Skip to content

Commit 6c3f0f5

Browse files
committed
Always retry with polyfill on Windows
The polyfill is actually nicer than the native function because it does not require admin rights, so even if the system supports symlink creation natively, we try the polyfill if native fails.
1 parent 1836fb9 commit 6c3f0f5

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

src/compas/_os.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66
import os
77
import sys
8+
import subprocess
89

910
PY3 = sys.version_info[0] == 3
1011
system = sys.platform
@@ -65,6 +66,15 @@ def select_python(python_executable):
6566
def absjoin(*parts):
6667
return os.path.abspath(os.path.join(*parts))
6768

69+
# Cache whatever symlink function works (native or polyfill)
70+
_os_symlink = None
71+
72+
def create_symlink_polyfill():
73+
def symlink_ms(source, link_name):
74+
subprocess.check_output(
75+
['mklink', '/D', link_name, source], stderr=subprocess.STDOUT, shell=True)
76+
77+
return symlink_ms
6878

6979
def create_symlink(source, link_name):
7080
"""Create a symbolic link pointing to source named link_name.
@@ -77,19 +87,26 @@ def create_symlink(source, link_name):
7787
This function is a polyfill of the native ``os.symlink``
7888
for Python 2.x on Windows platforms.
7989
"""
80-
os_symlink = getattr(os, 'symlink', None)
81-
82-
if not callable(os_symlink) and os.name == 'nt':
83-
import subprocess
90+
global _os_symlink
91+
enable_retry_with_polyfill = False
8492

85-
def symlink_ms(source, link_name):
86-
subprocess.check_output(
87-
['mklink', '/D', link_name, source], stderr=subprocess.STDOUT, shell=True)
93+
if not _os_symlink:
94+
_os_symlink = getattr(os, 'symlink', None)
8895

89-
os_symlink = symlink_ms
96+
if os.name == 'nt':
97+
if not callable(_os_symlink):
98+
_os_symlink = create_symlink_polyfill()
99+
else:
100+
enable_retry_with_polyfill = True
90101

91-
os_symlink(source, link_name)
102+
try:
103+
_os_symlink(source, link_name)
104+
except OSError:
105+
if not enable_retry_with_polyfill:
106+
raise
92107

108+
_os_symlink = create_symlink_polyfill()
109+
_os_symlink(source, link_name)
93110

94111
def remove_symlink(link):
95112
if os.path.isdir(link):

0 commit comments

Comments
 (0)