1 import datetime
2 from six.moves.urllib.parse import urlparse
3 import pytz
4 import time
5
6 import CommonMark
7 from pygments import highlight
8 from pygments.lexers import get_lexer_by_name, guess_lexer
9 from pygments.lexers.special import TextLexer
10 from pygments.util import ClassNotFound
11 from pygments.formatters import HtmlFormatter
12
13 import os
14 import re
15
16 from flask import Markup, url_for
17
18 from coprs import app
19 from coprs import helpers
23 info_words = node.info.split() if node.info else []
24 attrs = self.attrs(node)
25 lexer = None
26
27 if len(info_words) > 0 and len(info_words[0]) > 0:
28 attrs.append(['class', 'language-' +
29 CommonMark.common.escape_xml(info_words[0], True)])
30 try:
31 lexer = get_lexer_by_name(info_words[0])
32 except ClassNotFound:
33 pass
34
35 if lexer is None:
36 try:
37 lexer = guess_lexer(node.literal)
38 except ClassNotFound:
39 lexer = TextLexer
40
41 self.cr()
42 self.tag('pre')
43 self.tag('code', attrs)
44 code = highlight(node.literal, lexer, HtmlFormatter())
45 code = re.sub('<pre>', '', code)
46 code = re.sub('</pre>', '', code)
47 self.lit(code)
48 self.tag('/code')
49 self.tag('/pre')
50 self.cr()
51
52
53 @app.template_filter("remove_anchor")
54 -def remove_anchor(data):
60
63 if secs:
64 return time.strftime("%Y-%m-%d %H:%M:%S %Z", time.gmtime(secs))
65
66 return None
67
72
79
86
87
88 @app.template_filter("os_name_short")
89 -def os_name_short(os_name, os_version):
99
100
101 @app.template_filter('localized_time')
102 -def localized_time(time_in, timezone):
103 """ return time shifted into timezone (and printed in ISO format)
104
105 Input is in EPOCH (seconds since epoch).
106 """
107 if not time_in:
108 return "Not yet"
109 format_tz = "%Y-%m-%d %H:%M %Z"
110 utc_tz = pytz.timezone('UTC')
111 if timezone:
112 user_tz = pytz.timezone(timezone)
113 else:
114 user_tz = utc_tz
115 dt_aware = datetime.datetime.fromtimestamp(time_in).replace(tzinfo=utc_tz)
116 dt_my_tz = dt_aware.astimezone(user_tz)
117 return dt_my_tz.strftime(format_tz)
118
119
120 @app.template_filter('timestamp_diff')
121 -def timestamp_diff(time_in, until=None):
122 """ returns string with difference between two timestamps
123
124 Input is in EPOCH (seconds since epoch).
125 """
126 if time_in is None:
127 return " - "
128 if until is not None:
129 now = datetime.datetime.fromtimestamp(until)
130 else:
131 now = datetime.datetime.now()
132 diff = now - datetime.datetime.fromtimestamp(time_in)
133 return str(int(diff.total_seconds()))
134
135
136 @app.template_filter('time_ago')
137 -def time_ago(time_in, until=None):
138 """ returns string saying how long ago the time on input was
139
140 Input is in EPOCH (seconds since epoch).
141 """
142 if time_in is None:
143 return " - "
144 if until is not None:
145 now = datetime.datetime.fromtimestamp(until)
146 else:
147 now = datetime.datetime.now()
148 diff = now - datetime.datetime.fromtimestamp(time_in)
149 secdiff = int(diff.total_seconds())
150 if secdiff < 120:
151
152 return "1 minute"
153 elif secdiff < 7200:
154
155 return str(secdiff // 60) + " minutes"
156 elif secdiff < 172800:
157
158 return str(secdiff // 3600) + " hours"
159 elif secdiff < 5184000:
160
161 return str(secdiff // 86400) + " days"
162 elif secdiff < 63072000:
163
164 return str(secdiff // 2592000) + " months"
165 else:
166
167 return str(secdiff // 31536000) + " years"
168
179
186
190 if pkg is not None:
191 return os.path.basename(pkg)
192 return pkg
193
197
198 description_map = {
199 "failed": "Build failed. See logs for more details.",
200 "succeeded": "Successfully built.",
201 "canceled": "The build has been cancelled manually.",
202 "running": "Build in progress.",
203 "pending": "Your build is waiting for a builder.",
204 "skipped": "This package has already been built previously.",
205 "starting": "Trying to acquire and configure builder for task.",
206 "importing": "Package content is being imported into Dist Git."
207 }
208
209 return description_map.get(state, "")
210
214 description_map = {
215 "unset": "No default source",
216 "link": "External link to .spec or SRPM",
217 "upload": "SRPM or .spec file upload",
218 "git_and_tito": "SCM-1 build from a Git repository",
219 "mock_scm": "SCM-2 build from a SCM repository",
220 "pypi": "Build from PyPI",
221 "rubygems": "Build from RubyGems",
222 }
223
224 return description_map.get(state, "")
225
230
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.group_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