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
1 changed files with 118 additions and 90 deletions

View File

@ -8,10 +8,15 @@ import os
import argparse
import time
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.exceptions
#from dnf.comps import Comps
import libxml2
#import libxml2
def to_unicode(string: str) -> str:
"""
@ -43,6 +48,8 @@ class DnfQuiet(dnf.Base):
else:
available = self.sack.query().available().filter(latest_per_arch=1)
available.run()
for package in available:
ftime = int(package.buildtime)
if ftime > recentlimit:
@ -60,108 +67,126 @@ class DnfQuiet(dnf.Base):
class RepoRSS:
def __init__(self, filename='repo-rss.xml'):
self.description = 'Repository RSS'
self.link = 'http://dnf.baseurl.org'
self.link = 'https://github.com/rpm-software-management/dnf'
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] != '/':
cwd = os.getcwd()
self.filename = os.path.join(cwd, filename)
else:
self.filename = filename
try:
self.file_open = open(self.filename, 'w+')
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"""
def rsspackage(self, packages):
file = self.filename
rfc822_format = "%a, %d %b %Y %X GMT"
now = time.strftime(rfc822_format, time.gmtime())
rssheader = f"""<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>{self.title}</title>
<link>{self.link}</link>
<description>{self.description}</description>
<pubDate>{now}</pubDate>
<generator>DNF</generator>
"""
etbobj = TreeBuilder()
# start rss
etbobj.start('rss', {'version': '2.0'})
# start channel
etbobj.start('channel', {})
# start title
etbobj.start('title', {})
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):
item = self.rsspackage(package)
self.file_open.write(item.serialize("utf-8", 1))
item.unlinkNode()
item.freeNode()
del item
# start item
etbobj.start('item', {})
# start title
etbobj.start('title', {})
etbobj.data(title)
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):
end="\n </channel>\n</rss>\n"
self.file_open.write(end)
self.file_open.close()
del self.file_open
self.doc.freeDoc()
del self.doc
etbobj.end('channel')
# end channel
etbobj.end('rss')
# end rss
rss = etbobj.close()
etree = ElementTree(rss)
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.title = title
rssobj.link = link
rssobj.description = description
rssobj.start_rss()
if len(recent) > 0:
for package in recent:
rssobj.do_package(package)
rssobj.close_rss()
rssobj.rsspackage(recent)
def main(options):
days = options.days
@ -198,7 +223,7 @@ def main(options):
repoobj.load_metadata_other = True
print('Getting repo data')
print('Getting repo data for requested repos')
try:
dnfobj.fill_sack()
except:
@ -206,10 +231,13 @@ def main(options):
sys.exit(1)
sack_query = dnfobj.sack.query().available()
recent = sack_query.filter(latest_per_arch=1)
sorted_recents = sorted(set(recent.run()), key=lambda pkg: pkg.buildtime)
#recent = sack_query.filter(latest_per_arch=1)
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()
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__":
parser = argparse.ArgumentParser()