-
Notifications
You must be signed in to change notification settings - Fork 2
/
setup.py
129 lines (104 loc) · 4.74 KB
/
setup.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
# This file is vendored from Autorelease
import os
import ast
import sys
import fnmatch # Py 2
from setuptools import setup
def _glob_glob_recursive(directory, pattern):
# python 2 glob.glob doesn't have a recursive keyword
# this implements for the specific case that we want an exact match
# See also https://stackoverflow.com/a/2186565
matches = []
for root, dirname, filenames in os.walk(directory):
matches.extend([os.path.join(root, filename)
for filename in fnmatch.filter(filenames, pattern)])
return matches
class VersionPyFinder(object):
_VERSION_PY_FUNCTIONS = ['get_git_version', 'get_setup_cfg']
def __init__(self, filename='version.py', max_depth=2):
self.filename_base = filename
self.max_depth = max_depth
self.depth = None
self.filename = os.getenv("AUTORELEASE_VERSION_PY",
self._first_eligible())
self.functions = self._get_functions(self.filename)
def _find_files(self):
# all_files = glob.glob("**/" + self.filename_base, recursive=True)
all_files = _glob_glob_recursive('.', self.filename_base)
meets_depth = [fname for fname in all_files
if len(fname.split(os.sep)) <= self.max_depth + 1]
return meets_depth
def _is_eligible(self, filename):
with open(filename, mode='r') as f:
contents = f.read()
tree = ast.parse(contents)
# we requrie that our functions be defined at module level -- we
# know that's how we wrote them, at least!
all_functions = [node.name for node in tree.body
if isinstance(node, ast.FunctionDef)]
return all(func in all_functions
for func in self._VERSION_PY_FUNCTIONS)
def _first_eligible(self):
all_files = self._find_files()
for fname in all_files:
if self._is_eligible(fname):
return fname
return None
@property
def version_setup_depth(self):
def get_depth(fname):
return len(os.path.abspath(fname).split(os.sep))
# we assume thta setup.py is in the same dir as setup.cfg
diff = get_depth(self.filename) - get_depth(__file__)
return diff
def _get_functions(self, filename):
with open(self.filename, mode='r') as f:
contents = f.read()
tree = ast.parse(contents)
class MakeImportError(ast.NodeTransformer):
"""converts a from x import y into an import error"""
def __init__(self, import_name):
self.import_name = import_name
def visit_ImportFrom(self, node):
if node.module == self.import_name:
replacement = ast.Raise(exc=ast.Call(
func=ast.Name(id='ImportError', ctx=ast.Load()),
args=[],
keywords=[],
), cause=None)
return ast.copy_location(replacement, node)
else:
return node
import_remover = MakeImportError("_installed_version")
tree = import_remover.visit(tree)
ast.fix_missing_locations(tree)
locs = dict(globals())
exec(compile(tree, filename="version.py", mode='exec'), locs)
return {f: locs[f] for f in self._VERSION_PY_FUNCTIONS}
def write_installed_version_py(filename="_installed_version.py",
src_dir=None):
version_finder = VersionPyFinder()
directory = os.path.dirname(version_finder.filename)
depth = version_finder.version_setup_depth
get_git_version = version_finder.functions['get_git_version']
get_setup_cfg = version_finder.functions['get_setup_cfg']
installed_version = os.path.join(directory, "_installed_version.py")
content = "_installed_version = '{vers}'\n"
content += "_installed_git_hash = '{git}'\n"
content += "_version_setup_depth = {depth}\n"
# question: if I use the __file__ attribute in something I compile from
# here, what is the file?
my_dir = os.path.abspath(os.path.dirname(__file__))
conf = get_setup_cfg(directory=my_dir, filename='setup.cfg')
# conf = get_setup_cfg(directory=my_dir, filename='new_setup.cfg')
version = conf.get('metadata', 'version')
git_rev = get_git_version()
if src_dir is None:
src_dir = conf.get('metadata', 'name')
with open (os.path.join(src_dir, filename), 'w') as f:
f.write(content.format(vers=version, git=git_rev, depth=depth))
if __name__ == "__main__":
# TODO: only write version.py under special circumstances
write_installed_version_py(src_dir='paths_cli')
# write_version_py(os.path.join('autorelease', 'version.py'))
setup()