1 import datetime
2 from six.moves.urllib.parse import urlparse
3 import pytz
4 import time
5
6 try:
7 import commonmark
8 except:
9
10 import CommonMark as commonmark
11
12 from pygments import highlight
13 from pygments.lexers import get_lexer_by_name, guess_lexer
14 from pygments.lexers.special import TextLexer
15 from pygments.util import ClassNotFound
16 from pygments.formatters import HtmlFormatter
17
18 import humanize
19 import os
20 import re
21
22 from flask import Markup, url_for
23
24 from copr_common.enums import ModuleStatusEnum, StatusEnum
25 from coprs import app
26 from coprs import helpers
30 info_words = node.info.split() if node.info else []
31 attrs = self.attrs(node)
32 lexer = None
33
34 if len(info_words) > 0 and len(info_words[0]) > 0:
35 try:
36 code = commonmark.common.escape_xml(info_words[0])
37 except TypeError:
38
39 code = commonmark.common.escape_xml(info_words[0], True)
40 attrs.append(['class', 'language-' + code])
41
42 try:
43 lexer = get_lexer_by_name(info_words[0])
44 except ClassNotFound:
45 pass
46
47 if lexer is None:
48 try:
49 lexer = guess_lexer(node.literal)
50 except ClassNotFound:
51 lexer = TextLexer
52
53 self.cr()
54 self.tag('pre')
55 self.tag('code', attrs)
56 code = highlight(node.literal, lexer, HtmlFormatter())
57 code = re.sub('<pre>', '', code)
58 code = re.sub('</pre>', '', code)
59 self.lit(code)
60 self.tag('/code')
61 self.tag('/pre')
62 self.cr()
63
64
65 @app.template_filter("remove_anchor")
66 -def remove_anchor(data):
72
75 if secs:
76 return time.strftime("%Y-%m-%d %H:%M:%S %Z", time.gmtime(secs))
77
78 return None
79
83 return helpers.PermissionEnum(num)
84
88 if num is None:
89 return "unknown"
90 return StatusEnum(num)
91
95 if num is None:
96 return "unknown"
97 return ModuleStatusEnum(num)
98
99
100 @app.template_filter("os_name_short")
101 -def os_name_short(os_name, os_version):
111
112
113 @app.template_filter('localized_time')
114 -def localized_time(time_in, timezone):
115 """ return time shifted into timezone (and printed in ISO format)
116
117 Input is in EPOCH (seconds since epoch).
118 """
119 if not time_in:
120 return "Not yet"
121 format_tz = "%Y-%m-%d %H:%M %Z"
122 utc_tz = pytz.timezone('UTC')
123 if timezone:
124 user_tz = pytz.timezone(timezone)
125 else:
126 user_tz = utc_tz
127 dt_aware = datetime.datetime.fromtimestamp(time_in).replace(tzinfo=utc_tz)
128 dt_my_tz = dt_aware.astimezone(user_tz)
129 return dt_my_tz.strftime(format_tz)
130
131
132 @app.template_filter('timestamp_diff')
133 -def timestamp_diff(time_in, until=None):
134 """ returns string with difference between two timestamps
135
136 Input is in EPOCH (seconds since epoch).
137 """
138 if time_in is None:
139 return " - "
140 if until is not None:
141 now = datetime.datetime.fromtimestamp(until)
142 else:
143 now = datetime.datetime.now()
144 diff = now - datetime.datetime.fromtimestamp(time_in)
145 return str(int(diff.total_seconds()))
146
147
148 @app.template_filter('time_ago')
149 -def time_ago(time_in, until=None):
150 """ returns string saying how long ago the time on input was
151
152 Input is in EPOCH (seconds since epoch).
153 """
154 if time_in is None:
155 return " - "
156 if until is not None:
157 now = datetime.datetime.fromtimestamp(until)
158 else:
159 now = datetime.datetime.now()
160 diff = now - datetime.datetime.fromtimestamp(time_in)
161 return humanize.naturaldelta(diff)
162
173
180
184 if pkg is not None:
185 return os.path.basename(pkg)
186 return pkg
187
191
192 description_map = {
193 "failed": "Build failed. See logs for more details.",
194 "succeeded": "Successfully built.",
195 "canceled": "The build has been cancelled manually.",
196 "running": "Build in progress.",
197 "pending": "Build is waiting in queue for a backend worker.",
198 "skipped": "This package has already been built previously.",
199 "starting": "Backend worker is trying to acquire a builder machine.",
200 "importing": "Package sources are being imported into Copr DistGit.",
201 "waiting": "Task is waiting for something else to finish.",
202 "imported": "Package was successfully imported into Copr DistGit.",
203 "forked": "Build has been forked from another build.",
204 }
205
206 return description_map.get(state, "")
207
211 description_map = {
212 "unset": "No default source",
213 "link": "External link to .spec or SRPM",
214 "upload": "SRPM or .spec file upload",
215 "scm": "Build from an SCM repository",
216 "pypi": "Build from PyPI",
217 "rubygems": "Build from RubyGems",
218 "custom": "Custom build method",
219 "distgit": "Build from DistGit",
220 }
221
222 return description_map.get(state, "")
223
227 if app.config.get('REPO_NO_SSL', False):
228 return url.replace('https://', 'http://')
229 return helpers.fix_protocol_for_backend(url)
230
234 return helpers.fix_protocol_for_frontend(url)
235
236 @app.template_filter("repo_url")
237 -def repo_url(url):
238 """
239 render copr://<user>/<prj> or copr://g/<group>/<prj>
240 to be rendered as copr projects pages
241 """
242 parsed = urlparse(url)
243 if parsed.scheme == "copr":
244 owner = parsed.netloc
245 prj = parsed.path.split("/")[1]
246 if owner[0] == '@':
247 url = url_for("coprs_ns.copr_detail", group_name=owner[1:], coprname=prj)
248 else:
249 url = url_for("coprs_ns.copr_detail", username=owner, coprname=prj)
250
251 return helpers.fix_protocol_for_frontend(url)
252
253 @app.template_filter("mailto")
254 -def mailto(url):
255 return url if urlparse(url).scheme else "mailto:{}".format(url)
256