Coverage for dak/import_repository.py: 15%
123 statements
« prev ^ index » next coverage.py v7.6.0, created at 2026-08-03 16:46 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2026-08-03 16:46 +0000
1# Copyright (C) 2015, Ansgar Burchardt <ansgar@debian.org>
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License along
14# with this program; if not, write to the Free Software Foundation, Inc.,
15# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17# This is still work-in-progress and far too incomplete.
18# ruff: noqa
19# type: ignore
21import sys
22from collections import defaultdict
24import apt_pkg
26import daklib.archive
27import daklib.config
28import daklib.dbconn
29import daklib.import_repository
30import daklib.utils
33def usage(status=0):
34 print(
35 """
36dak import-repository
37 --keyring=/usr/share/keyrings/debian-archive-keyring.gpg
38 [--key=${fingerprint}]
39 [--architectures=a,b,c (default: architectures in origin suite)]
40 [--components=main,contrib (default: components in origin suite)]
41 [--target-suite=${suite} (default: origin suite name)]
42 [--add-overrides]
43 [--max-packages=${n} (import at maximum ${n} packages, default: no limit)]
44 http://httpredir.debian.org/debian unstable
46Things to think about:
47 - Import Built-Using sources
48 - all / only referenced
49 - Remove old packages:
50 - by-source: remove source X_v, if no X exists upstream
51 - by-version: remove source X_v, if no X_v exists upstream
52 (X denotes package name, v version, X_v package at a specific version)
53 - Import all or only newest?
54 - Expire binary packages?
55"""
56 )
57 sys.exit(status)
60def entry_is_newer(entry, packages):
61 version = entry["Version"]
62 for p in packages[entry["Package"]]:
63 if apt_pkg.version_compare(version, p.version) <= 0:
64 return False
65 return True
68def entry_in_packages(entry, packages):
69 return entry["Package"] in packages
72def get_packages_in_suite(suite):
73 sources = defaultdict(list)
74 for s in suite.sources:
75 sources[s.source].append(s)
77 packages = defaultdict(list)
78 for b in suite.binaries:
79 packages[b.package].append(b)
81 return sources, packages
84def import_sources(
85 base,
86 sources,
87 transaction,
88 target_suite,
89 component,
90 target_sources,
91 extra_sources,
92 extra_sources_comp,
93 max_packages=None,
94):
95 n = 0
96 for entry in sources:
97 if max_packages is not None and n > max_packages:
98 break
99 if entry.get("Extra-Source-Only", "no") == "yes":
100 # Remember package, we might need to import it later.
101 key = (entry["Package"], entry["Version"])
102 extra_sources[key] = entry
103 extra_sources_comp[key].add(c)
104 continue
105 if not entry_in_packages(entry, target_sources) or entry_is_newer(
106 entry, target_sources
107 ):
108 print("Importing {0}={1}".format(entry["Package"], entry["Version"]))
109 daklib.import_repository.import_source_to_suite(
110 base, entry, transaction, target_suite, component
111 )
112 n += 1
113 return n
116def import_built_using(
117 base,
118 source,
119 version,
120 transaction,
121 target_suite,
122 component,
123 extra_sources,
124 extra_sources_comp,
125):
126 if not daklib.import_repository.source_in_archive(
127 bu_source, bu_version, target_suite.archive
128 ):
129 print("Importing extra source {0}={1}".format(bu_source, bu_version))
130 key = (bu_source, bu_version)
131 extra_entry = extra_sources.get(key)
132 if extra_entry is None:
133 raise Exception(
134 "Extra source {0}={1} referenced by {2}={3} ({4}) not found in source suite.".format(
135 bu_source,
136 bu_version,
137 entry["Package"],
138 entry["Version"],
139 architecture,
140 )
141 )
142 # extra_components = extra_sources_comp[key]
143 if c in components:
144 extra_component = component
145 else:
146 # TODO: Take preferred components from those listed...
147 raise Exception("Not implemented.")
148 daklib.import_repository.import_source_to_suite(
149 base, extra_entry, transaction, target_suite, extra_component
150 )
153def import_packages(
154 base,
155 packages,
156 transaction,
157 target_suite,
158 component,
159 architecture,
160 target_binaries,
161 extra_sources,
162 extra_sources_comp,
163 max_packages=None,
164):
165 n = 0
166 for entry in packages:
167 if max_packages is not None and n > max_packages:
168 break
169 if not entry_in_packages(entry, target_binaries) or entry_is_newer(
170 entry, target_binaries
171 ):
172 print(
173 "Importing {0}={1} ({2})".format(
174 entry["Package"], entry["Version"], architecture
175 )
176 )
177 # Import Built-Using sources:
178 for bu_source, bu_version in daklib.utils.parse_built_using(entry):
179 import_built_using(
180 base,
181 bu_source,
182 bu_version,
183 transaction,
184 target_suite,
185 component,
186 extra_sources,
187 extra_sources_comp,
188 )
189 # Import binary:
190 daklib.import_repository.import_package_to_suite(
191 base, entry, transaction, target_suite, component
192 )
193 n += 1
194 return n
197def main(argv=None):
198 if argv is None: 198 ↛ 201line 198 didn't jump to line 201
199 argv = sys.argv
201 arguments = [
202 ("h", "help", "Import-Repository::Help"),
203 ("k", "keyring", "Import-Repository::Keyring", "HasArg"),
204 ("K", "key", "Import-Repository::Key", "HasArg"),
205 ("a", "architectures", "Import-Repository::Architectures", "HasArg"),
206 ("c", "components", "Import-Repository::Components", "HasArg"),
207 ("t", "target-suite", "Import-Repository::Target-Suite", "HasArg"),
208 ("A", "add-overrides", "Import-Repository::AddOverrides"),
209 ("n", "max-packages", "Import-Repository::MaxPackages", "HasArg"),
210 ]
212 cnf = daklib.config.Config()
213 argv = apt_pkg.parse_commandline(cnf.Cnf, arguments, argv) # type: ignore[attr-defined]
214 options = cnf.subtree("Import-Repository")
216 if "Help" in options or len(argv) < 2: 216 ↛ 219line 216 didn't jump to line 219 because the condition on line 216 was always true
217 usage(0)
219 keyring = options.find("Keyring") or None
220 if keyring is None:
221 print("Error: No keyring specified")
222 print()
224 if "Key" in options:
225 raise Exception("Not implemented.")
227 if "AddOverrides" in options:
228 raise Exception("Not implemented.")
230 if "MaxPackages" in options:
231 max_packages = int(options["MaxPackages"])
232 else:
233 max_packages = None
235 base, suite = argv[0:2]
237 target_suite_name = options.find("Target-Suite") or suite
239 print(
240 "Importing packages from {0}/dists/{1} to {2}".format(
241 base, suite, target_suite_name
242 )
243 )
244 with daklib.archive.ArchiveTransaction() as transaction:
245 target_suite = daklib.dbconn.get_suite(target_suite_name, transaction.session)
246 if target_suite is None:
247 daklib.utils.fubar(
248 "Target suite '{0}' is unknown.".format(target_suite_name)
249 )
251 release = daklib.import_repository.obtain_release(base, suite, keyring)
252 target_sources, target_binaries = get_packages_in_suite(target_suite)
254 if "Architectures" in options:
255 architectures = options["Architectures"].split(",")
256 else:
257 architectures = ["all"] + release.architectures()
259 if "Components" in options:
260 components = options["Components"].split(",")
261 else:
262 components = release.components()
264 # TODO: Clean this up...
266 n = 0
268 # For Extra-Source-Only sources packages, keep a dict
269 # (name, version) -> entry and (name, version) -> set of components
270 # to allow importing needed packages at a later stage
271 extra_sources = dict()
272 extra_sources_comp = defaultdict(set)
274 for c in components:
275 component = daklib.dbconn.get_component(c, transaction.session)
276 print("Processing {0}/source...".format(c))
277 sources = release.sources(c)
278 imported = import_sources(
279 base,
280 sources,
281 transaction,
282 target_suite,
283 component,
284 target_sources,
285 extra_sources,
286 extra_sources_comp,
287 max_packages,
288 )
289 print(" imported {0} source packages".format(imported))
290 n += imported
291 if max_packages is not None:
292 max_packages -= n
294 for c in components:
295 component = daklib.dbconn.get_component(c, transaction.session)
296 for architecture in architectures:
297 print("Processing {0}/{1}...".format(c, architecture))
298 packages = release.packages(c, architecture)
299 imported = import_packages(
300 base,
301 packages,
302 transaction,
303 target_suite,
304 component,
305 architecture,
306 target_binaries,
307 extra_sources,
308 extra_sources_comp,
309 max_packages,
310 )
311 print(" imported {0} binary packages".format(imported))
312 n += imported
313 if max_packages is not None:
314 max_packages -= n
316 transaction.rollback()