1#! /usr/bin/env python3
3"""Output html for packages in NEW"""
4# Copyright (C) 2007, 2009 Joerg Jaspert <joerg@debian.org>
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20################################################################################
22# <elmo> I'm James Troup, long term source of all evil in Debian. you may
23# know me from such debian-devel-announce gems as "Serious
24# Problems With ...."
26################################################################################
28import os
29import sys
30import time
31from multiprocessing import Manager
33import apt_pkg
35import dak.examine_package
36from daklib import policy
37from daklib.config import Config
38from daklib.dakmultiprocessing import (
39 PROC_STATUS_EXCEPTION,
40 PROC_STATUS_SUCCESS,
41 DakProcessPool,
42)
43from daklib.dbconn import DBChange, DBConn, PolicyQueue, PolicyQueueUpload
45# Globals
46Cnf = None
47Options = None
48manager = Manager()
49sources = manager.list()
50htmlfiles_to_process = manager.list()
51timeout_str = "Error or timeout while processing"
54################################################################################
55################################################################################
56################################################################################
59def html_header(name, missing):
60 if name.endswith(".changes"): 60 ↛ 61line 60 didn't jump to line 61, because the condition on line 60 was never true
61 name = " ".join(name.split("_")[:2])
62 result = """<!DOCTYPE html>
63<html lang="en">
64 <head>
65 <meta charset="utf-8">
66 <title>%(name)s - Debian NEW package overview</title>
67 <link rel="stylesheet" href="/style.css">
68 <link rel="shortcut icon" href="https://www.debian.org/favicon.ico">
69 <script>
70 function toggle(id, initial, display) {
71 var o = document.getElementById(id);
72 toggleObj(o, initial, display);
73 }
74 function show(id, display) {
75 var o = document.getElementById(id);
76 o.style.display = 'table-row-group';
77 }
78 function toggleObj(o, initial, display) {
79 if(! o.style.display)
80 o.style.display = initial;
81 if(o.style.display == display) {
82 o.style.display = "none";
83 } else {
84 o.style.display = display;
85 }
86 }
87 </script>
88 </head>
89 <body id="NEW-details-page">
90 <div id="logo">
91 <a href="https://www.debian.org/">
92 <img src="https://www.debian.org/logos/openlogo-nd-50.png"
93 alt=""></a>
94 <a href="https://www.debian.org/">
95 <img src="https://www.debian.org/Pics/debian.png"
96 alt="Debian Project"></a>
97 </div>
98 <div id="titleblock">
99 <img src="https://www.debian.org/Pics/red-upperleft.png"
100 id="red-upperleft" alt="">
101 <img src="https://www.debian.org/Pics/red-lowerleft.png"
102 id="red-lowerleft" alt="">
103 <img src="https://www.debian.org/Pics/red-upperright.png"
104 id="red-upperright" alt="">
105 <img src="https://www.debian.org/Pics/red-lowerright.png"
106 id="red-lowerright" alt="">
107 <span class="title">
108 Debian NEW package overview for %(name)s
109 </span>
110 </div>
112 """ % {
113 "name": name
114 }
116 # we assume only one source (.dsc) per changes here
117 result += """
118 <div id="menu">
119 <p class="title">Navigation</p>
120 <p><a href="#changes" onclick="show('changes-body')">.changes</a></p>
121 <p><a href="#dsc" onclick="show('dsc-body')">.dsc</a></p>
122 <p><a href="#source-lintian" onclick="show('source-lintian-body')">source lintian</a></p>
124"""
125 for binarytype, packagename in [m for m in missing if m[0] in ("deb", "udeb")]:
126 result += """
127 <p class="subtitle">%(pkg)s</p>
128 <p><a href="#binary-%(pkg)s-control" onclick="show('binary-%(pkg)s-control-body')">control file</a></p>
129 <p><a href="#binary-%(pkg)s-lintian" onclick="show('binary-%(pkg)s-lintian-body')">binary lintian</a></p>
130 <p><a href="#binary-%(pkg)s-contents" onclick="show('binary-%(pkg)s-contents-body')">.deb contents</a></p>
131 <p><a href="#binary-%(pkg)s-copyright" onclick="show('binary-%(pkg)s-copyright-body')">copyright</a></p>
132 <p><a href="#binary-%(pkg)s-file-listing" onclick="show('binary-%(pkg)s-file-listing-body')">file listing</a></p>
134""" % {
135 "pkg": packagename
136 }
137 result += " </div>"
138 return result
141def html_footer():
142 result = """ <p class="validate">Timestamp: %s (UTC)</p>
143""" % (
144 time.strftime("%d.%m.%Y / %H:%M:%S", time.gmtime())
145 )
146 result += "</body></html>"
147 return result
150################################################################################
153def do_pkg(upload_id):
154 cnf = Config()
156 session = DBConn().session()
157 upload = session.query(PolicyQueueUpload).filter_by(id=upload_id).one()
159 queue = upload.policy_queue
160 changes = upload.changes
162 origchanges = os.path.join(queue.path, changes.changesname)
163 print(origchanges)
165 htmlname = "{0}_{1}.html".format(changes.source, changes.version)
166 htmlfile = os.path.join(cnf["Show-New::HTMLPath"], htmlname)
168 # Have we already processed this?
169 if os.path.exists(htmlfile) and os.stat(htmlfile).st_mtime > time.mktime( 169 ↛ 172line 169 didn't jump to line 172, because the condition on line 169 was never true
170 changes.created.timetuple()
171 ):
172 with open(htmlfile, "r") as fd:
173 if fd.read() != timeout_str:
174 sources.append(htmlname)
175 return (PROC_STATUS_SUCCESS, "%s already up-to-date" % htmlfile)
177 # Go, process it... Now!
178 htmlfiles_to_process.append(htmlfile)
179 sources.append(htmlname)
181 group = cnf.get("Dinstall::UnprivGroup") or None
183 with open(htmlfile, "w") as outfile, policy.UploadCopy(
184 upload, group=group
185 ) as upload_copy:
186 handler = policy.PolicyQueueUploadHandler(upload, session)
187 missing = [(o["type"], o["package"]) for o in handler.missing_overrides()]
188 distribution = changes.distribution
190 outfile.write(html_header(changes.source, missing))
191 outfile.write(dak.examine_package.display_changes(distribution, origchanges))
193 if upload.source is not None and ("dsc", upload.source.source) in missing: 193 ↛ 196line 193 didn't jump to line 196, because the condition on line 193 was never false
194 fn = os.path.join(upload_copy.directory, upload.source.poolfile.basename)
195 outfile.write(dak.examine_package.check_dsc(distribution, fn, session))
196 for binary in upload.binaries:
197 if (binary.binarytype, binary.package) not in missing: 197 ↛ 198line 197 didn't jump to line 198, because the condition on line 197 was never true
198 continue
199 fn = os.path.join(upload_copy.directory, binary.poolfile.basename)
200 outfile.write(dak.examine_package.check_deb(distribution, fn, session))
202 outfile.write(html_footer())
204 session.close()
205 htmlfiles_to_process.remove(htmlfile)
206 return (PROC_STATUS_SUCCESS, "{0} already updated".format(htmlfile))
209################################################################################
212def usage(exit_code=0):
213 print(
214 """Usage: dak show-new [OPTION]... [CHANGES]...
215 -h, --help show this help and exit.
216 -p, --html-path [path] override output directory.
217 """
218 )
219 sys.exit(exit_code)
222################################################################################
225def init(session):
226 global cnf, Options
228 cnf = Config()
230 Arguments = [
231 ("h", "help", "Show-New::Options::Help"),
232 ("p", "html-path", "Show-New::HTMLPath", "HasArg"),
233 ("q", "queue", "Show-New::Options::Queue", "HasArg"),
234 ]
236 for i in ["help"]:
237 key = "Show-New::Options::%s" % i
238 if key not in cnf: 238 ↛ 236line 238 didn't jump to line 236, because the condition on line 238 was never false
239 cnf[key] = ""
241 changesnames = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv)
242 Options = cnf.subtree("Show-New::Options")
244 if Options["help"]:
245 usage()
247 queue_names = Options.find("Queue", "new").split(",")
248 uploads = (
249 session.query(PolicyQueueUpload)
250 .join(PolicyQueueUpload.policy_queue)
251 .filter(PolicyQueue.queue_name.in_(queue_names))
252 .join(PolicyQueueUpload.changes)
253 .order_by(DBChange.source)
254 )
256 if len(changesnames) > 0: 256 ↛ 257line 256 didn't jump to line 257, because the condition on line 256 was never true
257 uploads = uploads.filter(DBChange.changesname.in_(changesnames))
259 return uploads
262def result_callback(r):
263 code, msg = r
264 if code == PROC_STATUS_EXCEPTION: 264 ↛ 265line 264 didn't jump to line 265, because the condition on line 264 was never true
265 print("Job raised exception: %s" % (msg))
266 elif code != PROC_STATUS_SUCCESS: 266 ↛ 267line 266 didn't jump to line 267, because the condition on line 266 was never true
267 print("Job failed: %s" % (msg))
270################################################################################
271################################################################################
274def main():
275 dak.examine_package.use_html = True
276 pool = DakProcessPool(processes=5)
278 session = DBConn().session()
279 upload_ids = [u.id for u in init(session)]
280 session.close()
282 for upload_id in upload_ids:
283 pool.apply_async(do_pkg, [upload_id], callback=result_callback)
284 pool.close()
286 pool.join()
288 for htmlfile in htmlfiles_to_process: 288 ↛ 289line 288 didn't jump to line 289, because the loop on line 288 never started
289 with open(htmlfile, "w") as fd:
290 fd.write(timeout_str)
292 if pool.overall_status() != PROC_STATUS_SUCCESS: 292 ↛ 293line 292 didn't jump to line 293, because the condition on line 292 was never true
293 raise Exception("Processing failed (code %s)" % (pool.overall_status()))
295 files = set(os.listdir(cnf["Show-New::HTMLPath"]))
296 to_delete = [x for x in files.difference(set(sources)) if x.endswith(".html")]
297 for f in to_delete:
298 os.remove(os.path.join(cnf["Show-New::HTMLPath"], f))
301################################################################################
304if __name__ == "__main__":
305 main()