Package coprs :: Module filters
[hide private]
[frames] | no frames]

Source Code for Module coprs.filters

  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      # needed for Fedora <= 29 
 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 
27 28 -class CoprHtmlRenderer(commonmark.HtmlRenderer):
29 - def code_block(self, node, entering):
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 # fallback for Fedora <= 30 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):
67 if data: 68 data = re.sub("<.*?>", "", data) 69 data = re.sub("</a>", "", data) 70 return data 71 return None
72
73 @app.template_filter("date_from_secs") 74 -def date_from_secs(secs):
75 if secs: 76 return time.strftime("%Y-%m-%d %H:%M:%S %Z", time.gmtime(secs)) 77 78 return None
79
80 81 @app.template_filter("perm_type_from_num") 82 -def perm_type_from_num(num):
83 return helpers.PermissionEnum(num)
84
85 86 @app.template_filter("state_from_num") 87 -def state_from_num(num):
88 if num is None: 89 return "unknown" 90 return StatusEnum(num)
91
92 93 @app.template_filter("module_state_from_num") 94 -def module_state_from_num(num):
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):
102 # TODO: make it models.MockChroot method or not? 103 if os_version: 104 if os_version == "rawhide": 105 return os_version 106 if os_name == "fedora": 107 return "fc.{0}".format(os_version) 108 elif os_name == "epel": 109 return "el{0}".format(os_version) 110 return os_name
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
163 164 @app.template_filter("markdown") 165 -def markdown_filter(data):
166 if not data: 167 return '' 168 169 parser = commonmark.Parser() 170 renderer = CoprHtmlRenderer() 171 172 return Markup(renderer.render(parser.parse(data)))
173
174 175 @app.template_filter("pkg_name") 176 -def parse_package_name(pkg):
177 if pkg is not None: 178 return helpers.parse_package_name(os.path.basename(pkg)) 179 return pkg
180
181 182 @app.template_filter("basename") 183 -def parse_basename(pkg):
184 if pkg is not None: 185 return os.path.basename(pkg) 186 return pkg
187
188 189 @app.template_filter("build_state_description") 190 -def build_state_decoration(state):
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
208 209 @app.template_filter("build_source_description") 210 -def build_source_description(state):
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
224 225 @app.template_filter("fix_url_https_backend") 226 -def fix_url_https_backend(url):
227 if app.config.get('REPO_NO_SSL', False): 228 return url.replace('https://', 'http://') 229 return helpers.fix_protocol_for_backend(url)
230
231 232 @app.template_filter("fix_url_https_frontend") 233 -def fix_url_https_frontend(url):
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