1#! /usr/bin/env python3 

2 

3""" Output html for packages in NEW """ 

4# Copyright (C) 2007, 2009 Joerg Jaspert <joerg@debian.org> 

5 

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. 

10 

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. 

15 

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 

19 

20################################################################################ 

21 

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 ...." 

25 

26################################################################################ 

27 

28import os 

29import sys 

30import time 

31import apt_pkg 

32import dak.examine_package 

33 

34from daklib import policy 

35from daklib.dbconn import * 

36from daklib.config import Config 

37from daklib.dakmultiprocessing import DakProcessPool, PROC_STATUS_SUCCESS, PROC_STATUS_EXCEPTION 

38from multiprocessing import Manager 

39 

40# Globals 

41Cnf = None 

42Options = None 

43manager = Manager() 

44sources = manager.list() 

45htmlfiles_to_process = manager.list() 

46timeout_str = "Error or timeout while processing" 

47 

48 

49################################################################################ 

50################################################################################ 

51################################################################################ 

52 

53def html_header(name, missing): 

54 if name.endswith('.changes'): 54 ↛ 55line 54 didn't jump to line 55, because the condition on line 54 was never true

55 name = ' '.join(name.split('_')[:2]) 

56 result = """<!DOCTYPE html> 

57<html lang="en"> 

58 <head> 

59 <meta charset="utf-8"> 

60 <title>%(name)s - Debian NEW package overview</title> 

61 <link rel="stylesheet" href="/style.css"> 

62 <link rel="shortcut icon" href="https://www.debian.org/favicon.ico"> 

63 <script> 

64 function toggle(id, initial, display) { 

65 var o = document.getElementById(id); 

66 toggleObj(o, initial, display); 

67 } 

68 function show(id, display) { 

69 var o = document.getElementById(id); 

70 o.style.display = 'table-row-group'; 

71 } 

72 function toggleObj(o, initial, display) { 

73 if(! o.style.display) 

74 o.style.display = initial; 

75 if(o.style.display == display) { 

76 o.style.display = "none"; 

77 } else { 

78 o.style.display = display; 

79 } 

80 } 

81 </script> 

82 </head> 

83 <body id="NEW-details-page"> 

84 <div id="logo"> 

85 <a href="https://www.debian.org/"> 

86 <img src="https://www.debian.org/logos/openlogo-nd-50.png" 

87 alt=""></a> 

88 <a href="https://www.debian.org/"> 

89 <img src="https://www.debian.org/Pics/debian.png" 

90 alt="Debian Project"></a> 

91 </div> 

92 <div id="titleblock"> 

93 <img src="https://www.debian.org/Pics/red-upperleft.png" 

94 id="red-upperleft" alt=""> 

95 <img src="https://www.debian.org/Pics/red-lowerleft.png" 

96 id="red-lowerleft" alt=""> 

97 <img src="https://www.debian.org/Pics/red-upperright.png" 

98 id="red-upperright" alt=""> 

99 <img src="https://www.debian.org/Pics/red-lowerright.png" 

100 id="red-lowerright" alt=""> 

101 <span class="title"> 

102 Debian NEW package overview for %(name)s 

103 </span> 

104 </div> 

105 

106 """ % {"name": name} 

107 

108 # we assume only one source (.dsc) per changes here 

109 result += """ 

110 <div id="menu"> 

111 <p class="title">Navigation</p> 

112 <p><a href="#changes" onclick="show('changes-body')">.changes</a></p> 

113 <p><a href="#dsc" onclick="show('dsc-body')">.dsc</a></p> 

114 <p><a href="#source-lintian" onclick="show('source-lintian-body')">source lintian</a></p> 

115 

116""" 

117 for binarytype, packagename in [m for m in missing if m[0] in ('deb', 'udeb')]: 

118 result += """ 

119 <p class="subtitle">%(pkg)s</p> 

120 <p><a href="#binary-%(pkg)s-control" onclick="show('binary-%(pkg)s-control-body')">control file</a></p> 

121 <p><a href="#binary-%(pkg)s-lintian" onclick="show('binary-%(pkg)s-lintian-body')">binary lintian</a></p> 

122 <p><a href="#binary-%(pkg)s-contents" onclick="show('binary-%(pkg)s-contents-body')">.deb contents</a></p> 

123 <p><a href="#binary-%(pkg)s-copyright" onclick="show('binary-%(pkg)s-copyright-body')">copyright</a></p> 

124 <p><a href="#binary-%(pkg)s-file-listing" onclick="show('binary-%(pkg)s-file-listing-body')">file listing</a></p> 

125 

126""" % {"pkg": packagename} 

127 result += " </div>" 

128 return result 

129 

130 

131def html_footer(): 

132 result = """ <p class="validate">Timestamp: %s (UTC)</p> 

133""" % (time.strftime("%d.%m.%Y / %H:%M:%S", time.gmtime())) 

134 result += "</body></html>" 

135 return result 

136 

137################################################################################ 

138 

139 

140def do_pkg(upload_id): 

141 cnf = Config() 

142 

143 session = DBConn().session() 

144 upload = session.query(PolicyQueueUpload).filter_by(id=upload_id).one() 

145 

146 queue = upload.policy_queue 

147 changes = upload.changes 

148 

149 origchanges = os.path.join(queue.path, changes.changesname) 

150 print(origchanges) 

151 

152 htmlname = "{0}_{1}.html".format(changes.source, changes.version) 

153 htmlfile = os.path.join(cnf['Show-New::HTMLPath'], htmlname) 

154 

155 # Have we already processed this? 

156 if os.path.exists(htmlfile) and \ 156 ↛ 158line 156 didn't jump to line 158, because the condition on line 156 was never true

157 os.stat(htmlfile).st_mtime > time.mktime(changes.created.timetuple()): 

158 with open(htmlfile, "r") as fd: 

159 if fd.read() != timeout_str: 

160 sources.append(htmlname) 

161 return (PROC_STATUS_SUCCESS, 

162 '%s already up-to-date' % htmlfile) 

163 

164 # Go, process it... Now! 

165 htmlfiles_to_process.append(htmlfile) 

166 sources.append(htmlname) 

167 

168 group = cnf.get('Dinstall::UnprivGroup') or None 

169 

170 with open(htmlfile, 'w') as outfile, \ 

171 policy.UploadCopy(upload, group=group) as upload_copy: 

172 handler = policy.PolicyQueueUploadHandler(upload, session) 

173 missing = [(o['type'], o['package']) for o in handler.missing_overrides()] 

174 distribution = changes.distribution 

175 

176 outfile.write(html_header(changes.source, missing)) 

177 outfile.write(dak.examine_package.display_changes(distribution, origchanges)) 

178 

179 if upload.source is not None and ('dsc', upload.source.source) in missing: 179 ↛ 182line 179 didn't jump to line 182, because the condition on line 179 was never false

180 fn = os.path.join(upload_copy.directory, upload.source.poolfile.basename) 

181 outfile.write(dak.examine_package.check_dsc(distribution, fn, session)) 

182 for binary in upload.binaries: 

183 if (binary.binarytype, binary.package) not in missing: 183 ↛ 184line 183 didn't jump to line 184, because the condition on line 183 was never true

184 continue 

185 fn = os.path.join(upload_copy.directory, binary.poolfile.basename) 

186 outfile.write(dak.examine_package.check_deb(distribution, fn, session)) 

187 

188 outfile.write(html_footer()) 

189 

190 session.close() 

191 htmlfiles_to_process.remove(htmlfile) 

192 return (PROC_STATUS_SUCCESS, '{0} already updated'.format(htmlfile)) 

193 

194################################################################################ 

195 

196 

197def usage(exit_code=0): 

198 print("""Usage: dak show-new [OPTION]... [CHANGES]... 

199 -h, --help show this help and exit. 

200 -p, --html-path [path] override output directory. 

201 """) 

202 sys.exit(exit_code) 

203 

204################################################################################ 

205 

206 

207def init(session): 

208 global cnf, Options 

209 

210 cnf = Config() 

211 

212 Arguments = [('h', "help", "Show-New::Options::Help"), 

213 ("p", "html-path", "Show-New::HTMLPath", "HasArg"), 

214 ('q', 'queue', 'Show-New::Options::Queue', 'HasArg')] 

215 

216 for i in ["help"]: 

217 key = "Show-New::Options::%s" % i 

218 if key not in cnf: 218 ↛ 216line 218 didn't jump to line 216, because the condition on line 218 was never false

219 cnf[key] = "" 

220 

221 changesnames = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) 

222 Options = cnf.subtree("Show-New::Options") 

223 

224 if Options["help"]: 

225 usage() 

226 

227 queue_names = Options.find('Queue', 'new').split(',') 

228 uploads = session.query(PolicyQueueUpload) \ 

229 .join(PolicyQueueUpload.policy_queue).filter(PolicyQueue.queue_name.in_(queue_names)) \ 

230 .join(PolicyQueueUpload.changes).order_by(DBChange.source) 

231 

232 if len(changesnames) > 0: 232 ↛ 233line 232 didn't jump to line 233, because the condition on line 232 was never true

233 uploads = uploads.filter(DBChange.changesname.in_(changesnames)) 

234 

235 return uploads 

236 

237 

238def result_callback(r): 

239 code, msg = r 

240 if code == PROC_STATUS_EXCEPTION: 240 ↛ 241line 240 didn't jump to line 241, because the condition on line 240 was never true

241 print("Job raised exception: %s" % (msg)) 

242 elif code != PROC_STATUS_SUCCESS: 242 ↛ 243line 242 didn't jump to line 243, because the condition on line 242 was never true

243 print("Job failed: %s" % (msg)) 

244 

245 

246################################################################################ 

247################################################################################ 

248 

249def main(): 

250 dak.examine_package.use_html = True 

251 pool = DakProcessPool(processes=5) 

252 

253 session = DBConn().session() 

254 upload_ids = [u.id for u in init(session)] 

255 session.close() 

256 

257 for upload_id in upload_ids: 

258 pool.apply_async(do_pkg, [upload_id], callback=result_callback) 

259 pool.close() 

260 

261 pool.join() 

262 

263 for htmlfile in htmlfiles_to_process: 263 ↛ 264line 263 didn't jump to line 264, because the loop on line 263 never started

264 with open(htmlfile, "w") as fd: 

265 fd.write(timeout_str) 

266 

267 if pool.overall_status() != PROC_STATUS_SUCCESS: 267 ↛ 268line 267 didn't jump to line 268, because the condition on line 267 was never true

268 raise Exception("Processing failed (code %s)" % (pool.overall_status())) 

269 

270 files = set(os.listdir(cnf["Show-New::HTMLPath"])) 

271 to_delete = [x for x in files.difference(set(sources)) if x.endswith(".html")] 

272 for f in to_delete: 

273 os.remove(os.path.join(cnf["Show-New::HTMLPath"], f)) 

274 

275################################################################################ 

276 

277 

278if __name__ == '__main__': 

279 main()