forked from sig_core/toolkit
move to use elementtree
This commit is contained in:
parent
98a1737764
commit
21f8ced3dc
@ -8,10 +8,15 @@ import os
|
|||||||
import argparse
|
import argparse
|
||||||
import time
|
import time
|
||||||
import binascii
|
import binascii
|
||||||
|
# The old yum-utils repo-rss used string manipulation. We're instead going to
|
||||||
|
# use the XML python library to do the work for us. This is cleaner, imo.
|
||||||
|
from xml.sax.saxutils import escape as xmlescape
|
||||||
|
from xml.etree.ElementTree import ElementTree, TreeBuilder, tostring
|
||||||
|
from xml.dom import minidom
|
||||||
import dnf
|
import dnf
|
||||||
import dnf.exceptions
|
import dnf.exceptions
|
||||||
#from dnf.comps import Comps
|
#from dnf.comps import Comps
|
||||||
import libxml2
|
#import libxml2
|
||||||
|
|
||||||
def to_unicode(string: str) -> str:
|
def to_unicode(string: str) -> str:
|
||||||
"""
|
"""
|
||||||
@ -43,6 +48,8 @@ class DnfQuiet(dnf.Base):
|
|||||||
else:
|
else:
|
||||||
available = self.sack.query().available().filter(latest_per_arch=1)
|
available = self.sack.query().available().filter(latest_per_arch=1)
|
||||||
|
|
||||||
|
available.run()
|
||||||
|
|
||||||
for package in available:
|
for package in available:
|
||||||
ftime = int(package.buildtime)
|
ftime = int(package.buildtime)
|
||||||
if ftime > recentlimit:
|
if ftime > recentlimit:
|
||||||
@ -60,108 +67,126 @@ class DnfQuiet(dnf.Base):
|
|||||||
class RepoRSS:
|
class RepoRSS:
|
||||||
def __init__(self, filename='repo-rss.xml'):
|
def __init__(self, filename='repo-rss.xml'):
|
||||||
self.description = 'Repository RSS'
|
self.description = 'Repository RSS'
|
||||||
self.link = 'http://dnf.baseurl.org'
|
self.link = 'https://github.com/rpm-software-management/dnf'
|
||||||
self.title = 'Recent Packages'
|
self.title = 'Recent Packages'
|
||||||
self.do_file(filename)
|
|
||||||
self.do_doc()
|
|
||||||
|
|
||||||
def do_doc(self):
|
|
||||||
self.doc = libxml2.newDoc('1.0')
|
|
||||||
self.xmlescape = self.doc.encodeEntitiesReentrant
|
|
||||||
rss = self.doc.newChild(None, 'rss', None)
|
|
||||||
rss.setProp('version', '2.0')
|
|
||||||
self.rssnode = rss.newChild(None, 'channel', None)
|
|
||||||
|
|
||||||
def do_file(self, filename):
|
|
||||||
if filename[0] != '/':
|
if filename[0] != '/':
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
self.filename = os.path.join(cwd, filename)
|
self.filename = os.path.join(cwd, filename)
|
||||||
else:
|
else:
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
|
||||||
try:
|
def rsspackage(self, packages):
|
||||||
self.file_open = open(self.filename, 'w+')
|
file = self.filename
|
||||||
except IOError as exc:
|
|
||||||
print(f'Error opening file {self.filename}: {exc}', file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def rsspackage(self, package):
|
|
||||||
rfc822_format = "%a, %d %b %Y %X GMT"
|
|
||||||
changelog_format = "%a, %d %b %Y GMT"
|
|
||||||
package_hex = binascii.hexlify(package.chksum[1]).decode()
|
|
||||||
item = self.rssnode.newChild(None, 'item', None)
|
|
||||||
title = self.xmlescape(str(package))
|
|
||||||
description = package.description
|
|
||||||
item.newChild(None, 'title', title)
|
|
||||||
date = time.gmtime(float(package.buildtime))
|
|
||||||
item.newChild(None, 'pubDate', time.strftime(rfc822_format, date))
|
|
||||||
# pylint: disable=line-too-long
|
|
||||||
item.newChild(None, 'guid', package_hex).setProp("isPermaLink", "false")
|
|
||||||
link = package.remote_location()
|
|
||||||
item.newChild(None, 'link', self.xmlescape(link))
|
|
||||||
changelog = ''
|
|
||||||
count = 0
|
|
||||||
if package.changelogs is not None:
|
|
||||||
changelog_list = package.changelogs
|
|
||||||
else:
|
|
||||||
changelog_list = []
|
|
||||||
for meta in changelog_list:
|
|
||||||
count += 1
|
|
||||||
if count > 3:
|
|
||||||
changelog += '...'
|
|
||||||
break
|
|
||||||
date = meta['timestamp'].strftime(changelog_format)
|
|
||||||
author = meta['author']
|
|
||||||
desc = meta['text']
|
|
||||||
changelog += f'{date} - {author}\n{desc}\n\n'
|
|
||||||
# pylint: disable=line-too-long,consider-using-f-string
|
|
||||||
description = '<p><strong>{}</strong> - {}</p>\n\n'.format(self.xmlescape(package.name), self.xmlescape(package.summary))
|
|
||||||
description += '<p>%s</p>\n\n<p><strong>Change Log:</strong></p>\n\n' % self.xmlescape(description.replace("\n", "<br />\n"))
|
|
||||||
description += self.xmlescape('<pre>%s</pre>' % self.xmlescape(changelog))
|
|
||||||
item.newChild(None, 'description', description)
|
|
||||||
return item
|
|
||||||
|
|
||||||
def start_rss(self):
|
|
||||||
"""return string representation of rss preamble"""
|
|
||||||
rfc822_format = "%a, %d %b %Y %X GMT"
|
rfc822_format = "%a, %d %b %Y %X GMT"
|
||||||
now = time.strftime(rfc822_format, time.gmtime())
|
now = time.strftime(rfc822_format, time.gmtime())
|
||||||
rssheader = f"""<?xml version="1.0" encoding="utf-8"?>
|
etbobj = TreeBuilder()
|
||||||
<rss version="2.0">
|
# start rss
|
||||||
<channel>
|
etbobj.start('rss', {'version': '2.0'})
|
||||||
<title>{self.title}</title>
|
# start channel
|
||||||
<link>{self.link}</link>
|
etbobj.start('channel', {})
|
||||||
<description>{self.description}</description>
|
# start title
|
||||||
<pubDate>{now}</pubDate>
|
etbobj.start('title', {})
|
||||||
<generator>DNF</generator>
|
etbobj.data(self.title)
|
||||||
"""
|
etbobj.end('title')
|
||||||
|
# end title
|
||||||
|
# start link
|
||||||
|
etbobj.start('link', {})
|
||||||
|
etbobj.data(self.link)
|
||||||
|
etbobj.end('link')
|
||||||
|
# end link
|
||||||
|
# start description
|
||||||
|
etbobj.start('description', {})
|
||||||
|
etbobj.data(self.description)
|
||||||
|
etbobj.end('description')
|
||||||
|
# end description
|
||||||
|
# start pubDate
|
||||||
|
etbobj.start('pubDate', {})
|
||||||
|
etbobj.data(now)
|
||||||
|
etbobj.end('pubDate')
|
||||||
|
# end pubDate
|
||||||
|
# start generator
|
||||||
|
etbobj.start('generator', {})
|
||||||
|
etbobj.data('DNF')
|
||||||
|
etbobj.end('generator')
|
||||||
|
# end generator
|
||||||
|
|
||||||
self.file_open.write(rssheader)
|
rfc822_format = "%a, %d %b %Y %X GMT"
|
||||||
|
changelog_format = "%a, %d %b %Y GMT"
|
||||||
|
for package in packages:
|
||||||
|
package_hex = binascii.hexlify(package.chksum[1]).decode()
|
||||||
|
title = xmlescape(str(package))
|
||||||
|
date = time.gmtime(float(package.buildtime))
|
||||||
|
description = package.description
|
||||||
|
link = package.remote_location()
|
||||||
|
# form description
|
||||||
|
changelog = ''
|
||||||
|
count = 0
|
||||||
|
if package.changelogs is not None:
|
||||||
|
changelog_list = package.changelogs
|
||||||
|
else:
|
||||||
|
changelog_list = []
|
||||||
|
for meta in changelog_list:
|
||||||
|
count += 1
|
||||||
|
if count > 3:
|
||||||
|
changelog += '...'
|
||||||
|
break
|
||||||
|
date = meta['timestamp'].strftime(changelog_format)
|
||||||
|
author = meta['author']
|
||||||
|
desc = meta['text']
|
||||||
|
changelog += f'{date} - {author}\n{desc}\n\n'
|
||||||
|
description = f'<p><strong>{package.name}</strong> - {package.summary}</p>\n\n'
|
||||||
|
description += '<p>%s</p>\n\n<p><strong>Change Log:</strong></p>\n\n' % description.replace("\n", "<br />\n")
|
||||||
|
description += f'<pre>{changelog}</pre>'
|
||||||
|
|
||||||
def do_package(self, package):
|
# start item
|
||||||
item = self.rsspackage(package)
|
etbobj.start('item', {})
|
||||||
self.file_open.write(item.serialize("utf-8", 1))
|
# start title
|
||||||
item.unlinkNode()
|
etbobj.start('title', {})
|
||||||
item.freeNode()
|
etbobj.data(title)
|
||||||
del item
|
etbobj.end('title')
|
||||||
|
# end title
|
||||||
|
# start pubDate
|
||||||
|
etbobj.start('pubDate', {})
|
||||||
|
etbobj.data(date)
|
||||||
|
etbobj.end('pubDate')
|
||||||
|
# end pubDate
|
||||||
|
# start guid
|
||||||
|
etbobj.start('guid', {'isPermaLink': 'false'})
|
||||||
|
etbobj.data(package_hex)
|
||||||
|
etbobj.end('guid',)
|
||||||
|
# end guid
|
||||||
|
# start link
|
||||||
|
etbobj.start('link', {})
|
||||||
|
etbobj.data(link)
|
||||||
|
etbobj.end('link')
|
||||||
|
# end link
|
||||||
|
# start description
|
||||||
|
etbobj.start('description', {})
|
||||||
|
etbobj.data(xmlescape(description))
|
||||||
|
etbobj.end('description')
|
||||||
|
# end description
|
||||||
|
etbobj.end('item')
|
||||||
|
# end item
|
||||||
|
|
||||||
def close_rss(self):
|
etbobj.end('channel')
|
||||||
end="\n </channel>\n</rss>\n"
|
# end channel
|
||||||
self.file_open.write(end)
|
etbobj.end('rss')
|
||||||
self.file_open.close()
|
# end rss
|
||||||
del self.file_open
|
rss = etbobj.close()
|
||||||
self.doc.freeDoc()
|
etree = ElementTree(rss)
|
||||||
del self.doc
|
some_string = tostring(etree.getroot(), encoding='utf-8')
|
||||||
|
xmlstr = minidom.parseString(some_string).toprettyxml(indent=" ")
|
||||||
|
#etree.write(file, encoding='utf-8')
|
||||||
|
with open(file, 'w+', encoding='utf-8') as f:
|
||||||
|
f.write(xmlstr)
|
||||||
|
f.close()
|
||||||
|
|
||||||
def make_rss_feed(filename, title, link, description, recent, dnfobj):
|
def make_rss_feed(filename, title, link, description, recent):
|
||||||
rssobj = RepoRSS(filename)
|
rssobj = RepoRSS(filename)
|
||||||
rssobj.title = title
|
rssobj.title = title
|
||||||
rssobj.link = link
|
rssobj.link = link
|
||||||
rssobj.description = description
|
rssobj.description = description
|
||||||
rssobj.start_rss()
|
rssobj.rsspackage(recent)
|
||||||
if len(recent) > 0:
|
|
||||||
for package in recent:
|
|
||||||
rssobj.do_package(package)
|
|
||||||
rssobj.close_rss()
|
|
||||||
|
|
||||||
def main(options):
|
def main(options):
|
||||||
days = options.days
|
days = options.days
|
||||||
@ -198,7 +223,7 @@ def main(options):
|
|||||||
|
|
||||||
repoobj.load_metadata_other = True
|
repoobj.load_metadata_other = True
|
||||||
|
|
||||||
print('Getting repo data')
|
print('Getting repo data for requested repos')
|
||||||
try:
|
try:
|
||||||
dnfobj.fill_sack()
|
dnfobj.fill_sack()
|
||||||
except:
|
except:
|
||||||
@ -206,10 +231,13 @@ def main(options):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
sack_query = dnfobj.sack.query().available()
|
sack_query = dnfobj.sack.query().available()
|
||||||
recent = sack_query.filter(latest_per_arch=1)
|
#recent = sack_query.filter(latest_per_arch=1)
|
||||||
sorted_recents = sorted(set(recent.run()), key=lambda pkg: pkg.buildtime)
|
recent = dnfobj.get_recent(days=days)
|
||||||
|
#sorted_recents = sorted(set(recent.run()), key=lambda pkg: pkg.buildtime)
|
||||||
|
sorted_recents = sorted(set(recent), key=lambda pkg: pkg.buildtime)
|
||||||
sorted_recents.reverse()
|
sorted_recents.reverse()
|
||||||
make_rss_feed(options.filename, options.title, options.link, options.description, sorted_recents, dnfobj)
|
make_rss_feed(options.filename, options.title, options.link,
|
||||||
|
options.description, sorted_recents)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
Loading…
Reference in New Issue
Block a user