|
Ralph Bean |
ad48e3 |
# This program is free software; you can redistribute it and/or
|
|
Ralph Bean |
ad48e3 |
# modify it under the terms of the GNU General Public License
|
|
Ralph Bean |
ad48e3 |
# as published by the Free Software Foundation; either version 2
|
|
Ralph Bean |
ad48e3 |
# of the License, or (at your option) any later version.
|
|
Ralph Bean |
ad48e3 |
#
|
|
Ralph Bean |
ad48e3 |
# This program is distributed in the hope that it will be useful,
|
|
Ralph Bean |
ad48e3 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Ralph Bean |
ad48e3 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Ralph Bean |
ad48e3 |
# GNU General Public License for more details.
|
|
Ralph Bean |
ad48e3 |
#
|
|
Ralph Bean |
ad48e3 |
# You should have received a copy of the GNU General Public License
|
|
Ralph Bean |
ad48e3 |
# along with this program; if not, write to the Free Software
|
|
Ralph Bean |
ad48e3 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
Ralph Bean |
ad48e3 |
# USA.
|
|
Ralph Bean |
ad48e3 |
|
|
Ralph Bean |
ad48e3 |
""" Pagure-flavored Markdown
|
|
Ralph Bean |
ad48e3 |
|
|
Ralph Bean |
ad48e3 |
Author: Ralph Bean <rbean@redhat.com></rbean@redhat.com>
|
|
Pierre-Yves Chibon |
721198 |
Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
|
|
Ralph Bean |
ad48e3 |
"""
|
|
Ralph Bean |
ad48e3 |
|
|
Pierre-Yves Chibon |
67d1cc |
from __future__ import unicode_literals, absolute_import
|
|
Aurélien Bompard |
dcf6f6 |
|
|
Ralph Bean |
ad48e3 |
import flask
|
|
Ralph Bean |
ad48e3 |
|
|
Ralph Bean |
ad48e3 |
import markdown.inlinepatterns
|
|
Adam Williamson |
c9fff8 |
import markdown.preprocessors
|
|
Julen Landa Alustiza |
890236 |
import markdown.postprocessors
|
|
Ralph Bean |
ad48e3 |
import markdown.util
|
|
Pierre-Yves Chibon |
be0baf |
import pygit2
|
|
Adam Williamson |
c9fff8 |
import re
|
|
Aurélien Bompard |
831553 |
import six
|
|
Ralph Bean |
ad48e3 |
|
|
Pierre-Yves Chibon |
930073 |
import pagure.lib.query
|
|
Pierre-Yves Chibon |
b130e5 |
from pagure.config import config as pagure_config
|
|
Ralph Bean |
6ac06e |
|
|
Ralph Bean |
ad48e3 |
|
|
Pierre-Yves Chibon |
8ed43b |
try:
|
|
Pierre-Yves Chibon |
8ed43b |
from markdown.inlinepatterns import ImagePattern as ImagePattern
|
|
Pierre-Yves Chibon |
8ed43b |
|
|
Pierre-Yves Chibon |
8ed43b |
MK_VERSION = 2
|
|
Pierre-Yves Chibon |
8ed43b |
except ImportError:
|
|
Pierre-Yves Chibon |
8ed43b |
from markdown.inlinepatterns import ImageInlineProcessor as ImagePattern
|
|
Pierre-Yves Chibon |
8ed43b |
|
|
Pierre-Yves Chibon |
8ed43b |
MK_VERSION = 3
|
|
Pierre-Yves Chibon |
8ed43b |
|
|
Pierre-Yves Chibon |
8ed43b |
|
|
Adam Williamson |
53d919 |
# the (?
|
|
Adam Williamson |
53d919 |
# negative lookbehind assertion. It means 'match when the preceding
|
|
Adam Williamson |
53d919 |
# character is not in the \w class'. This stops us from starting a
|
|
Adam Williamson |
53d919 |
# match in the middle of a word (e.g. someone@something in the
|
|
Adam Williamson |
53d919 |
# MENTION_RE regex). Note that it is a zero-length match - it does
|
|
Adam Williamson |
53d919 |
# not capture or consume any of the string - and it does not appear
|
|
Adam Williamson |
53d919 |
# as a group for the match object.
|
|
Pierre-Yves Chibon |
3ff584 |
MENTION_RE = r"(?
|
|
Pierre-Yves Chibon |
e11381 |
# Each line below correspond to a line of the regex:
|
|
Adam Williamson |
53d919 |
# 1) Don't start matching in the middle of a word
|
|
Pierre-Yves Chibon |
e11381 |
# 2) See if there is a `forks/` at the start
|
|
Pierre-Yves Chibon |
e11381 |
# 3) See if we have a `user/`
|
|
Pierre-Yves Chibon |
e11381 |
# 4) See if we have a `namespace/`
|
|
Pierre-Yves Chibon |
e11381 |
# 5) Get the last part `project`
|
|
Pierre-Yves Chibon |
e11381 |
# 6) Get the identifier `#<id>`</id>
|
|
Pierre-Yves Chibon |
9c2953 |
EXPLICIT_LINK_RE = (
|
|
Pierre-Yves Chibon |
9c2953 |
r"(?
|
|
Pierre-Yves Chibon |
9c2953 |
r"(fork[s]?/)?"
|
|
Pierre-Yves Chibon |
9c2953 |
r"([a-zA-Z0-9_-]*?/)?"
|
|
Pierre-Yves Chibon |
9c2953 |
r"([a-zA-Z0-9_-]*?/)?"
|
|
Pierre-Yves Chibon |
9c2953 |
r"([a-zA-Z0-9_-]+)"
|
|
Pierre-Yves Chibon |
9c2953 |
r"#(?P<id>[0-9]+)"</id>
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
9c2953 |
COMMIT_LINK_RE = (
|
|
Pierre-Yves Chibon |
9c2953 |
r"(?
|
|
Pierre-Yves Chibon |
9c2953 |
r"(fork[s]?/)?"
|
|
Pierre-Yves Chibon |
9c2953 |
r"([a-zA-Z0-9_-]*?/)?"
|
|
Pierre-Yves Chibon |
9c2953 |
r"([a-zA-Z0-9_-]*?/)?"
|
|
Pierre-Yves Chibon |
9c2953 |
r"([a-zA-Z0-9_-]+)"
|
|
Pierre-Yves Chibon |
9c2953 |
r"#(?P<id>[\w]{40})"</id>
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Adam Williamson |
c9fff8 |
# PREPROCIMPLLINK is used by ImplicitIssuePreprocessor to replace the
|
|
Adam Williamson |
c9fff8 |
# '#' when a line starts with an implicit issue link, to prevent
|
|
Adam Williamson |
c9fff8 |
# markdown parsing it as a header; we have to handle it here
|
|
Pierre-Yves Chibon |
9c2953 |
IMPLICIT_ISSUE_RE = r"(?
|
|
Pierre-Yves Chibon |
9c2953 |
IMPLICIT_PR_RE = r"(?
|
|
Pierre-Yves Chibon |
9c2953 |
IMPLICIT_COMMIT_RE = r"(?
|
|
Pierre-Yves Chibon |
9c2953 |
STRIKE_THROUGH_RE = r"~~(.*?)~~"
|
|
Pierre-Yves Chibon |
b8c7ae |
|
|
Pierre-Yves Chibon |
b8c7ae |
|
|
Pierre-Yves Chibon |
721198 |
class MentionPattern(markdown.inlinepatterns.Pattern):
|
|
Pierre-Yves Chibon |
721198 |
""" @user pattern class. """
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
def handleMatch(self, m):
|
|
Pierre-Yves Chibon |
721198 |
""" When the pattern matches, update the text. """
|
|
Pierre-Yves Chibon |
98e061 |
name = markdown.util.AtomicString(m.group(2))
|
|
Pierre-Yves Chibon |
9c2953 |
text = "@%s" % name
|
|
Pierre-Yves Chibon |
930073 |
user = pagure.lib.query.search_user(flask.g.session, username=name)
|
|
Pierre-Yves Chibon |
721198 |
if not user:
|
|
Pierre-Yves Chibon |
721198 |
return text
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
element = markdown.util.etree.Element("a")
|
|
Pierre-Yves Chibon |
9c2953 |
base_url = pagure_config["APP_URL"]
|
|
Pierre-Yves Chibon |
9c2953 |
if base_url.endswith("/"):
|
|
Pierre-Yves Chibon |
477d8f |
base_url = base_url[:-1]
|
|
Pierre-Yves Chibon |
9c2953 |
url = "%s/user/%s" % (base_url, user.username)
|
|
Pierre-Yves Chibon |
9c2953 |
element.set("href", url)
|
|
Pierre-Yves Chibon |
721198 |
element.text = text
|
|
Pierre-Yves Chibon |
721198 |
return element
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
10eda2 |
class ExplicitLinkPattern(markdown.inlinepatterns.Pattern):
|
|
Pierre-Yves Chibon |
10eda2 |
""" Explicit link pattern. """
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
def handleMatch(self, m):
|
|
Pierre-Yves Chibon |
721198 |
""" When the pattern matches, update the text. """
|
|
Pierre-Yves Chibon |
10eda2 |
is_fork = m.group(2)
|
|
Pierre-Yves Chibon |
10eda2 |
user = m.group(3)
|
|
Pierre-Yves Chibon |
10eda2 |
namespace = m.group(4)
|
|
Pierre-Yves Chibon |
10eda2 |
repo = m.group(5)
|
|
Pierre-Yves Chibon |
10eda2 |
idx = m.group(6)
|
|
Pierre-Yves Chibon |
9c2953 |
text = "%s#%s" % (repo, idx)
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
10eda2 |
if not is_fork and user:
|
|
Pierre-Yves Chibon |
10eda2 |
namespace = user
|
|
Pierre-Yves Chibon |
10eda2 |
user = None
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
10eda2 |
if namespace:
|
|
Pierre-Yves Chibon |
9c2953 |
namespace = namespace.rstrip("/")
|
|
Pierre-Yves Chibon |
9c2953 |
text = "%s/%s" % (namespace, text)
|
|
Pierre-Yves Chibon |
10eda2 |
if user:
|
|
Pierre-Yves Chibon |
9c2953 |
user = user.rstrip("/")
|
|
Pierre-Yves Chibon |
9c2953 |
text = "%s/%s" % (user.rstrip("/"), text)
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
ac8d80 |
try:
|
|
Pierre-Yves Chibon |
ac8d80 |
idx = int(idx)
|
|
Abhijeet Kasurde |
f4bf50 |
except (ValueError, TypeError):
|
|
Pierre-Yves Chibon |
ac8d80 |
return text
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
10eda2 |
issue = _issue_exists(user, namespace, repo, idx)
|
|
Pierre-Yves Chibon |
6c7986 |
if issue:
|
|
Pierre-Yves Chibon |
10eda2 |
return _obj_anchor_tag(user, namespace, repo, issue, text)
|
|
Pierre-Yves Chibon |
6c7986 |
|
|
Pierre-Yves Chibon |
10eda2 |
request = _pr_exists(user, namespace, repo, idx)
|
|
Pierre-Yves Chibon |
6c7986 |
if request:
|
|
Pierre-Yves Chibon |
10eda2 |
return _obj_anchor_tag(user, namespace, repo, request, text)
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
6c7986 |
return text
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
dfd818 |
class CommitLinkPattern(markdown.inlinepatterns.Pattern):
|
|
Pierre-Yves Chibon |
dfd818 |
""" Commit link pattern. """
|
|
Pierre-Yves Chibon |
dfd818 |
|
|
Pierre-Yves Chibon |
dfd818 |
def handleMatch(self, m):
|
|
Pierre-Yves Chibon |
dfd818 |
""" When the pattern matches, update the text. """
|
|
Pierre-Yves Chibon |
dfd818 |
is_fork = m.group(2)
|
|
Pierre-Yves Chibon |
dfd818 |
user = m.group(3)
|
|
Pierre-Yves Chibon |
dfd818 |
namespace = m.group(4)
|
|
Pierre-Yves Chibon |
dfd818 |
repo = m.group(5)
|
|
Pierre-Yves Chibon |
dfd818 |
commitid = m.group(6)
|
|
Pierre-Yves Chibon |
9c2953 |
text = "%s#%s" % (repo, commitid)
|
|
Pierre-Yves Chibon |
dfd818 |
|
|
Pierre-Yves Chibon |
dfd818 |
if not is_fork and user:
|
|
Pierre-Yves Chibon |
dfd818 |
namespace = user
|
|
Pierre-Yves Chibon |
dfd818 |
user = None
|
|
Pierre-Yves Chibon |
dfd818 |
|
|
Pierre-Yves Chibon |
dfd818 |
if namespace:
|
|
Pierre-Yves Chibon |
9c2953 |
namespace = namespace.rstrip("/")
|
|
Pierre-Yves Chibon |
9c2953 |
text = "%s/%s" % (namespace, text)
|
|
Pierre-Yves Chibon |
dfd818 |
if user:
|
|
Pierre-Yves Chibon |
9c2953 |
user = user.rstrip("/")
|
|
Pierre-Yves Chibon |
9c2953 |
text = "%s/%s" % (user.rstrip("/"), text)
|
|
Pierre-Yves Chibon |
dfd818 |
|
|
Pierre-Yves Chibon |
930073 |
if pagure.lib.query.search_projects(
|
|
Pierre-Yves Chibon |
9c2953 |
flask.g.session,
|
|
Pierre-Yves Chibon |
9c2953 |
username=user,
|
|
Pierre-Yves Chibon |
9c2953 |
fork=is_fork,
|
|
Pierre-Yves Chibon |
9c2953 |
namespace=namespace,
|
|
Pierre-Yves Chibon |
9c2953 |
pattern=repo,
|
|
Pierre-Yves Chibon |
9c2953 |
):
|
|
Pierre-Yves Chibon |
dfd818 |
return _obj_anchor_tag(user, namespace, repo, commitid, text)
|
|
Pierre-Yves Chibon |
dfd818 |
|
|
Pierre-Yves Chibon |
dfd818 |
return text
|
|
Pierre-Yves Chibon |
dfd818 |
|
|
Pierre-Yves Chibon |
dfd818 |
|
|
Adam Williamson |
c9fff8 |
class ImplicitIssuePreprocessor(markdown.preprocessors.Preprocessor):
|
|
Adam Williamson |
c9fff8 |
"""
|
|
Adam Williamson |
c9fff8 |
Preprocessor which handles lines starting with an implicit
|
|
Adam Williamson |
c9fff8 |
link. We have to modify these so that markdown doesn't interpret
|
|
Adam Williamson |
c9fff8 |
them as headers.
|
|
Adam Williamson |
c9fff8 |
"""
|
|
Pierre-Yves Chibon |
9c2953 |
|
|
Adam Williamson |
c9fff8 |
def run(self, lines):
|
|
Adam Williamson |
c9fff8 |
"""
|
|
Adam Williamson |
c9fff8 |
If a line starts with an implicit issue link like #152,
|
|
Adam Williamson |
c9fff8 |
we replace the # with PREPROCIMPLLINK. This prevents markdown
|
|
Adam Williamson |
c9fff8 |
parsing the line as a header. ImplicitIssuePattern will catch
|
|
Adam Williamson |
c9fff8 |
and parse the text later. Otherwise, we change nothing.
|
|
Adam Williamson |
c9fff8 |
"""
|
|
Adam Williamson |
c9fff8 |
# match a # character, then any number of digits
|
|
Pierre-Yves Chibon |
9c2953 |
regex = re.compile(r"#([0-9]+)")
|
|
Adam Williamson |
c9fff8 |
new_lines = []
|
|
Adam Williamson |
c9fff8 |
for line in lines:
|
|
Adam Williamson |
c9fff8 |
# avoid calling the regex if line doesn't start with #
|
|
Pierre-Yves Chibon |
9c2953 |
if line.startswith("#"):
|
|
Adam Williamson |
c9fff8 |
match = regex.match(line)
|
|
Adam Williamson |
c9fff8 |
if match:
|
|
Adam Williamson |
c9fff8 |
idx = int(match.group(1))
|
|
Adam Williamson |
c9fff8 |
# we have to check if this is a real issue or PR now.
|
|
Adam Williamson |
c9fff8 |
# we can't just 'tag' the text somehow and leave it to
|
|
Adam Williamson |
c9fff8 |
# the pattern to check, as if it's *not* one we want
|
|
Adam Williamson |
c9fff8 |
# the line treated as a header, so we need the block
|
|
Adam Williamson |
c9fff8 |
# processor to see it unmodified.
|
|
Adam Williamson |
c9fff8 |
try:
|
|
Adam Williamson |
c9fff8 |
namespace, repo, user = _get_ns_repo_user()
|
|
Adam Williamson |
c9fff8 |
except RuntimeError:
|
|
Adam Williamson |
c9fff8 |
# non-match path, keep original line
|
|
Adam Williamson |
c9fff8 |
new_lines.append(line)
|
|
Adam Williamson |
c9fff8 |
continue
|
|
Pierre-Yves Chibon |
9c2953 |
if _issue_exists(user, namespace, repo, idx) or _pr_exists(
|
|
Pierre-Yves Chibon |
9c2953 |
user, namespace, repo, idx
|
|
Adam Williamson |
c9fff8 |
):
|
|
Adam Williamson |
c9fff8 |
# tweak the text
|
|
Pierre-Yves Chibon |
9c2953 |
new_lines.append("PREPROCIMPLLINK" + line[1:])
|
|
Adam Williamson |
c9fff8 |
continue
|
|
Adam Williamson |
c9fff8 |
# this is a non-match path, keep original line
|
|
Adam Williamson |
c9fff8 |
new_lines.append(line)
|
|
Adam Williamson |
c9fff8 |
continue
|
|
Adam Williamson |
c9fff8 |
return new_lines
|
|
Adam Williamson |
c9fff8 |
|
|
Pierre-Yves Chibon |
1b30cb |
|
|
Pierre-Yves Chibon |
721198 |
class ImplicitIssuePattern(markdown.inlinepatterns.Pattern):
|
|
Pierre-Yves Chibon |
721198 |
""" Implicit issue pattern. """
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
def handleMatch(self, m):
|
|
Pierre-Yves Chibon |
721198 |
""" When the pattern matches, update the text. """
|
|
Pierre-Yves Chibon |
721198 |
idx = markdown.util.AtomicString(m.group(2))
|
|
Pierre-Yves Chibon |
9c2953 |
text = "#%s" % idx
|
|
Pierre-Yves Chibon |
ac8d80 |
try:
|
|
Pierre-Yves Chibon |
ac8d80 |
idx = int(idx)
|
|
Abhijeet Kasurde |
f4bf50 |
except (ValueError, TypeError):
|
|
Pierre-Yves Chibon |
ac8d80 |
return text
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
89dcc4 |
try:
|
|
Pierre-Yves Chibon |
17a1bf |
namespace, repo, user = _get_ns_repo_user()
|
|
Pierre-Yves Chibon |
89dcc4 |
except RuntimeError:
|
|
Pierre-Yves Chibon |
89dcc4 |
return text
|
|
Pierre-Yves Chibon |
aa74ce |
|
|
Pierre-Yves Chibon |
10eda2 |
issue = _issue_exists(user, namespace, repo, idx)
|
|
Pierre-Yves Chibon |
3549f5 |
if issue:
|
|
Pierre-Yves Chibon |
10eda2 |
return _obj_anchor_tag(user, namespace, repo, issue, text)
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
10eda2 |
request = _pr_exists(user, namespace, repo, idx)
|
|
Pierre-Yves Chibon |
3549f5 |
if request:
|
|
Pierre-Yves Chibon |
10eda2 |
return _obj_anchor_tag(user, namespace, repo, request, text)
|
|
Pierre-Yves Chibon |
3549f5 |
|
|
Pierre-Yves Chibon |
3549f5 |
return text
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
1a226f |
class ImplicitPRPattern(markdown.inlinepatterns.Pattern):
|
|
Pierre-Yves Chibon |
1a226f |
""" Implicit pull-request pattern. """
|
|
Pierre-Yves Chibon |
1a226f |
|
|
Pierre-Yves Chibon |
1a226f |
def handleMatch(self, m):
|
|
Pierre-Yves Chibon |
1a226f |
""" When the pattern matches, update the text. """
|
|
Pierre-Yves Chibon |
1a226f |
idx = markdown.util.AtomicString(m.group(2))
|
|
Pierre-Yves Chibon |
9c2953 |
text = "PR#%s" % idx
|
|
Pierre-Yves Chibon |
ac8d80 |
try:
|
|
Pierre-Yves Chibon |
ac8d80 |
idx = int(idx)
|
|
Abhijeet Kasurde |
f4bf50 |
except (ValueError, TypeError):
|
|
Pierre-Yves Chibon |
ac8d80 |
return text
|
|
Pierre-Yves Chibon |
1a226f |
|
|
Pierre-Yves Chibon |
89dcc4 |
try:
|
|
Pierre-Yves Chibon |
17a1bf |
namespace, repo, user = _get_ns_repo_user()
|
|
Pierre-Yves Chibon |
89dcc4 |
except RuntimeError:
|
|
Pierre-Yves Chibon |
89dcc4 |
return text
|
|
Pierre-Yves Chibon |
1a226f |
|
|
Pierre-Yves Chibon |
10eda2 |
issue = _issue_exists(user, namespace, repo, idx)
|
|
Pierre-Yves Chibon |
1a226f |
if issue:
|
|
Pierre-Yves Chibon |
10eda2 |
return _obj_anchor_tag(user, namespace, repo, issue, text)
|
|
Pierre-Yves Chibon |
1a226f |
|
|
Pierre-Yves Chibon |
10eda2 |
request = _pr_exists(user, namespace, repo, idx)
|
|
Pierre-Yves Chibon |
1a226f |
if request:
|
|
Pierre-Yves Chibon |
10eda2 |
return _obj_anchor_tag(user, namespace, repo, request, text)
|
|
Pierre-Yves Chibon |
1a226f |
|
|
Pierre-Yves Chibon |
1a226f |
return text
|
|
Pierre-Yves Chibon |
1a226f |
|
|
Pierre-Yves Chibon |
1a226f |
|
|
Pierre-Yves Chibon |
82e2f3 |
class ImplicitCommitPattern(markdown.inlinepatterns.Pattern):
|
|
Pierre-Yves Chibon |
82e2f3 |
""" Implicit commit pattern. """
|
|
Pierre-Yves Chibon |
82e2f3 |
|
|
Pierre-Yves Chibon |
82e2f3 |
def handleMatch(self, m):
|
|
Pierre-Yves Chibon |
82e2f3 |
""" When the pattern matches, update the text. """
|
|
Pierre-Yves Chibon |
82e2f3 |
|
|
Pierre-Yves Chibon |
82e2f3 |
githash = markdown.util.AtomicString(m.group(2))
|
|
Pierre-Yves Chibon |
9c2953 |
text = "%s" % githash
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
82e2f3 |
try:
|
|
Pierre-Yves Chibon |
17a1bf |
namespace, repo, user = _get_ns_repo_user()
|
|
Pierre-Yves Chibon |
82e2f3 |
except RuntimeError:
|
|
Pierre-Yves Chibon |
82e2f3 |
return text
|
|
Pierre-Yves Chibon |
30383f |
|
|
Pierre-Yves Chibon |
930073 |
if pagure.lib.query.search_projects(
|
|
Pierre-Yves Chibon |
9c2953 |
flask.g.session, username=user, namespace=namespace, pattern=repo
|
|
Pierre-Yves Chibon |
9c2953 |
) and _commit_exists(user, namespace, repo, githash):
|
|
Clement Verna |
90bb3b |
return _obj_anchor_tag(user, namespace, repo, githash, text[:7])
|
|
Pierre-Yves Chibon |
82e2f3 |
|
|
Pierre-Yves Chibon |
82e2f3 |
return text
|
|
Pierre-Yves Chibon |
82e2f3 |
|
|
Pierre-Yves Chibon |
82e2f3 |
|
|
Pierre-Yves Chibon |
e7a276 |
class StrikeThroughPattern(markdown.inlinepatterns.Pattern):
|
|
Pierre-Yves Chibon |
e7a276 |
""" ~~striked~~ pattern class. """
|
|
Pierre-Yves Chibon |
e7a276 |
|
|
Pierre-Yves Chibon |
e7a276 |
def handleMatch(self, m):
|
|
Pierre-Yves Chibon |
e7a276 |
""" When the pattern matches, update the text. """
|
|
Pierre-Yves Chibon |
e7a276 |
text = markdown.util.AtomicString(m.group(2))
|
|
Pierre-Yves Chibon |
e7a276 |
|
|
Pierre-Yves Chibon |
e7a276 |
element = markdown.util.etree.Element("del")
|
|
Pierre-Yves Chibon |
e7a276 |
element.text = text
|
|
Pierre-Yves Chibon |
e7a276 |
return element
|
|
Pierre-Yves Chibon |
e7a276 |
|
|
Pierre-Yves Chibon |
e7a276 |
|
|
Pierre-Yves Chibon |
ded859 |
class AutolinkPattern2(markdown.inlinepatterns.Pattern):
|
|
Pierre-Yves Chibon |
ded859 |
""" Return a link Element given an autolink (`<http: com="" example="">`). """</http:>
|
|
Pierre-Yves Chibon |
9c2953 |
|
|
Pierre-Yves Chibon |
ded859 |
def handleMatch(self, m):
|
|
Pierre-Yves Chibon |
ded859 |
""" When the pattern matches, update the text.
|
|
Pierre-Yves Chibon |
ded859 |
|
|
Pierre-Yves Chibon |
ded859 |
:arg m: the matched object
|
|
Pierre-Yves Chibon |
ded859 |
|
|
Pierre-Yves Chibon |
ded859 |
"""
|
|
Pierre-Yves Chibon |
ded859 |
url = m.group(2)
|
|
Pierre-Yves Chibon |
9c2953 |
if url.startswith("<"):
|
|
Pierre-Yves Chibon |
ded859 |
url = url[1:]
|
|
Pierre-Yves Chibon |
9c2953 |
if url.endswith(">"):
|
|
Pierre-Yves Chibon |
ded859 |
url = url[:-1]
|
|
Pierre-Yves Chibon |
ded859 |
el = markdown.util.etree.Element("a")
|
|
Pierre-Yves Chibon |
9c2953 |
el.set("href", self.unescape(url))
|
|
Pierre-Yves Chibon |
ded859 |
el.text = markdown.util.AtomicString(url)
|
|
Pierre-Yves Chibon |
ded859 |
return el
|
|
Pierre-Yves Chibon |
ded859 |
|
|
Pierre-Yves Chibon |
ded859 |
|
|
Pierre-Yves Chibon |
8ed43b |
class ImagePatternLazyLoad(ImagePattern):
|
|
Pierre-Yves Chibon |
9f532e |
""" Customize the image element matched for lazyloading. """
|
|
Pierre-Yves Chibon |
9f532e |
|
|
Pierre-Yves Chibon |
8ed43b |
def handleMatch(self, m, *args):
|
|
Pierre-Yves Chibon |
8ed43b |
out = super(ImagePatternLazyLoad, self).handleMatch(m, *args)
|
|
Pierre-Yves Chibon |
8ed43b |
if MK_VERSION == 3:
|
|
Pierre-Yves Chibon |
8ed43b |
el = out[0]
|
|
Pierre-Yves Chibon |
8ed43b |
else:
|
|
Pierre-Yves Chibon |
8ed43b |
el = out
|
|
Pierre-Yves Chibon |
f5dd6e |
|
|
Pierre-Yves Chibon |
f5dd6e |
# Add a noscript tag with the untouched img tag
|
|
Pierre-Yves Chibon |
f5dd6e |
noscript = markdown.util.etree.Element("noscript")
|
|
Pierre-Yves Chibon |
f5dd6e |
noscript.append(el)
|
|
Pierre-Yves Chibon |
f5dd6e |
|
|
Pierre-Yves Chibon |
f5dd6e |
# Modify the origina img tag
|
|
Pierre-Yves Chibon |
f5dd6e |
img = markdown.util.etree.Element("img")
|
|
Pierre-Yves Chibon |
9c2953 |
img.set("data-src", el.get("src"))
|
|
Pierre-Yves Chibon |
9c2953 |
img.set("src", "")
|
|
Pierre-Yves Chibon |
9c2953 |
img.set("alt", el.get("alt"))
|
|
Pierre-Yves Chibon |
9c2953 |
img.set("class", "lazyload")
|
|
Pierre-Yves Chibon |
f5dd6e |
|
|
Pierre-Yves Chibon |
f5dd6e |
# Create a global span in which we add both the new img tag and the
|
|
Pierre-Yves Chibon |
f5dd6e |
# noscript one
|
|
Pierre-Yves Chibon |
f5dd6e |
outel = markdown.util.etree.Element("span")
|
|
Pierre-Yves Chibon |
f5dd6e |
outel.append(img)
|
|
Pierre-Yves Chibon |
f5dd6e |
outel.append(noscript)
|
|
Pierre-Yves Chibon |
f5dd6e |
|
|
Pierre-Yves Chibon |
8ed43b |
output = outel
|
|
Pierre-Yves Chibon |
8ed43b |
if MK_VERSION == 3:
|
|
Pierre-Yves Chibon |
8ed43b |
output = (outel, out[1], out[2])
|
|
Pierre-Yves Chibon |
8ed43b |
|
|
Pierre-Yves Chibon |
8ed43b |
return output
|
|
Pierre-Yves Chibon |
9f532e |
|
|
Pierre-Yves Chibon |
9f532e |
|
|
Julen Landa Alustiza |
890236 |
class EncapsulateMarkdownPostprocessor(markdown.postprocessors.Postprocessor):
|
|
Julen Landa Alustiza |
890236 |
def run(self, text):
|
|
Julen Landa Alustiza |
890236 |
return '' + text + " "
|
|
Julen Landa Alustiza |
890236 |
|
|
Julen Landa Alustiza |
890236 |
|
|
Pierre-Yves Chibon |
721198 |
class PagureExtension(markdown.extensions.Extension):
|
|
Pierre-Yves Chibon |
721198 |
def extendMarkdown(self, md, md_globals):
|
|
Pierre-Yves Chibon |
721198 |
# First, make it so that bare links get automatically linkified.
|
|
Pierre-Yves Chibon |
9c2953 |
AUTOLINK_RE = "(%s)" % "|".join(
|
|
Pierre-Yves Chibon |
9c2953 |
[
|
|
Pierre-Yves Chibon |
9c2953 |
r"<((?:[Ff]|[Hh][Tt])[Tt][Pp][Ss]?://[^>]*)>",
|
|
Pierre-Yves Chibon |
9c2953 |
r"\b(?:[Ff]|[Hh][Tt])[Tt][Pp][Ss]?://[^)<>\s]+[^.,)<>\s]",
|
|
Pierre-Yves Chibon |
9c2953 |
r"<(Ii][Rr][Cc][Ss]?://[^>]*)>",
|
|
Pierre-Yves Chibon |
9c2953 |
r"\b[Ii][Rr][Cc][Ss]?://[^)<>\s]+[^.,)<>\s]",
|
|
Pierre-Yves Chibon |
9c2953 |
]
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
ded859 |
markdown.inlinepatterns.AUTOLINK_RE = AUTOLINK_RE
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
9c2953 |
md.preprocessors["implicit_issue"] = ImplicitIssuePreprocessor()
|
|
Adam Williamson |
c9fff8 |
|
|
Pierre-Yves Chibon |
9c2953 |
md.inlinePatterns["mention"] = MentionPattern(MENTION_RE)
|
|
Pierre-Yves Chibon |
82e2f3 |
|
|
Pierre-Yves Chibon |
9f532e |
# Customize the image linking to support lazy loading
|
|
Pierre-Yves Chibon |
9f532e |
md.inlinePatterns["image_link"] = ImagePatternLazyLoad(
|
|
Pierre-Yves Chibon |
9c2953 |
markdown.inlinepatterns.IMAGE_LINK_RE, md
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
9c2953 |
|
|
Pierre-Yves Chibon |
9c2953 |
md.inlinePatterns["implicit_commit"] = ImplicitCommitPattern(
|
|
Pierre-Yves Chibon |
9c2953 |
IMPLICIT_COMMIT_RE
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
9c2953 |
md.inlinePatterns["commit_links"] = CommitLinkPattern(COMMIT_LINK_RE)
|
|
Pierre-Yves Chibon |
9c2953 |
md.inlinePatterns["autolink"] = AutolinkPattern2(AUTOLINK_RE, md)
|
|
Pierre-Yves Chibon |
9c2953 |
|
|
Pierre-Yves Chibon |
9c2953 |
if pagure_config.get("ENABLE_TICKETS", True):
|
|
Pierre-Yves Chibon |
9c2953 |
md.inlinePatterns["implicit_pr"] = ImplicitPRPattern(
|
|
Pierre-Yves Chibon |
9c2953 |
IMPLICIT_PR_RE
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
9c2953 |
md.inlinePatterns["explicit_fork_issue"] = ExplicitLinkPattern(
|
|
Pierre-Yves Chibon |
9c2953 |
EXPLICIT_LINK_RE
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
9c2953 |
md.inlinePatterns["implicit_issue"] = ImplicitIssuePattern(
|
|
Pierre-Yves Chibon |
9c2953 |
IMPLICIT_ISSUE_RE
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
9c2953 |
|
|
Pierre-Yves Chibon |
9c2953 |
md.inlinePatterns["striked"] = StrikeThroughPattern(STRIKE_THROUGH_RE)
|
|
Pierre-Yves Chibon |
e7a276 |
|
|
Julen Landa Alustiza |
890236 |
md.postprocessors["encapsulate"] = EncapsulateMarkdownPostprocessor()
|
|
Julen Landa Alustiza |
890236 |
|
|
Pierre-Yves Chibon |
721198 |
md.registerExtension(self)
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
|
|
Pierre-Yves Chibon |
721198 |
def makeExtension(*arg, **kwargs):
|
|
Pierre-Yves Chibon |
721198 |
return PagureExtension(**kwargs)
|
|
Ralph Bean |
ad48e3 |
|
|
Ralph Bean |
ad48e3 |
|
|
Pierre-Yves Chibon |
10eda2 |
def _issue_exists(user, namespace, repo, idx):
|
|
Pierre-Yves Chibon |
b8c7ae |
""" Utility method checking if a given issue exists. """
|
|
Farhaan Bukhsh |
72e9db |
|
|
Pierre-Yves Chibon |
930073 |
repo_obj = pagure.lib.query.get_authorized_project(
|
|
Pierre-Yves Chibon |
9c2953 |
flask.g.session, project_name=repo, user=user, namespace=namespace
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Farhaan Bukhsh |
72e9db |
|
|
Ralph Bean |
debf63 |
if not repo_obj:
|
|
Ralph Bean |
debf63 |
return False
|
|
Ralph Bean |
debf63 |
|
|
Pierre-Yves Chibon |
930073 |
issue_obj = pagure.lib.query.search_issues(
|
|
Pierre-Yves Chibon |
9c2953 |
flask.g.session, repo=repo_obj, issueid=idx
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Ralph Bean |
debf63 |
if not issue_obj:
|
|
Ralph Bean |
debf63 |
return False
|
|
Ralph Bean |
debf63 |
|
|
Pierre-Yves Chibon |
3549f5 |
return issue_obj
|
|
Ralph Bean |
debf63 |
|
|
Ralph Bean |
debf63 |
|
|
Pierre-Yves Chibon |
10eda2 |
def _pr_exists(user, namespace, repo, idx):
|
|
Pierre-Yves Chibon |
f4a3af |
""" Utility method checking if a given PR exists. """
|
|
Pierre-Yves Chibon |
930073 |
repo_obj = pagure.lib.query.get_authorized_project(
|
|
Pierre-Yves Chibon |
9c2953 |
flask.g.session, project_name=repo, user=user, namespace=namespace
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Farhaan Bukhsh |
72e9db |
|
|
Pierre-Yves Chibon |
3549f5 |
if not repo_obj:
|
|
Pierre-Yves Chibon |
3549f5 |
return False
|
|
Pierre-Yves Chibon |
3549f5 |
|
|
Pierre-Yves Chibon |
930073 |
pr_obj = pagure.lib.query.search_pull_requests(
|
|
Pierre-Yves Chibon |
9c2953 |
flask.g.session, project_id=repo_obj.id, requestid=idx
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
3549f5 |
if not pr_obj:
|
|
Pierre-Yves Chibon |
3549f5 |
return False
|
|
Pierre-Yves Chibon |
3549f5 |
|
|
Pierre-Yves Chibon |
3549f5 |
return pr_obj
|
|
Pierre-Yves Chibon |
3549f5 |
|
|
Pierre-Yves Chibon |
3549f5 |
|
|
Pierre-Yves Chibon |
be0baf |
def _commit_exists(user, namespace, repo, githash):
|
|
Pierre-Yves Chibon |
be0baf |
""" Utility method checking if a given commit exists. """
|
|
Pierre-Yves Chibon |
930073 |
repo_obj = pagure.lib.query.get_authorized_project(
|
|
Pierre-Yves Chibon |
9c2953 |
flask.g.session, project_name=repo, user=user, namespace=namespace
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
be0baf |
if not repo_obj:
|
|
Pierre-Yves Chibon |
be0baf |
return False
|
|
Pierre-Yves Chibon |
be0baf |
|
|
Pierre-Yves Chibon |
b130e5 |
reponame = pagure.utils.get_repo_path(repo_obj)
|
|
Pierre-Yves Chibon |
be0baf |
git_repo = pygit2.Repository(reponame)
|
|
Pierre-Yves Chibon |
be0baf |
return githash in git_repo
|
|
Pierre-Yves Chibon |
be0baf |
|
|
Pierre-Yves Chibon |
be0baf |
|
|
Pierre-Yves Chibon |
10eda2 |
def _obj_anchor_tag(user, namespace, repo, obj, text):
|
|
Jeremy Cline |
e1630c |
"""
|
|
Jeremy Cline |
e1630c |
Utility method generating the link to an issue or a PR.
|
|
Jeremy Cline |
e1630c |
|
|
Jeremy Cline |
e1630c |
:return: An element tree containing the href to the issue or PR
|
|
Jeremy Cline |
e1630c |
:rtype: xml.etree.ElementTree.Element
|
|
Jeremy Cline |
e1630c |
"""
|
|
Aurélien Bompard |
831553 |
if isinstance(obj, six.string_types):
|
|
Pierre-Yves Chibon |
dfd818 |
url = flask.url_for(
|
|
Pierre-Yves Chibon |
9c2953 |
"ui_ns.view_commit",
|
|
Pierre-Yves Chibon |
9c2953 |
username=user,
|
|
Pierre-Yves Chibon |
9c2953 |
namespace=namespace,
|
|
Pierre-Yves Chibon |
9c2953 |
repo=repo,
|
|
Pierre-Yves Chibon |
9c2953 |
commitid=obj,
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
9c2953 |
title = "Commit %s" % obj
|
|
Pierre-Yves Chibon |
9c2953 |
elif obj.isa == "issue":
|
|
Pierre-Yves Chibon |
3549f5 |
url = flask.url_for(
|
|
Pierre-Yves Chibon |
9c2953 |
"ui_ns.view_issue",
|
|
Pierre-Yves Chibon |
9c2953 |
username=user,
|
|
Pierre-Yves Chibon |
9c2953 |
namespace=namespace,
|
|
Pierre-Yves Chibon |
9c2953 |
repo=repo,
|
|
Pierre-Yves Chibon |
9c2953 |
issueid=obj.id,
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
859a72 |
if obj.private:
|
|
Pierre-Yves Chibon |
9c2953 |
title = "Private issue"
|
|
Pierre-Yves Chibon |
859a72 |
else:
|
|
Pierre-Yves Chibon |
f8a683 |
if obj.status:
|
|
Pierre-Yves Chibon |
9c2953 |
title = "[%s] %s" % (obj.status, obj.title)
|
|
Pierre-Yves Chibon |
f8a683 |
else:
|
|
Pierre-Yves Chibon |
f8a683 |
title = obj.title
|
|
Pierre-Yves Chibon |
3549f5 |
else:
|
|
Pierre-Yves Chibon |
3549f5 |
url = flask.url_for(
|
|
Pierre-Yves Chibon |
9c2953 |
"ui_ns.request_pull",
|
|
Pierre-Yves Chibon |
9c2953 |
username=user,
|
|
Pierre-Yves Chibon |
9c2953 |
namespace=namespace,
|
|
Pierre-Yves Chibon |
9c2953 |
repo=repo,
|
|
Pierre-Yves Chibon |
9c2953 |
requestid=obj.id,
|
|
Pierre-Yves Chibon |
9c2953 |
)
|
|
Pierre-Yves Chibon |
f8a683 |
if obj.status:
|
|
Pierre-Yves Chibon |
9c2953 |
title = "[%s] %s" % (obj.status, obj.title)
|
|
Pierre-Yves Chibon |
f8a683 |
else:
|
|
Pierre-Yves Chibon |
f8a683 |
title = obj.title
|
|
Pierre-Yves Chibon |
3549f5 |
|
|
Pierre-Yves Chibon |
b8c7ae |
element = markdown.util.etree.Element("a")
|
|
Pierre-Yves Chibon |
9c2953 |
element.set("href", url)
|
|
Pierre-Yves Chibon |
9c2953 |
element.set("title", title)
|
|
Pierre-Yves Chibon |
b8c7ae |
element.text = text
|
|
Pierre-Yves Chibon |
b8c7ae |
return element
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
17a1bf |
def _get_ns_repo_user():
|
|
Pierre-Yves Chibon |
17a1bf |
""" Return the namespace, repo, user corresponding to the given request
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
17a1bf |
:return: A tuple of three string corresponding to namespace, repo, user
|
|
Pierre-Yves Chibon |
17a1bf |
:rtype: tuple(str, str, str)
|
|
Pierre-Yves Chibon |
17a1bf |
"""
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
17a1bf |
root = flask.request.url_root
|
|
Pierre-Yves Chibon |
17a1bf |
url = flask.request.url
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
96be15 |
user = flask.request.args.get("user") or None
|
|
Pierre-Yves Chibon |
96be15 |
namespace = flask.request.args.get("namespace") or None
|
|
Pierre-Yves Chibon |
96be15 |
repo = flask.request.args.get("repo") or None
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
17a1bf |
if not user and not repo:
|
|
Pierre-Yves Chibon |
9c2953 |
if "fork/" in url:
|
|
Pierre-Yves Chibon |
9c2953 |
user, ext = url.split("fork/")[1].split("/", 1)
|
|
Pierre-Yves Chibon |
17a1bf |
else:
|
|
Pierre-Yves Chibon |
17a1bf |
ext = url.split(root)[1]
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
9c2953 |
if ext.count("/") >= 3:
|
|
Pierre-Yves Chibon |
9c2953 |
namespace, repo = ext.split("/", 2)[:2]
|
|
Pierre-Yves Chibon |
17a1bf |
else:
|
|
Pierre-Yves Chibon |
9c2953 |
repo = ext.split("/", 1)[0]
|
|
Pierre-Yves Chibon |
17a1bf |
|
|
Pierre-Yves Chibon |
17a1bf |
return (namespace, repo, user)
|