forked from robotframework/robotframework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrobotpath.py
More file actions
176 lines (147 loc) · 5.74 KB
/
robotpath.py
File metadata and controls
176 lines (147 loc) · 5.74 KB
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
170
171
172
173
174
175
176
# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import os.path
import sys
from robot.errors import DataError
from .encoding import system_decode
from .platform import IRONPYTHON, PY_VERSION, PY2, WINDOWS
from .robottypes import is_unicode
from .unic import unic
if IRONPYTHON and PY_VERSION == (2, 7, 8):
# https://github.com/IronLanguages/ironpython2/issues/371
def _abspath(path):
if os.path.isabs(path):
if not os.path.splitdrive(path)[0]:
drive = os.path.splitdrive(os.getcwd())[0]
return drive + path
return path
return os.path.abspath(path)
else:
_abspath = os.path.abspath
if PY2:
from urllib import pathname2url
def path_to_url(path):
return pathname2url(path.encode('UTF-8'))
else:
from urllib.request import pathname2url as path_to_url
if WINDOWS:
CASE_INSENSITIVE_FILESYSTEM = True
else:
try:
CASE_INSENSITIVE_FILESYSTEM = os.listdir('/tmp') == os.listdir('/TMP')
except OSError:
CASE_INSENSITIVE_FILESYSTEM = False
def normpath(path, case_normalize=False):
"""Replacement for os.path.normpath with some enhancements.
1. Convert non-Unicode paths to Unicode using the file system encoding.
2. NFC normalize Unicode paths (affects mainly OSX).
3. Optionally lower-case paths on case-insensitive file systems.
That includes Windows and also OSX in default configuration.
4. Turn ``c:`` into ``c:\\`` on Windows instead of keeping it as ``c:``.
"""
if not is_unicode(path):
path = system_decode(path)
path = unic(path) # Handles NFC normalization on OSX
path = os.path.normpath(path)
if case_normalize and CASE_INSENSITIVE_FILESYSTEM:
path = path.lower()
if WINDOWS and len(path) == 2 and path[1] == ':':
return path + '\\'
return path
def abspath(path, case_normalize=False):
"""Replacement for os.path.abspath with some enhancements and bug fixes.
1. Non-Unicode paths are converted to Unicode using file system encoding.
2. Optionally lower-case paths on case-insensitive file systems.
That includes Windows and also OSX in default configuration.
3. Turn ``c:`` into ``c:\\`` on Windows instead of ``c:\\current\\path``.
"""
path = normpath(path, case_normalize)
return normpath(_abspath(path), case_normalize)
def get_link_path(target, base):
"""Returns a relative path to ``target`` from ``base``.
If ``base`` is an existing file, then its parent directory is considered to
be the base. Otherwise ``base`` is assumed to be a directory.
The returned path is URL encoded. On Windows returns an absolute path with
``file:`` prefix if the target is on a different drive.
"""
path = _get_link_path(target, base)
url = path_to_url(path)
if os.path.isabs(path):
url = 'file:' + url
return url
def _get_link_path(target, base):
target = abspath(target)
base = abspath(base)
if os.path.isfile(base):
base = os.path.dirname(base)
if base == target:
return '.'
base_drive, base_path = os.path.splitdrive(base)
# Target and base on different drives
if os.path.splitdrive(target)[0] != base_drive:
return target
common_len = len(_common_path(base, target))
if base_path == os.sep:
return target[common_len:]
if common_len == len(base_drive) + len(os.sep):
common_len -= len(os.sep)
dirs_up = os.sep.join([os.pardir] * base[common_len:].count(os.sep))
path = os.path.join(dirs_up, target[common_len + len(os.sep):])
return os.path.normpath(path)
def _common_path(p1, p2):
"""Returns the longest path common to p1 and p2.
Rationale: as os.path.commonprefix is character based, it doesn't consider
path separators as such, so it may return invalid paths:
commonprefix(('/foo/bar/', '/foo/baz.txt')) -> '/foo/ba' (instead of /foo)
"""
while p1 and p2:
if p1 == p2:
return p1
if len(p1) > len(p2):
p1 = os.path.dirname(p1)
else:
p2 = os.path.dirname(p2)
return ''
def find_file(path, basedir='.', file_type=None):
path = os.path.normpath(path.replace('/', os.sep))
if os.path.isabs(path):
ret = _find_absolute_path(path)
else:
ret = _find_relative_path(path, basedir)
if ret:
return ret
default = file_type or 'File'
file_type = {'Library': 'Test library',
'Variables': 'Variable file',
'Resource': 'Resource file'}.get(file_type, default)
raise DataError("%s '%s' does not exist." % (file_type, path))
def _find_absolute_path(path):
if _is_valid_file(path):
return path
return None
def _find_relative_path(path, basedir):
for base in [basedir] + sys.path:
if not (base and os.path.isdir(base)):
continue
if not is_unicode(base):
base = system_decode(base)
ret = os.path.abspath(os.path.join(base, path))
if _is_valid_file(ret):
return ret
return None
def _is_valid_file(path):
return os.path.isfile(path) or \
(os.path.isdir(path) and os.path.isfile(os.path.join(path, '__init__.py')))