forked from oils-for-unix/oils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathos_path.py
169 lines (130 loc) · 4.55 KB
/
os_path.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
"""
os_path.py - Copy of code from Python's posixpath.py and genericpath.py.
"""
import posix_ as posix
from mycpp import mylib
from typing import Tuple, List, Optional
extsep = '.'
sep = '/'
def join(s1, s2):
# type: (str, str) -> str
"""Join pathnames.
Ignore the previous parts if a part is absolute. Insert a '/' unless the
first part is empty or already ends in '/'.
Special case of os.path.join() which avoids varargs.
"""
if s2.startswith('/') or len(s1) == 0:
# absolute path
return s2
if s1.endswith('/'):
return s1 + s2
return '%s/%s' % (s1, s2)
if mylib.PYTHON:
def rstrip_slashes(s):
# type: (str) -> str
"""Helper for split() and dirname()."""
# This is an awkward implementation from the Python stdlib, but we rewrite it
# in C++.
n = len(s)
if n and s != '/'*n:
s = s.rstrip('/')
return s
# Split a path in head (everything up to the last '/') and tail (the
# rest). If the path ends in '/', tail will be empty. If there is no
# '/' in the path, head will be empty.
# Trailing '/'es are stripped from head unless it is the root.
def split(p):
# type: (str) -> Tuple[str, str]
"""Split a pathname. Returns tuple "(head, tail)" where "tail" is
everything after the final slash. Either part may be empty."""
i = p.rfind('/') + 1
head = p[:i]
tail = p[i:]
head = rstrip_slashes(head)
return head, tail
# Split a path in root and extension.
# The extension is everything starting at the last dot in the last
# pathname component; the root is everything before that.
# It is always true that root + ext == p.
# Generic implementation of splitext, to be parametrized with
# the separators
def _splitext(p, sep, extsep):
# type: (str, str, str) -> Tuple[str, str]
"""Split the extension from a pathname.
Extension is everything from the last dot to the end, ignoring
leading dots. Returns "(root, ext)"; ext may be empty."""
sepIndex = p.rfind(sep)
dotIndex = p.rfind(extsep)
if dotIndex > sepIndex:
# skip all leading dots
filenameIndex = sepIndex + 1
while filenameIndex < dotIndex:
if p[filenameIndex] != extsep:
return p[:dotIndex], p[dotIndex:]
filenameIndex += 1
return p, ''
# Split a path in root and extension.
# The extension is everything starting at the last dot in the last
# pathname component; the root is everything before that.
# It is always true that root + ext == p.
def splitext(p):
# type: (str) -> Tuple[str, str]
return _splitext(p, sep, extsep)
# Return the tail (basename) part of a path, same as split(path)[1].
def basename(p):
# type: (str) -> str
"""Returns the final component of a pathname"""
i = p.rfind('/') + 1
return p[i:]
# Return the head (dirname) part of a path, same as split(path)[0].
def dirname(p):
# type: (str) -> str
"""Returns the directory component of a pathname"""
i = p.rfind('/') + 1
head = p[:i]
head = rstrip_slashes(head)
return head
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
# It should be understood that this may change the meaning of the path
# if it contains symbolic links!
def normpath(path):
# type: (str) -> str
"""Normalize path, eliminating double slashes, etc."""
slash = '/'
dot = '.'
if path == '':
return dot
initial_slashes = path.startswith('/') # type: int
# POSIX allows one or two initial slashes, but treats three or more
# as single slash.
if (initial_slashes and
path.startswith('//') and not path.startswith('///')):
initial_slashes = 2
comps = path.split('/')
new_comps = [] # type: List[str]
for comp in comps:
if len(comp) == 0 or comp == '.': # mycpp rewrite: comp in ('', '.')
continue
if (comp != '..' or (initial_slashes == 0 and len(new_comps) == 0) or
(len(new_comps) and new_comps[-1] == '..')):
new_comps.append(comp)
elif len(new_comps):
new_comps.pop()
comps = new_comps
path = slash.join(comps)
if initial_slashes:
path = slash*initial_slashes + path
return path if len(path) else dot
# Return whether a path is absolute.
# Trivial in Posix, harder on the Mac or MS-DOS.
def isabs(s):
# type: (str) -> bool
"""Test whether a path is absolute"""
return s.startswith('/')
def abspath(path):
# type: (str) -> str
"""Return an absolute path."""
if not isabs(path):
cwd = posix.getcwd()
path = join(cwd, path)
return normpath(path)