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.
19import os
20import sys
22import apt_pkg
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)
42def usage():
43 print(
44 """Usage:
46dak import <suite> <component> <files...>
47dak import -D|--dump <file> <suite> <component>
48dak import -E|--export-dump <suite> <component>
50WARNING: This command does no sanity checks. Only use it on trusted packages.
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
63File format used by --dump:
65 <filename>:<md5>:<sha1>:<sha256>:[<fingerprint>]:[<changed-by>]
66"""
67 )
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
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)
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])
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()
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 )
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
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])
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 )
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 )
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 )
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))
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))
278 hashed_file = daklib.upload.HashedFile(filename, int(size), md5, sha1, sha256)
279 hashed_file.check(directory)
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 )
295 transaction.commit()
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 )
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
319WHERE
320 suite.id = :suite_id
321 AND fam.component_id = :component_id
323ORDER BY tmp.order, f.filename;
324"""
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))
337def main(argv=None):
338 if argv is None: 338 ↛ 341line 338 didn't jump to line 341
339 argv = sys.argv
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 ]
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")
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)
359 suite_name = argv[0]
360 component_name = argv[1]
362 add_overrides = options.find_b("AddOverrides")
363 require_signature = not options.find_b("IgnoreSignature")
364 changed_by = options.find("ChangedBy") or None
366 log = daklib.daklog.Logger("import")
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]
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()
415 log.close()
418if __name__ == "__main__":
419 main()