diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README | 6 | ||||
-rw-r--r-- | cl2vcs.py | 153 | ||||
-rw-r--r-- | htmlchangelog.py | 9 | ||||
-rwxr-xr-x | index.cgi | 133 | ||||
-rw-r--r-- | templates/index.html | 2 | ||||
-rw-r--r-- | vcsbrowsers.py | 1 |
7 files changed, 171 insertions, 137 deletions
@@ -1,8 +1,8 @@ -VERSION=$(shell grep ^VERSION index.cgi | sed -e s'/.*\="\([0-9.]\+\)".*/\1/') +VERSION=$(shell grep ^VERSION cl2vcs.py | sed -e s'/.*\="\([0-9.]\+\)".*/\1/') PKG=cl2vcs all: - nosetests --with-doctest + nosetests3 --with-doctest clean: rm -f *.pyc @@ -2,4 +2,8 @@ For more information see: https://honk.sigxcpu.org/piki/projects/cl2vcs/ -Depends: python-lxml, python-urlgrabber, python-genshi, python-debian (>=0.1.11) +To test locally try + + python3 -c "import cl2vcs; cl2vcs.handle_pkg('multipath-tools', title='bla')" > out.html + +Depends: python3-lxml, python3-urlgrabber, python3-genshi, python3-debian diff --git a/cl2vcs.py b/cl2vcs.py new file mode 100644 index 0000000..be58145 --- /dev/null +++ b/cl2vcs.py @@ -0,0 +1,153 @@ +#!/usr/bin/python3 -u +# vim: set fileencoding=utf-8 : +# +# (C) 2008,2015,2022 Guido Guenther <agx@sigxcpu.org> +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +"""Link Debian changelog entries to the VCS""" + +from builtins import str +import cgi +import os +import re +import sys +import requests +from lxml import etree +from genshi.template import TemplateLoader +import vcsbrowsers +from htmlchangelog import HTMLChangelog +from io import BytesIO + +VERSION="0.0.5" +XMLNS='http://www.w3.org/1999/xhtml' +PTS='http://packages.qa.debian.org' +PKGNAMERE="[a-zA-Z0-9.+\-]+$" +TITLE = "cl2vcs %s" % VERSION + + +def fetch_changelog(cl_url): + resp = requests.get(cl_url, timeout=5.0) + resp.raise_for_status() + return resp.content + + +def fetch_pts_page(package): + pts = None + url = "%s/%s" % (PTS, package) + resp = requests.get(url, timeout=5.0) + if resp.status_code == 404: + raise Exception("Can't find package '%s' on '%s'" % (package, PTS)) + resp.raise_for_status() + return resp.content + + +def parse_pts_xhtml(pts): + cl_url = None + vcs_url = None + vcs = None + + tree = etree.parse(BytesIO(pts)) + searcher = etree.ETXPath('/{%s}html/{%s}body//{%s}a[@href]' % (XMLNS, XMLNS, XMLNS)) + result = searcher(tree) + + for r in result: + if not r.text: + continue + if r.text.lower() == "changelog": + cl_url = r.attrib['href'] + elif r.text.lower() == "browse": + vcs_url = r.attrib['href'] + parent = r.getparent() + vcs = parent.getchildren()[0].text.lower() + return cl_url, vcs_url, vcs + + +def get_vcsbrowser(vcs, vcs_url): + if vcs == "git": + return vcsbrowsers.guess_git_repo(vcs_url) + elif vcs == "Mercurial": + return vcsbrowsers.HgBrowser(vcs_url) + + +def render_search_page(title, pkg=None, err=None): + loader = TemplateLoader('templates') + tmpl = loader.load('index.html', encoding='utf-8') + t = tmpl.generate(title=title, pkg=pkg, err=err) + print(t.render('xhtml', doctype='xhtml-strict')) + + + +def render_changelog_page(cl): + print(cl) + + +def handle_pkg(pkg, title): + if pkg: + if not re.match(PKGNAMERE, pkg): + return render_search_page(title=title, err=u"Invalid package name: '%s'" % pkg) + else: + pkg = str(pkg) + else: + return render_search_page(title=title, err="") + + try: + pts = fetch_pts_page(pkg) + except Exception as exc_err: + err = exc_err + pts = None + + if not pts: + return render_search_page(title=title, pkg=pkg, err=err) + + cl_url, vcs_url, vcs = parse_pts_xhtml(pts) + if cl_url == None: + return render_search_page(title=title, pkg=pkg, + err="Cannot parse changelog from PTS page.") + try: + cl_text = fetch_changelog(cl_url) + except urlgrabber.grabber.URLGrabError as e: + (errcode, errmsg) = e.args + return render_search_page(title=title, + err="Cannot fetch '%s': %s" % (cl_url, errmsg)) + if vcs and vcs_url: + vcsbrowser = get_vcsbrowser(vcs, vcs_url) + else: + vcsbrowser = None + cl = HTMLChangelog(cl_text, vcsbrowser=vcsbrowser) + if cl: + render_changelog_page(cl) + + +def main(argv): + err = "" + + print("Content-Type: text/html; charset=utf-8") + print() + + try: + form = cgi.FieldStorage() + + if 'pkg' in form: + pkg = form.getfirst('pkg').strip() + else: + pkg = None + + handle_pkg(pkg, TITLE) + except Exception as err: + import traceback + traceback.print_exc(file=sys.stderr) + render_search_page(title=TITLE, err="Unknown error") + return 0 + diff --git a/htmlchangelog.py b/htmlchangelog.py index 9dddcff..bc667db 100644 --- a/htmlchangelog.py +++ b/htmlchangelog.py @@ -1,7 +1,8 @@ # vim: set fileencoding=utf-8 : +from builtins import object import re -import cgi +import html from genshi.template import TemplateLoader import debian.changelog @@ -22,7 +23,7 @@ class HTMLChangelogFilter(object): def vcs_commit_filter(self, changes): body = [] for line in changes: - line = cgi.escape(line) + line = html.escape(line) for regex in self.commit_id_res: m = regex.match(line) if m: @@ -38,7 +39,7 @@ class HTMLChangelogFilter(object): if self.vcsbrowser: block.body = self.vcs_commit_filter(block.changes()) else: - block.body = cgi.escape("\n".join(block.changes())) + block.body = html.escape("\n".join(block.changes())) return block @@ -61,5 +62,5 @@ class HTMLChangelog(debian.changelog.Changelog): return self.html_tmpl.generate(title=title, blocks=self._blocks, markup_block=self.markup_block) def __str__(self): - return self.stream().render('xhtml', doctype='xhtml-strict').encode('utf-8') + return self.stream().render('xhtml', doctype='xhtml-strict') @@ -1,7 +1,7 @@ -#!/usr/bin/python -u +#!/usr/bin/python3 -u # vim: set fileencoding=utf-8 : # -# (C) 2008,2015 Guido Guenther <agx@sigxcpu.org> +# (C) 2008,2015,2022 Guido Guenther <agx@sigxcpu.org> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or @@ -18,134 +18,9 @@ # """Link Debian changelog entries to the VCS""" -import cgi -import os -import re import sys -import urlgrabber -from lxml import etree -from genshi.template import TemplateLoader -import vcsbrowsers -from htmlchangelog import HTMLChangelog - -VERSION="0.0.4" -XMLNS='http://www.w3.org/1999/xhtml' -PTS='http://packages.qa.debian.org' -PKGNAMERE="[a-zA-Z0-9.+\-]+$" - - -def fetch_changelog(cl_url): - changelog = urlgrabber.urlread(cl_url, timeout=5.0).decode('utf-8') - return changelog - - -def fetch_pts_page(package): - pts = None - try: - url = "%s/%s" % (PTS, package) - pts = urlgrabber.urlopen(url, timeout=5.0) - except urlgrabber.grabber.URLGrabError as (code, msg): - if code == 14: - raise Exception, "Can't find package '%s' on '%s'" % (package, PTS) - else: - raise - return pts - - -def parse_pts_xhtml(pts): - cl_url = None - vcs_url = None - vcs = None - - tree = etree.parse(pts) - searcher = etree.ETXPath('/{%s}html/{%s}body//{%s}a[@href]' % (XMLNS, XMLNS, XMLNS)) - result = searcher(tree) - - for r in result: - if not r.text: - continue - if r.text.lower() == "changelog": - cl_url = r.attrib['href'] - elif r.text.lower() == "browse": - vcs_url = r.attrib['href'] - parent = r.getparent() - vcs = parent.getchildren()[0].text.lower() - return cl_url, vcs_url, vcs - - -def get_vcsbrowser(vcs, vcs_url): - if vcs == "git": - return vcsbrowsers.guess_git_repo(vcs_url) - elif vcs == "Mercurial": - return vcsbrowsers.HgBrowser(vcs_url) - - -def render_search_page(title, pkg=None, err=None): - loader = TemplateLoader('templates') - tmpl = loader.load('index.html', encoding='utf-8') - t = tmpl.generate(title=title, pkg=pkg, err=err) - print t.render('xhtml', doctype='xhtml-strict').encode('utf-8') - - - -def render_changelog_page(cl): - print cl - - -def main(argv): - title = "cl2vcs %s" % VERSION - err = "" - - print "Content-Type: text/html; charset=utf-8" - print - - try: - form = cgi.FieldStorage() - - if form.has_key('pkg'): - pkg = form.getfirst('pkg').decode('utf-8').strip() - else: - pkg = None - - if pkg: - if not re.match(PKGNAMERE, pkg): - return render_search_page(title=title, err=u"Invalid package name: '%s'" % pkg) - else: - pkg = str(pkg) - else: - return render_search_page(title=title, err=err) - - try: - pts = fetch_pts_page(pkg) - except Exception as exc_err: - err = exc_err - pts = None - - if not pts: - return render_search_page(title=title, pkg=pkg, err=err) - - cl_url, vcs_url, vcs = parse_pts_xhtml(pts) - if cl_url == None: - return render_search_page(title=title, pkg=pkg, - err="Cannot parse changelog from PTS page.") - try: - cl_text = fetch_changelog(cl_url) - except urlgrabber.grabber.URLGrabError, (errcode, errmsg): - return render_search_page(title=title, - err="Cannot fetch '%s': %s" % (cl_url, errmsg)) - if vcs and vcs_url: - vcsbrowser = get_vcsbrowser(vcs, vcs_url) - else: - vcsbrowser = None - cl = HTMLChangelog(cl_text, vcsbrowser=vcsbrowser) - if cl: - render_changelog_page(cl) - except Exception, err: - import traceback - traceback.print_exc(file=sys.stderr) - render_search_page(title=title, err="Unknown error") - return 0 +import cl2vcs if __name__ == "__main__": - sys.exit(main(sys.argv)) + sys.exit(cl2vcs.main(sys.argv)) diff --git a/templates/index.html b/templates/index.html index b8cd84c..b792778 100644 --- a/templates/index.html +++ b/templates/index.html @@ -27,7 +27,7 @@ <div id="footer"> <hr /> - <p>© 2008,2009,2015 Guido Günther <a href="mailto:agx@sigxcpu.org"><agx@sigxcpu.org></a></p> + <p>© 2008,2009,2015,2022 Guido Günther <a href="mailto:agx@sigxcpu.org"><agx@sigxcpu.org></a></p> </div> </body> </html> diff --git a/vcsbrowsers.py b/vcsbrowsers.py index 2e082a6..409c1dc 100644 --- a/vcsbrowsers.py +++ b/vcsbrowsers.py @@ -1,6 +1,7 @@ # convenience wrappers to construct links # into the webinterfaces of different VCSs +from builtins import object import re |