2 # Generate two rss feeds for a directory with .changes file
4 # License: GPL v2 or later
5 # Author: Filippo Giunchedi <filippo@debian.org>
13 import encodings.ascii
14 from optparse import OptionParser
15 from datetime import datetime
19 from debian_bundle.deb822 import Changes
21 inrss_filename = "NEW_in.rss"
22 outrss_filename = "NEW_out.rss"
23 db_filename = "status.db"
25 parser = OptionParser()
26 parser.set_defaults(queuedir="queue", outdir="out", datadir="status", max_entries="30")
28 parser.add_option("-q", "--queuedir", dest="queuedir",
29 help="The queue dir (%default)")
30 parser.add_option("-o", "--outdir", dest="outdir",
31 help="The output directory (%default)")
32 parser.add_option("-d", "--datadir", dest="datadir",
33 help="The data dir (%default)")
34 parser.add_option("-m", "--max-entries", dest="max_entries", type="int",
35 help="Max number of entries to keep (%default)")
39 self.feed_in = PyRSS2Gen.RSS2(
40 title = "Packages entering NEW",
41 link = "http://ftp-master.debian.org/new.html",
42 description = "Debian packages entering the NEW queue" )
44 self.feed_out = PyRSS2Gen.RSS2(
45 title = "Packages leaving NEW",
46 link = "http://ftp-master.debian.org/new.html",
47 description = "Debian packages leaving the NEW queue" )
52 """ Return an ASCII encoded copy of the input UTF-8 string """
54 res = unicode(src, 'utf-8').encode('ascii', 'replace')
55 except UnicodeDecodeError:
59 def purge_old_items(feed, max):
60 """ Purge RSSItem from feed, no more than max. """
61 if feed.items is None or len(feed.items) == 0:
64 feed.items = feed.items[:max]
67 def parse_changes(fname):
68 """ Parse a .changes file named fname.
70 Return {fname: parsed} """
72 m = Changes(open(fname))
74 wanted_fields = set(['Source', 'Version', 'Architecture', 'Distribution',
75 'Date', 'Maintainer', 'Description', 'Changes'])
77 if not set(m.keys()).issuperset(wanted_fields):
80 return {os.path.basename(fname): m}
82 def parse_queuedir(dir):
83 """ Parse dir for .changes files.
85 Return a dictionary {filename: parsed_file}"""
87 if not os.path.exists(dir):
91 for fname in os.listdir(dir):
92 if not fname.endswith(".changes"):
95 parsed = parse_changes(os.path.join(dir, fname))
101 def add_rss_item(status, msg, direction):
102 if direction == "in":
103 feed = status.feed_in
104 title = "%s %s entered NEW" % (msg['Source'], msg['Version'])
105 pubdate = msg['Date']
106 elif direction == "out":
107 feed = status.feed_out
108 title = "%s %s left NEW" % (msg['Source'], msg['Version'])
109 pubdate = datetime.utcnow()
113 description = "<pre>Description: %s\nChanges: %s\n</pre>" % \
114 (utf2ascii(cgi.escape(msg['Description'])), utf2ascii(cgi.escape(msg['Changes'])))
116 link = "http://ftp-master.debian.org/new/%s_%s.html" % \
117 (msg['Source'], msg['Version'])
123 description = description,
124 author = utf2ascii(cgi.escape(msg['Maintainer'])),
130 def update_feeds(curqueue, status):
131 # inrss -> append all items in curqueue not in status.queue
132 # outrss -> append all items in status.queue not in curqueue
134 for (name, parsed) in curqueue.items():
135 if not status.queue.has_key(name):
137 add_rss_item(status, parsed, "in")
139 for (name, parsed) in status.queue.items():
140 if not curqueue.has_key(name):
142 add_rss_item(status, parsed, "out")
146 if __name__ == "__main__":
148 (settings, args) = parser.parse_args()
150 if not os.path.exists(settings.outdir):
151 sys.stderr.write("Outdir '%s' does not exists\n" % settings.outdir)
155 if not os.path.exists(settings.datadir):
156 sys.stderr.write("Datadir '%s' does not exists\n" % settings.datadir)
160 status_db = os.path.join(settings.datadir, db_filename)
163 status = cPickle.load(open(status_db))
167 current_queue = parse_queuedir(settings.queuedir)
168 if not current_queue:
169 sys.stderr.write("Unable to scan queuedir '%s'\n" % settings.queuedir)
173 update_feeds(current_queue, status)
175 purge_old_items(status.feed_in, settings.max_entries)
176 purge_old_items(status.feed_out, settings.max_entries)
178 feed_in_file = os.path.join(settings.outdir, inrss_filename)
179 feed_out_file = os.path.join(settings.outdir, outrss_filename)
182 status.feed_in.write_xml(file(feed_in_file, "w+"), "utf-8")
183 status.feed_out.write_xml(file(feed_out_file, "w+"), "utf-8")
185 sys.stderr.write("Unable to write feeds: %s\n", why)
188 status.queue = current_queue
191 cPickle.dump(status, open(status_db, "w+"))
193 sys.stderr.write("Unable to save status: %s\n", why)