comparison mercurial/vfs.py @ 47809:98c3fa6a3ac2 stable

vfs: always use / as file separator (issue6546) Various part of vfs already enforce `/` usage and using `\` confuse the encoded vfs. So we simply use `/` all the time. Differential Revision: https://phab.mercurial-scm.org/D11260
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Thu, 05 Aug 2021 12:53:44 +0200
parents 9ab54aa56982
children 6000f5b25c9b
comparison
equal deleted inserted replaced
47808:23921bc857b5 47809:98c3fa6a3ac2
48 48
49 49
50 class abstractvfs(object): 50 class abstractvfs(object):
51 """Abstract base class; cannot be instantiated""" 51 """Abstract base class; cannot be instantiated"""
52 52
53 # default directory separator for vfs
54 #
55 # Other vfs code always use `/` and this works fine because python file API
56 # abstract the use of `/` and make it work transparently. For consistency
57 # vfs will always use `/` when joining. This avoid some confusion in
58 # encoded vfs (see issue6546)
59 _dir_sep = b'/'
60
53 def __init__(self, *args, **kwargs): 61 def __init__(self, *args, **kwargs):
54 '''Prevent instantiation; don't call this from subclasses.''' 62 '''Prevent instantiation; don't call this from subclasses.'''
55 raise NotImplementedError('attempted instantiating ' + str(type(self))) 63 raise NotImplementedError('attempted instantiating ' + str(type(self)))
56 64
57 def __call__(self, path, mode=b'rb', **kwargs): 65 def __call__(self, path, mode=b'rb', **kwargs):
150 except OSError: 158 except OSError:
151 return False 159 return False
152 mode = st.st_mode 160 mode = st.st_mode
153 return stat.S_ISREG(mode) or stat.S_ISLNK(mode) 161 return stat.S_ISREG(mode) or stat.S_ISLNK(mode)
154 162
163 def _join(self, *paths):
164 root_idx = 0
165 for idx, p in enumerate(paths):
166 if os.path.isabs(p) or p.startswith(self._dir_sep):
167 root_idx = idx
168 if root_idx != 0:
169 paths = paths[root_idx:]
170 paths = [p for p in paths if p]
171 return self._dir_sep.join(paths)
172
155 def reljoin(self, *paths): 173 def reljoin(self, *paths):
156 """join various elements of a path together (as os.path.join would do) 174 """join various elements of a path together (as os.path.join would do)
157 175
158 The vfs base is not injected so that path stay relative. This exists 176 The vfs base is not injected so that path stay relative. This exists
159 to allow handling of strange encoding if needed.""" 177 to allow handling of strange encoding if needed."""
160 return os.path.join(*paths) 178 return self._join(*paths)
161 179
162 def split(self, path): 180 def split(self, path):
163 """split top-most element of a path (as os.path.split would do) 181 """split top-most element of a path (as os.path.split would do)
164 182
165 This exists to allow handling of strange encoding if needed.""" 183 This exists to allow handling of strange encoding if needed."""
526 else: 544 else:
527 self.write(dst, src) 545 self.write(dst, src)
528 546
529 def join(self, path, *insidef): 547 def join(self, path, *insidef):
530 if path: 548 if path:
531 return os.path.join(self.base, path, *insidef) 549 parts = [self.base, path]
550 parts.extend(insidef)
551 return self._join(*parts)
532 else: 552 else:
533 return self.base 553 return self.base
534 554
535 555
536 opener = vfs 556 opener = vfs