-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathpresent.py
More file actions
246 lines (192 loc) · 6.57 KB
/
present.py
File metadata and controls
246 lines (192 loc) · 6.57 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
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
# pkgs.void - web catalog of Void Linux packages.
# Copyright (C) 2019-2023 Piotr Wójcik <chocimier@tlen.pl>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from collections import Counter, namedtuple
from urllib.parse import quote as urlquote
# pylint can't import modules from create_module, so import-error
# some functions are used only in templates, so unused-import
# above makes lines too long, so noqa
import tenjin.helpers # pylint: disable=import-error
from humanize import naturalsize
from tenjin import MemoryCacheStorage, SafeEngine, SafePreprocessor
from tenjin.escaped import as_escaped, to_escaped # noqa, pylint: disable=import-error
from tenjin.helpers import echo, to_str # noqa, pylint: disable=unused-import,import-error
from custom_types import ValueAt
from settings import config
Area = namedtuple('Area', ('value', 'coords'))
class CustomPreprocessor(SafePreprocessor):
def _localvars_assignments(self):
'''
Preprocessor calls _decode_params without defining it
'''
return (
super()._localvars_assignments()
+ "_decode_params = tenjin.helpers._decode_params;"
)
class LoaderCache:
def __init__(self):
self.engine = None
def loader(self):
if config.DEVEL_MODE or self.engine is None:
self.engine = SafeEngine(
path=['templates'],
preprocess=True,
preprocessorclass=CustomPreprocessor,
cache=MemoryCacheStorage()
)
return self.engine
_loader_cache = LoaderCache()
_loader = _loader_cache.loader
def web_parameters():
return {
'root_url': config.ROOT_URL,
'assets_url': config.ASSETS_URL,
'voidlinux_url': config.VOIDLINUX_URL,
'generated_files_url': config.GENERATED_FILES_URL,
'urlquote': urlquote,
}
def parse_contact(value):
return value.split('<')[0].strip()
def render_link(href, text):
code = '<a href="{}">{}</a>'
return as_escaped(code.format(
tenjin.helpers.escape(href),
tenjin.helpers.escape(text)
))
def _masks_as_string(masks_set):
return ', '.join(map('-'.join, masks_set))
def _masks_presenter(values, space):
masks_set = _masks(values, space) or {}
return _masks_as_string(masks_set)
SNIPPET = object()
def render_template(template_path, template_mode=None, **kwargs):
context = {
'masks_presenter': _masks_presenter,
**web_parameters(),
**kwargs
}
if template_mode is SNIPPET:
return as_escaped(_loader().render(template_path, context))
return _loader().render(template_path, context, layout='base.html')
def render_paragraph(text):
return render_template('paragraph.html', text=text)
def as_new_version(versions):
return render_template(
'small/as_new_version.html',
SNIPPET, versions=versions
)
def as_package(value):
pkgname = value
pkgver = ''
for char in '><-':
pos = value.rfind(char)
if pos >= 0:
pkgname = value[:pos]
pkgver = value[pos:]
break
if pkgver == '>=0':
pkgver = ''
href = config.ROOT_URL + '/package/' + urlquote(pkgname)
if '_' in pkgver:
pairs = []
version = ''
revision = ''
while pkgver:
if revision:
if pkgver[0].isdigit():
revision += pkgver[0]
else:
pairs.append((version, revision))
version = pkgver[0]
revision = ''
else:
if pkgver[0] == '_':
revision = pkgver[0]
else:
version += pkgver[0]
pkgver = pkgver[1:]
if version:
pairs.append((version, revision))
pkgver = render_template('small/as_package.html', SNIPPET, pairs=pairs)
else:
pkgver = to_escaped(pkgver)
return as_escaped(
render_link(href, pkgname)
+ as_escaped(pkgver.rstrip('\n'))
)
def as_link(value):
return render_link(value, value)
def as_date(value):
return value
def as_popularity(value):
return f'{value}'
def as_repository(value):
name = (
value.repo
if value.repo in ['restricted', 'bootstrap']
else 'additional'
)
return render_template(
f'present/repository/{name}.html',
SNIPPET,
**value._asdict()
)
def as_size(value):
return naturalsize(value, binary=True, format='%.2f')
def _covering_labels(elems, space):
for dim in reversed(range(len(space))):
found = True
having = Counter()
for elem in elems:
having[elem[dim]] += 1
for point in having:
if having[point] != space[dim][point]:
found = False
break
if found:
return dim, having.keys()
return None
def _mask(elems, dim, point, space):
if space[dim][point] == 1:
return next(elem for elem in elems if elem[dim] == point)
return [point if i == dim else '*' for i in range(len(space))]
def _masks(elems, space):
if len(elems) == sum(space[0].values()):
return None
covering = _covering_labels(elems, space)
if covering is None:
return elems
dim, points = covering
return [_mask(elems, dim, point, space) for point in points]
def combine_simple(prop, values):
if prop.islist:
values = [
ValueAt(val, sublist.coords)
for sublist in values
for val in sublist.value
]
distinct = sorted({i.value for i in values})
variants = []
for value in distinct:
coords_of_value = [i.coords for i in values if i.value == value]
variants.append(Area(value, coords_of_value))
return variants
def combine_minmax(prop, values):
del prop
minimum = min(i.value for i in values)
maximum = max(i.value for i in values)
return {'min': minimum, 'max': maximum}
def combine_set(prop, values):
del prop
return set(i.value for i in values)