summaryrefslogtreecommitdiffstats
path: root/platform_utils.py
diff options
context:
space:
mode:
authorRenaud Paquay <rpaquay@google.com>2016-11-01 11:24:03 -0700
committerDavid Pursehouse <dpursehouse@collab.net>2017-05-29 19:30:34 +0900
commitd5cec5e752821ca2710101b626b3a3ca07fdb7f8 (patch)
tree4ecee491de2d3d57b4d03f526701c8c06a133b17 /platform_utils.py
parent2e7029116204cf2d6f516e4514091f0b492bc689 (diff)
downloadgit-repo-d5cec5e752821ca2710101b626b3a3ca07fdb7f8.tar.gz
Add support for creating symbolic links on Windows
Replace all calls to os.symlink with platform_utils.symlink. The Windows implementation calls into the CreateSymbolicLinkW Win32 API, as os.symlink is not supported. Separate the Win32 API definitions into a separate module platform_utils_win32 for clarity. Change-Id: I0714c598664c2df93383734e609d948692c17ec5
Diffstat (limited to 'platform_utils.py')
-rw-r--r--platform_utils.py43
1 files changed, 43 insertions, 0 deletions
diff --git a/platform_utils.py b/platform_utils.py
index 1c719b1d..f4dfa0b1 100644
--- a/platform_utils.py
+++ b/platform_utils.py
@@ -167,3 +167,46 @@ class _FileDescriptorStreamsThreads(FileDescriptorStreams):
167 self.queue.put(_FileDescriptorStreamsThreads.QueueItem(self, line)) 167 self.queue.put(_FileDescriptorStreamsThreads.QueueItem(self, line))
168 self.fd.close() 168 self.fd.close()
169 self.queue.put(_FileDescriptorStreamsThreads.QueueItem(self, None)) 169 self.queue.put(_FileDescriptorStreamsThreads.QueueItem(self, None))
170
171
172def symlink(source, link_name):
173 """Creates a symbolic link pointing to source named link_name.
174 Note: On Windows, source must exist on disk, as the implementation needs
175 to know whether to create a "File" or a "Directory" symbolic link.
176 """
177 if isWindows():
178 import platform_utils_win32
179 source = _validate_winpath(source)
180 link_name = _validate_winpath(link_name)
181 target = os.path.join(os.path.dirname(link_name), source)
182 if os.path.isdir(target):
183 platform_utils_win32.create_dirsymlink(source, link_name)
184 else:
185 platform_utils_win32.create_filesymlink(source, link_name)
186 else:
187 return os.symlink(source, link_name)
188
189
190def _validate_winpath(path):
191 path = os.path.normpath(path)
192 if _winpath_is_valid(path):
193 return path
194 raise ValueError("Path \"%s\" must be a relative path or an absolute "
195 "path starting with a drive letter".format(path))
196
197
198def _winpath_is_valid(path):
199 """Windows only: returns True if path is relative (e.g. ".\\foo") or is
200 absolute including a drive letter (e.g. "c:\\foo"). Returns False if path
201 is ambiguous (e.g. "x:foo" or "\\foo").
202 """
203 assert isWindows()
204 path = os.path.normpath(path)
205 drive, tail = os.path.splitdrive(path)
206 if tail:
207 if not drive:
208 return tail[0] != os.sep # "\\foo" is invalid
209 else:
210 return tail[0] == os.sep # "x:foo" is invalid
211 else:
212 return not drive # "x:" is invalid