Coverage for dak/show_new.py: 77%
109 statements
« prev ^ index » next coverage.py v7.6.0, created at 2026-01-04 16:18 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2026-01-04 16:18 +0000
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: Config
47Options: apt_pkg.Configuration
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 (
184 open(htmlfile, "w") as outfile,
185 policy.UploadCopy(upload, group=group) as upload_copy,
186 ):
187 handler = policy.PolicyQueueUploadHandler(upload, session)
188 missing = [(o["type"], o["package"]) for o in handler.missing_overrides()]
189 distribution = changes.distribution
191 outfile.write(html_header(changes.source, missing))
192 outfile.write(dak.examine_package.display_changes(distribution, origchanges))
194 if upload.source is not None and ("dsc", upload.source.source) in missing: 194 ↛ 197line 194 didn't jump to line 197 because the condition on line 194 was always true
195 fn = os.path.join(upload_copy.directory, upload.source.poolfile.basename)
196 outfile.write(dak.examine_package.check_dsc(distribution, fn, session))
197 for binary in upload.binaries:
198 if (binary.binarytype, binary.package) not in missing: 198 ↛ 199line 198 didn't jump to line 199 because the condition on line 198 was never true
199 continue
200 fn = os.path.join(upload_copy.directory, binary.poolfile.basename)
201 outfile.write(dak.examine_package.check_deb(distribution, fn, session))
203 outfile.write(html_footer())
205 session.close()
206 htmlfiles_to_process.remove(htmlfile)
207 return (PROC_STATUS_SUCCESS, "{0} already updated".format(htmlfile))
210################################################################################
213def usage(exit_code=0):
214 print(
215 """Usage: dak show-new [OPTION]... [CHANGES]...
216 -h, --help show this help and exit.
217 -p, --html-path [path] override output directory.
218 """
219 )
220 sys.exit(exit_code)
223################################################################################
226def init(session):
227 global cnf, Options
229 cnf = Config()
231 Arguments = [
232 ("h", "help", "Show-New::Options::Help"),
233 ("p", "html-path", "Show-New::HTMLPath", "HasArg"),
234 ("q", "queue", "Show-New::Options::Queue", "HasArg"),
235 ]
237 for i in ["help"]:
238 key = "Show-New::Options::%s" % i
239 if key not in cnf: 239 ↛ 237line 239 didn't jump to line 237 because the condition on line 239 was always true
240 cnf[key] = ""
242 changesnames = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) # type: ignore[attr-defined]
243 Options = cnf.subtree("Show-New::Options")
245 if Options["help"]:
246 usage()
248 queue_names = Options.find("Queue", "new").split(",")
249 uploads = (
250 session.query(PolicyQueueUpload)
251 .join(PolicyQueueUpload.policy_queue)
252 .filter(PolicyQueue.queue_name.in_(queue_names))
253 .join(PolicyQueueUpload.changes)
254 .order_by(DBChange.source)
255 )
257 if len(changesnames) > 0: 257 ↛ 258line 257 didn't jump to line 258 because the condition on line 257 was never true
258 uploads = uploads.filter(DBChange.changesname.in_(changesnames))
260 return uploads
263def result_callback(r):
264 code, msg = r
265 if code == PROC_STATUS_EXCEPTION:
266 print("Job raised exception: %s" % (msg))
267 elif code != PROC_STATUS_SUCCESS:
268 print("Job failed: %s" % (msg))
271################################################################################
272################################################################################
275def main():
276 dak.examine_package.use_html = True
277 pool = DakProcessPool(processes=5)
279 session = DBConn().session()
280 upload_ids = [u.id for u in init(session)]
281 session.close()
283 for upload_id in upload_ids:
284 pool.apply_async(do_pkg, [upload_id], callback=result_callback)
285 pool.close()
287 pool.join()
289 for htmlfile in htmlfiles_to_process: 289 ↛ 290line 289 didn't jump to line 290 because the loop on line 289 never started
290 with open(htmlfile, "w") as fd:
291 fd.write(timeout_str)
293 if pool.overall_status() != PROC_STATUS_SUCCESS: 293 ↛ 294line 293 didn't jump to line 294 because the condition on line 293 was never true
294 raise Exception("Processing failed (code %s)" % (pool.overall_status()))
296 files = set(os.listdir(cnf["Show-New::HTMLPath"]))
297 to_delete = [x for x in files.difference(set(sources)) if x.endswith(".html")]
298 for f in to_delete:
299 os.remove(os.path.join(cnf["Show-New::HTMLPath"], f))
302################################################################################
305if __name__ == "__main__":
306 main()