1#! /usr/bin/env python3 

2# 

3# Copyright (C) 2012, Ansgar Burchardt <ansgar@debian.org> 

4# 

5# This program is free software; you can redistribute it and/or modify 

6# it under the terms of the GNU General Public License as published by 

7# the Free Software Foundation; either version 2 of the License, or 

8# (at your option) any later version. 

9# 

10# This program is distributed in the hope that it will be useful, 

11# but WITHOUT ANY WARRANTY; without even the implied warranty of 

12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

13# GNU General Public License for more details. 

14# 

15# You should have received a copy of the GNU General Public License along 

16# with this program; if not, write to the Free Software Foundation, Inc., 

17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 

18 

19import os 

20import sys 

21 

22import apt_pkg 

23 

24import daklib.archive 

25import daklib.config 

26import daklib.daklog 

27import daklib.regexes 

28import daklib.upload 

29from daklib.dbconn import ( 

30 Component, 

31 Fingerprint, 

32 Keyring, 

33 Override, 

34 OverrideType, 

35 Priority, 

36 Section, 

37 Suite, 

38 get_or_set_maintainer, 

39) 

40 

41 

42def usage(): 

43 print( 

44 """Usage: 

45 

46dak import <suite> <component> <files...> 

47dak import -D|--dump <file> <suite> <component> 

48dak import -E|--export-dump <suite> <component> 

49 

50WARNING: This command does no sanity checks. Only use it on trusted packages. 

51 

52Options: 

53 -h, --help: show this help message 

54 -a, --add-overrides: add missing overrides automatically 

55 -c, --changed-by: Changed-By for imported source packages 

56 (default: maintainer) 

57 -D, --dump <file>: Import all files listed in <file>. The format 

58 is described below. 

59 -E, --export-dump: Export list of files in the format required 

60 by dak import --dump. 

61 -s, --ignore-signature: ignore signature for imported source packages 

62 

63File format used by --dump: 

64 

65 <filename>:<md5>:<sha1>:<sha256>:[<fingerprint>]:[<changed-by>] 

66""" 

67 ) 

68 

69 

70def import_source( 

71 log, 

72 transaction, 

73 suite, 

74 component, 

75 directory, 

76 hashed_file, 

77 fingerprint=None, 

78 changed_by=None, 

79 keyrings=None, 

80 require_signature=True, 

81 add_overrides=False, 

82): 

83 if keyrings is None: 

84 keyrings = [] 

85 filename = hashed_file.filename 

86 session = transaction.session 

87 

88 source = daklib.upload.Source(directory, [hashed_file], keyrings, require_signature) 

89 if source.valid_signature: 

90 fingerprint = ( 

91 session.query(Fingerprint) 

92 .filter_by(fingerprint=source.primary_fingerprint) 

93 .first() 

94 ) 

95 if changed_by is None: 

96 changed_by = source.dsc["Maintainer"] 

97 db_changed_by = get_or_set_maintainer(changed_by, session) 

98 

99 transaction.install_source( 

100 directory, source, suite, component, db_changed_by, fingerprint=fingerprint 

101 ) 

102 log.log(["import-source", suite.suite_name, component.component_name, filename]) 

103 

104 if ( 

105 add_overrides 

106 and not session.query(Override) 

107 .filter_by( 

108 suite=suite.get_overridesuite(), 

109 component=component, 

110 package=source.dsc["Source"], 

111 ) 

112 .join(OverrideType) 

113 .filter(OverrideType.overridetype == "dsc") 

114 .first() 

115 ): 

116 overridetype = session.query(OverrideType).filter_by(overridetype="dsc").one() 

117 overridesuite = suite.get_overridesuite() 

118 section_name = "misc" 

119 if component.component_name != "main": 

120 section_name = "{0}/{1}".format(component.component_name, section_name) 

121 section = session.query(Section).filter_by(section=section_name).one() 

122 priority = session.query(Priority).filter_by(priority="optional").one() 

123 

124 override = Override( 

125 package=source.dsc["Source"], 

126 suite=overridesuite, 

127 component=component, 

128 section=section, 

129 priority=priority, 

130 overridetype=overridetype, 

131 ) 

132 session.add(override) 

133 log.log( 

134 [ 

135 "add-source-override", 

136 suite.suite_name, 

137 component.component_name, 

138 source.dsc["Source"], 

139 section.section, 

140 priority.priority, 

141 ] 

142 ) 

143 

144 

145def import_binary( 

146 log, 

147 transaction, 

148 suite, 

149 component, 

150 directory, 

151 hashed_file, 

152 fingerprint=None, 

153 add_overrides=False, 

154): 

155 filename = hashed_file.filename 

156 session = transaction.session 

157 

158 binary = daklib.upload.Binary(directory, hashed_file) 

159 transaction.install_binary( 

160 directory, binary, suite, component, fingerprint=fingerprint 

161 ) 

162 log.log(["import-binary", suite.suite_name, component.component_name, filename]) 

163 

164 if ( 

165 add_overrides 

166 and not session.query(Override) 

167 .filter_by( 

168 suite=suite.get_overridesuite(), 

169 component=component, 

170 package=binary.control["Package"], 

171 ) 

172 .join(OverrideType) 

173 .filter(OverrideType.overridetype == binary.type) 

174 .first() 

175 ): 

176 overridetype = ( 

177 session.query(OverrideType).filter_by(overridetype=binary.type).one() 

178 ) 

179 overridesuite = suite.get_overridesuite() 

180 section = ( 

181 session.query(Section).filter_by(section=binary.control["Section"]).one() 

182 ) 

183 priority = ( 

184 session.query(Priority) 

185 .filter_by(priority=binary.control.get("Priority", "optional")) 

186 .one() 

187 ) 

188 

189 override = Override( 

190 package=binary.control["Package"], 

191 suite=overridesuite, 

192 component=component, 

193 section=section, 

194 priority=priority, 

195 overridetype=overridetype, 

196 ) 

197 session.add(override) 

198 log.log( 

199 [ 

200 "add-binary-override", 

201 suite.suite_name, 

202 component.component_name, 

203 binary.control["Package"], 

204 section.section, 

205 priority.priority, 

206 ] 

207 ) 

208 

209 

210def import_file( 

211 log, 

212 transaction, 

213 suite, 

214 component, 

215 directory, 

216 hashed_file, 

217 fingerprint=None, 

218 changed_by=None, 

219 keyrings=None, 

220 require_signature=True, 

221 add_overrides=False, 

222): 

223 filename = hashed_file.filename 

224 if daklib.regexes.re_file_binary.match(filename): 

225 import_binary( 

226 log, 

227 transaction, 

228 suite, 

229 component, 

230 directory, 

231 hashed_file, 

232 fingerprint=fingerprint, 

233 add_overrides=add_overrides, 

234 ) 

235 elif daklib.regexes.re_file_dsc.match(filename): 

236 import_source( 

237 log, 

238 transaction, 

239 suite, 

240 component, 

241 directory, 

242 hashed_file, 

243 fingerprint=fingerprint, 

244 changed_by=changed_by, 

245 keyrings=keyrings, 

246 require_signature=require_signature, 

247 add_overrides=add_overrides, 

248 ) 

249 else: 

250 raise Exception( 

251 "File is neither source nor binary package: {0}".format(filename) 

252 ) 

253 

254 

255def import_dump( 

256 log, 

257 transaction, 

258 suite, 

259 component, 

260 fh, 

261 keyrings=None, 

262 require_signature=True, 

263 add_overrides=False, 

264): 

265 session = transaction.session 

266 for line in fh: 

267 path, size, md5, sha1, sha256, fpr, changed_by = line.strip().split(":", 6) 

268 directory, filename = os.path.split(os.path.abspath(path)) 

269 

270 if not changed_by: 

271 changed_by = None 

272 fingerprint = None 

273 if fpr: 

274 fingerprint = session.query(Fingerprint).filter_by(fingerprint=fpr).first() 

275 if fingerprint is None: 

276 print("W: {0}: unknown fingerprint {1}".format(filename, fpr)) 

277 

278 hashed_file = daklib.upload.HashedFile(filename, int(size), md5, sha1, sha256) 

279 hashed_file.check(directory) 

280 

281 import_file( 

282 log, 

283 transaction, 

284 suite, 

285 component, 

286 directory, 

287 hashed_file, 

288 fingerprint=fingerprint, 

289 changed_by=changed_by, 

290 keyrings=keyrings, 

291 require_signature=require_signature, 

292 add_overrides=add_overrides, 

293 ) 

294 

295 transaction.commit() 

296 

297 

298_export_query = r""" 

299WITH 

300tmp AS 

301 (SELECT 1 AS order, s.file AS file_id, s.sig_fpr AS fingerprint_id, s.changedby AS changed_by, sa.suite AS suite_id 

302 FROM source s 

303 JOIN src_associations sa ON sa.source = s.id 

304 UNION 

305 SELECT 2 AS order, b.file AS file_id, b.sig_fpr AS fingerprint_id, NULL, ba.suite AS suite_id 

306 FROM binaries b 

307 JOIN bin_associations ba ON ba.bin = b.id 

308 ) 

309 

310SELECT 

311 f.filename, f.size::TEXT, f.md5sum, f.sha1sum, f.sha256sum, COALESCE(fpr.fingerprint, ''), COALESCE(m.name, '') 

312FROM files f 

313JOIN tmp ON f.id = tmp.file_id 

314JOIN suite ON suite.id = tmp.suite_id 

315JOIN files_archive_map fam ON fam.file_id = f.id AND fam.archive_id = suite.archive_id 

316LEFT JOIN fingerprint fpr ON fpr.id = tmp.fingerprint_id 

317LEFT JOIN maintainer m ON m.id = tmp.changed_by 

318 

319WHERE 

320 suite.id = :suite_id 

321 AND fam.component_id = :component_id 

322 

323ORDER BY tmp.order, f.filename; 

324""" 

325 

326 

327def export_dump(transaction, suite, component): 

328 session = transaction.session 

329 query = session.execute( 

330 _export_query, 

331 {"suite_id": suite.suite_id, "component_id": component.component_id}, 

332 ) 

333 for row in query: 

334 print(":".join(row)) 

335 

336 

337def main(argv=None): 

338 if argv is None: 338 ↛ 341line 338 didn't jump to line 341

339 argv = sys.argv 

340 

341 arguments = [ 

342 ("h", "help", "Import::Options::Help"), 

343 ("a", "add-overrides", "Import::Options::AddOverrides"), 

344 ("c", "changed-by", "Import::Options::ChangedBy", "HasArg"), 

345 ("D", "dump", "Import::Options::Dump", "HasArg"), 

346 ("E", "export-dump", "Import::Options::Export"), 

347 ("s", "ignore-signature", "Import::Options::IgnoreSignature"), 

348 ] 

349 

350 cnf = daklib.config.Config() 

351 cnf["Import::Options::Dummy"] = "" 

352 argv = apt_pkg.parse_commandline(cnf.Cnf, arguments, argv) 

353 options = cnf.subtree("Import::Options") 

354 

355 if "Help" in options or len(argv) < 2: 355 ↛ 359line 355 didn't jump to line 359, because the condition on line 355 was never false

356 usage() 

357 sys.exit(0) 

358 

359 suite_name = argv[0] 

360 component_name = argv[1] 

361 

362 add_overrides = options.find_b("AddOverrides") 

363 require_signature = not options.find_b("IgnoreSignature") 

364 changed_by = options.find("ChangedBy") or None 

365 

366 log = daklib.daklog.Logger("import") 

367 

368 with daklib.archive.ArchiveTransaction() as transaction: 

369 session = transaction.session 

370 suite = session.query(Suite).filter_by(suite_name=suite_name).one() 

371 component = ( 

372 session.query(Component).filter_by(component_name=component_name).one() 

373 ) 

374 keyrings = ( 

375 session.query(Keyring).filter_by(active=True).order_by(Keyring.priority) 

376 ) 

377 keyring_files = [k.keyring_name for k in keyrings] 

378 

379 dump = options.find("Dump") or None 

380 if options.find_b("Export"): 

381 export_dump(transaction, suite, component) 

382 transaction.rollback() 

383 elif dump is not None: 

384 with open(dump, "r") as fh: 

385 import_dump( 

386 log, 

387 transaction, 

388 suite, 

389 component, 

390 fh, 

391 keyring_files, 

392 require_signature=require_signature, 

393 add_overrides=add_overrides, 

394 ) 

395 transaction.commit() 

396 else: 

397 files = argv[2:] 

398 for f in files: 

399 directory, filename = os.path.split(os.path.abspath(f)) 

400 hashed_file = daklib.upload.HashedFile.from_file(directory, filename) 

401 import_file( 

402 log, 

403 transaction, 

404 suite, 

405 component, 

406 directory, 

407 hashed_file, 

408 changed_by=changed_by, 

409 keyrings=keyring_files, 

410 require_signature=require_signature, 

411 add_overrides=add_overrides, 

412 ) 

413 transaction.commit() 

414 

415 log.close() 

416 

417 

418if __name__ == "__main__": 

419 main()