-
Notifications
You must be signed in to change notification settings - Fork 4
/
__init__.py
164 lines (128 loc) · 5.47 KB
/
__init__.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
import logging
import os
from collections import OrderedDict
from contextlib import ContextDecorator
from jinja2 import Environment, PackageLoader, Template
from medikit import settings
from medikit.events import attach_subscriptions
from medikit.file import File
from medikit.settings import DEFAULT_FEATURES
from medikit.utils import is_identifier, format_file_content
from yapf import yapf_api
from mondrian import term
ABSOLUTE_PRIORITY = -100
HIGH_PRIORITY = -80
MEDIUM_PRIORITY = -60
LOW_PRIORITY = -60
SUPPORT_PRIORITY = -20
LAST_PRIORITY = 100
class Feature(object):
_jinja_environment = None
requires = set()
conflicts = set()
file_type = staticmethod(File)
__usage__ = None
class Config(ContextDecorator):
def __enter__(self):
return self
def __exit__(self, *exc):
return False
def __init__(self, dispatcher):
"""
:param LoggingDispatcher dispatcher:
"""
self.dispatcher = dispatcher
self.configure()
attach_subscriptions(self, self.dispatcher)
def configure(self):
pass
def file(self, *args, **kwargs):
return self.file_type(self.dispatcher, *args, **kwargs)
@property
def __name__(self):
return type(self).__name__
@property
def __shortname__(self):
return self.__name__.replace("Feature", "").lower()
@property
def jinja(self):
if type(self)._jinja_environment is None:
type(self)._jinja_environment = Environment(loader=PackageLoader(__name__, "template"))
return type(self)._jinja_environment
def _log_file(self, target, override, content=()):
self.dispatcher.info(
term.bold(term.red("W!") if override else term.green("W?")), target, "({} bytes)".format(len(content))
)
def render(self, template, context=None):
context = context or {}
os.path.join(os.path.dirname(__file__), "template")
return self.jinja.get_template(template).render(**(context or {}))
def render_file(self, target, template, context=None, *, executable=False, override=False, force_python=False):
with self.file(target, executable=executable, override=override) as f:
content = format_file_content(self.render(template, context))
if force_python or target.endswith(".py"):
content, modified = yapf_api.FormatCode(content, filename=target)
f.write(content)
self._log_file(target, override, content)
def render_file_inline(self, target, template_string, context=None, override=False, force_python=False):
with self.file(target, override=override) as f:
content = format_file_content(Template(template_string).render(**(context or {})))
if force_python or target.endswith(".py"):
content, modified = yapf_api.FormatCode(
content, filename=target, style_config=settings.YAPF_STYLE_CONFIG
)
f.write(content)
self._log_file(target, override, content)
def render_empty_files(self, *targets, **kwargs):
override = kwargs.pop("override", False)
for target in targets:
with self.file(target, override=override) as f:
self._log_file(target, override)
def get_config(self, event, feature=None):
"""
Retrieve the config object for a feature, defaults to current feature.
:param event: event from which to extract the config.
:param feature: feature name, or None for current.
:return: Feature.Config
"""
return event.config[feature or self.__shortname__]
class ProjectInitializer(Feature):
def __init__(self, dispatcher, options, target=None):
super().__init__(dispatcher)
self.options = options
self.target = target
def execute(self):
context = {"name": ""}
if self.options.get("name"):
if not is_identifier(self.options["name"]):
raise RuntimeError(
"Invalid package name {!r}. Please only use valid python identifiers.".format(self.options["name"])
)
context["name"] = self.options["name"]
elif self.target:
context["name"] = os.path.basename(self.target)
while not is_identifier(context["name"]):
context["name"] = input("Name: ")
logging.error(
"Invalid package name {!r}. Please only use valid python identifiers.".format(context["name"])
)
logging.info("name = %s", context["name"])
if self.options.get("description"):
context["description"] = self.options["description"]
else:
context["description"] = input("Description: ")
if self.options.get("license"):
context["license"] = self.options["license"]
else:
context["license"] = (
input("License [Apache License, Version 2.0]: ").strip() or "Apache License, Version 2.0"
)
context["url"] = ""
context["download_url"] = ""
context["author"] = ""
context["author_email"] = ""
context["features"] = DEFAULT_FEATURES
if self.options.get("features"):
context["features"] = context["features"].union(self.options["features"])
context["requirements"] = self.options.get("requirements", [])
self.render_file("Projectfile", "Projectfile.j2", context, override=True, force_python=True)