forked from rotsehub/rotseutil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsetup_utils.py
267 lines (216 loc) · 8.36 KB
/
setup_utils.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
import os
import re
import codecs
import stat
from distutils.sysconfig import get_python_lib
def read(*parts, encoding="utf8"):
"""
Build an absolute path from *parts* and and return the contents of the
resulting file.
"""
# if not here:
# here = os.path.abspath(os.path.dirname(__file__))
path = os.path.join(*parts)
with codecs.open(path, "rb", encoding) as f:
result = f.read()
return result
def find_meta(meta, file, error=True):
"""
Extract __meta__ value from METAFILE.
file may contain:
__meta__ = 'value'
__meta__ = '''value lines '''
"""
try:
text = read(file)
except Exception as err:
raise RuntimeError("Failed to read file") from err
tbase = (r"^__{meta}__[ ]*=[ ]*(({sq}(?P<text1>(.*\n*)*?){sq})|"
"({dq}(?P<text2>(.*\n*)*?){dq}))")
sbase = (r"^__{meta}__[ ]*=[ ]*(({sq}(?P<text1>([^\n])*?){sq})|"
"({dq}(?P<text2>([^\n])*?){dq}))")
triple = tbase.format(meta=meta, sq="'''", dq='"""')
re_meta_tripple = re.compile(triple, re.M)
single = sbase.format(meta=meta, sq="'", dq='"')
re_meta_single = re.compile(single, re.M)
try:
meta_match = re_meta_tripple.search(text)
except Exception:
meta_match = None
# This is separated from exception since search may
# result with None.
if meta_match is None:
try:
meta_match = re_meta_single.search(text)
except Exception:
meta_match = None
if meta_match is not None:
match1 = meta_match.group('text1')
match2 = meta_match.group('text2')
return match1 if match1 is not None else match2
if error:
raise RuntimeError("Unable to find __{meta}__ string in {file}."
.format(meta=meta, file=file))
def read_meta_or_file(meta, metafile=None, metahost=None, error=True):
''' reads meta tag or file for text information.
if meta exists, return it. If not, and file exists,
return its content.
Args:
meta: name to look for as in __meta__; e.g.,
if meta is set to "authors", __authors__ will be sought.
metahost: python (.py) file to look for meta definitions.
metafile: text file to read if meta not found. If none, it will
look for capital(meta)*
Returns:
string of text found.
'''
text = None
if metahost:
text = find_meta(meta, file=metahost, error=False)
if text:
return text
# if metafile not provided or not found, we need to look for
# metahost and extract value from __meta__ = 'value'
# try metafile
if not metafile:
folder = os.getcwd()
elif os.path.isdir(metafile):
folder = metafile
metafile = None
if metafile:
if not os.path.isfile(metafile):
raise RuntimeError("Provided metafile not found: {}"
.format(metafile))
else:
dir_files = os.listdir(folder)
file_pattern = re.compile(
r'^({}|{}).*'.format(meta.lower(), meta.upper()))
options = [file_pattern.match(f) for f in dir_files]
options = [opt.group(0) for opt in options if opt]
if len(options) != 1:
msg = 'Too many options' if len(options) > 1\
else 'No option'
raise RuntimeError("{} for metafile '{}'; {}"
.format(msg, meta, ', '.join(options)))
metafile = os.path.join(folder, options[0])
if metafile:
if metafile.endswith('.py'):
text = find_meta(meta, file=metafile, error=False)
else:
text = read(metafile)
if not text and error:
raise RuntimeError("Provided meta not found or empty: {}"
.format(meta))
return text
def read_authors_(text):
vlines = [line for line in map(str.strip, text.split('\n')) if line]
author = ', '.join([line.rpartition(' ')[0] for line in vlines])
email = ', '.join([line.rpartition(' ')[2] for line in vlines])
return author, email
def read_authors(tag='authors', metafile=None, metahost=None):
text = read_meta_or_file(tag, metafile=metafile, metahost=metahost)
AUTHOR, AUTHOR_EMAIL = read_authors_(text)
return AUTHOR, AUTHOR_EMAIL
def read_version_(text):
''' reads version from location.
Args:
location: PACKAGE path where version.py
'''
version = text.strip() # .partition('=')[2].replace("'", "")
return version
def read_version(tag='version', metafile=None, metahost=None):
''' reads package version from either a metafile (file containing
the version string. Or from a file that would contain assignment
to __version__.
Args:
tag: the tag that would compose metafile or meta-variable in
file.
metafile: a text file that contains version string only.
file: a file that would contain assignment to meta-var. E.g.,
__version__ = '1.0.1'
Returns:
version string read from metafile or file.
'''
text = read_meta_or_file(tag, metafile=metafile, metahost=metahost)
if text:
VERSION = read_version_(text)
else:
raise RuntimeError("Cannot read {} from metafile: {},"
"or metahost: {}".format(tag, metafile,
metahost))
return VERSION
def read_required(tag='required', metafile=None, metahost=None):
try:
text = read_meta_or_file(tag, metafile=metafile, metahost=metahost)
except Exception:
text = ''
REQUIRED = []
if text:
for item in text.split('\n'):
item = item.strip()
if item:
REQUIRED += [item]
else:
raise RuntimeError("Cannot read {} from metafile: {},"
"or metahost: {}".format(tag, metafile,
metahost))
return REQUIRED
def existing_package(package):
# Warn if we are installing over top of an existing installation. This can
# cause issues where files that were deleted from a more recent Accord are
# still present in site-packages. See #18115.
overlay_warning = False
lib_paths = [get_python_lib()]
if lib_paths[0].startswith("/usr/lib/"):
# We have to try also with an explicit prefix of /usr/local
# to catch Debian's custom user site-packages directory.
lib_paths.append(get_python_lib(prefix="/usr/local"))
for lib_path in lib_paths:
existing_path = os.path.abspath(os.path.join(lib_path, package))
if os.path.exists(existing_path):
# We note the need for the warning here, but present it after
# the command is run, so it's more likely to be seen.
overlay_warning = True
break
return existing_path if overlay_warning else None
def find_packages(location):
# Find all sub packages
packages = list()
for root, _, _ in os.walk(location, topdown=False):
if os.path.isfile(os.path.join(root, '__init__.py')):
packages.append(root)
return packages
def metahost(package):
return os.path.join(package, '__init__.py')
def metafile(package, meta):
metafile = os.path.join(package, '{}.py'.format(meta.upper()))
if not os.path.isfile(metafile):
metafile = os.path.join(package, '{}.py'.format(meta.lower()))
if not os.path.isfile(metafile):
metafile = None
return metafile
def isexe(fpath):
fstat = os.stat(fpath)
mode = fstat.st_mode
x_perm = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
has_x = (mode & x_perm) > 0
return has_x and os.path.isfile(fpath)
def scripts(package):
''' pull all scripts from package/bin.This is not limited to
executables, as some scripts are sources.
'''
bindir = os.path.join(package, 'bin')
scripts = []
if os.path.isdir(bindir):
for file in os.listdir(bindir):
file = os.path.join(bindir, file)
if os.path.isfile(file) and not file.endswith('__init__.py'):
scripts += [file]
return scripts
def find_sub_packages(packages):
sub_packages = []
for package in packages:
for root, _, _ in os.walk(package, topdown=False):
if os.path.isfile(os.path.join(root, '__init__.py')):
sub_packages.append(root)
return list(set(sub_packages))