move to use elementtree

This commit is contained in:
Louis Abel 2023-09-07 02:12:08 -07:00
parent 98a1737764
commit 21f8ced3dc
Signed by: label
GPG Key ID: B37E62D143879B36

View File

@ -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()