diff options
author | Renaud Paquay <rpaquay@google.com> | 2016-11-01 11:24:03 -0700 |
---|---|---|
committer | David Pursehouse <dpursehouse@collab.net> | 2017-05-29 19:30:34 +0900 |
commit | d5cec5e752821ca2710101b626b3a3ca07fdb7f8 (patch) | |
tree | 4ecee491de2d3d57b4d03f526701c8c06a133b17 /platform_utils.py | |
parent | 2e7029116204cf2d6f516e4514091f0b492bc689 (diff) | |
download | git-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.py | 43 |
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 | |||
172 | def 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 | |||
190 | def _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 | |||
198 | def _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 | ||