1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import sys
20
21 import sqlalchemy.sql as sql
22 from sqlalchemy.orm.exc import NoResultFound
23
24 import daklib.daklog
25 import daklib.utils
26 from daklib.archive import ArchiveTransaction
27 from daklib.dbconn import ArchiveFile, Component, DBBinary, DBSource, PoolFile, Suite
28
29 """
30 Idea:
31
32 dak update-suite testing testing-kfreebsd
33 -> grab all source & binary packages from testing with a higher version
34 than in testing-kfreebsd (or not in -kfreebsd) and copy them
35 -> limited to architectures in testing-kfreebsd
36 -> obeys policy queues
37 -> copies to build queues
38
39 dak update-suite --create-in=ftp-master stable testing
40 -> create suite "testing" based on "stable" in archive "ftp-master"
41
42 Additional switches:
43 --skip-policy-queue: skip target suite's policy queue
44 --skip-build-queues: do not copy to build queue
45 --no-new-packages: do not copy new packages
46 -> source-based, new binaries from existing sources will be added
47 --only-new-packages: do not update existing packages
48 -> source-based, do not copy new binaries w/o source!
49 --also-policy-queue: also copy pending packages from policy queue
50 --update-overrides: update overrides as well (if different overrides are used)
51 --no-act
52 """
53
54
56 print("dak update-suite [-n|--no-act] <origin> <target>")
57 sys.exit(0)
58
59
61 - def __init__(
62 self,
63 transaction,
64 origin,
65 target,
66 new_packages=True,
67 also_from_policy_queue=False,
68 obey_policy_queue=True,
69 obey_build_queues=True,
70 update_overrides=False,
71 dry_run=False,
72 ):
73 self.transaction = transaction
74 self.origin = origin
75 self.target = target
76 self.new_packages = new_packages
77 self.also_from_policy_queue = also_from_policy_queue
78 self.obey_policy_queue = obey_policy_queue
79 self.obey_build_queues = obey_build_queues
80 self.update_overrides = update_overrides
81 self.dry_run = dry_run
82
83 if obey_policy_queue and target.policy_queue_id is not None:
84 raise Exception("Not implemented...")
85 self.logger = None if dry_run else daklib.daklog.Logger("update-suite")
86
88
89 query = """
90 SELECT b.*
91 FROM binaries b
92 JOIN bin_associations ba ON b.id = ba.bin AND ba.suite = :origin
93 """
94 if self.also_from_policy_queue:
95 query += """
96 UNION
97 SELECT b.*
98 FROM binaries b
99 JOIN policy_queue_upload_binaries_map pqubm ON pqubm.binary_id = b.id
100 JOIN policy_queue_upload pqu ON pqu.id = pqubm.policy_queue_upload_id
101 WHERE pqu.target_suite_id = :origin
102 AND pqu.policy_queue_id = (SELECT policy_queue_id FROM suite WHERE id = :origin)
103 """
104
105
106
107
108
109
110 if self.obey_policy_queue:
111 cond_source_in_policy_queue = """
112 EXISTS (SELECT 1
113 FROM policy_queue_upload pqu
114 WHERE tmp.source = pqu.source_id
115 AND pqu.target_suite_id = :target
116 AND pqu.policy_queue_id = (SELECT policy_queue_id FROM suite WHERE id = :target))
117 """
118 else:
119 cond_source_in_policy_queue = "FALSE"
120 query = """
121 WITH tmp AS ({0})
122 SELECT DISTINCT *
123 FROM tmp
124 WHERE tmp.architecture IN (SELECT architecture FROM suite_architectures WHERE suite = :target)
125 AND (tmp.source IN :additional_sources
126 OR EXISTS (SELECT 1
127 FROM src_associations sa
128 WHERE tmp.source = sa.source AND sa.suite = :target)
129 OR {1})
130 AND NOT EXISTS (SELECT 1
131 FROM binaries b2
132 JOIN bin_associations ba2 ON b2.id = ba2.bin AND ba2.suite = :target
133 WHERE tmp.package = b2.package AND tmp.architecture = b2.architecture AND b2.version >= tmp.version)
134 ORDER BY package, version, architecture
135 """.format(
136 query, cond_source_in_policy_queue
137 )
138
139
140
141
142 if len(additional_sources) == 0:
143 additional_sources = tuple([None])
144
145 params = {
146 "origin": self.origin.suite_id,
147 "target": self.target.suite_id,
148 "additional_sources": additional_sources,
149 }
150
151 return (
152 self.transaction.session.query(DBBinary)
153 .from_statement(sql.text(query))
154 .params(params)
155 )
156
158
159 query = """
160 SELECT s.*
161 FROM source s
162 JOIN src_associations sa ON s.id = sa.source AND sa.suite = :origin
163 """
164 if self.also_from_policy_queue:
165 query += """
166 UNION
167 SELECT s.*
168 FROM source s
169 JOIN policy_queue_upload pqu ON pqu.source_id = s.id
170 WHERE pqu.target_suite_id = :origin
171 AND pqu.policy_queue_id = (SELECT policy_queue_id FROM suite WHERE id = :origin)
172 """
173
174
175 query = """
176 WITH tmp AS ({0})
177 SELECT DISTINCT *
178 FROM tmp
179 WHERE NOT EXISTS (SELECT 1
180 FROM source s2
181 JOIN src_associations sa2 ON s2.id = sa2.source AND sa2.suite = :target
182 WHERE s2.source = tmp.source AND s2.version >= tmp.version)
183 """.format(
184 query
185 )
186
187
188 if not self.new_packages:
189 query += """
190 AND EXISTS (SELECT 1
191 FROM source s2
192 JOIN src_associations sa2 ON s2.id = sa2.source AND sa2.suite = :target
193 WHERE s2.source = tmp.source)
194 """
195
196 query += "ORDER BY source, version"
197
198 params = {"origin": self.origin.suite_id, "target": self.target.suite_id}
199
200 return (
201 self.transaction.session.query(DBSource)
202 .from_statement(sql.text(query))
203 .params(params)
204 )
205
207 session = self.transaction.session
208 return (
209 session.query(Component)
210 .join(ArchiveFile, Component.component_id == ArchiveFile.component_id)
211 .join(ArchiveFile.file)
212 .filter(PoolFile.file_id == binary.poolfile_id)
213 .filter(ArchiveFile.archive_id == suite.archive_id)
214 )
215
217 if len(binaries) == 0:
218 return
219
220
221 if self.origin.archive_id == suite.archive_id:
222 query = "INSERT INTO bin_associations (bin, suite) VALUES (:bin, :suite)"
223 target_id = suite.suite_id
224 params = [{"bin": b.binary_id, "suite": target_id} for b in binaries]
225 self.transaction.session.execute(query, params)
226 else:
227 for b in binaries:
228 for c in self._components_for_binary(b, suite):
229 self.transaction.copy_binary(b, suite, c)
230
232 session = self.transaction.session
233 return (
234 session.query(Component)
235 .join(ArchiveFile, Component.component_id == ArchiveFile.component_id)
236 .join(ArchiveFile.file)
237 .filter(PoolFile.file_id == source.poolfile_id)
238 .filter(ArchiveFile.archive_id == suite.archive_id)
239 )
240
242 if len(sources) == 0:
243 return
244
245
246 if self.origin.archive_id == suite.archive_id:
247 query = (
248 "INSERT INTO src_associations (source, suite) VALUES (:source, :suite)"
249 )
250 target_id = suite.suite_id
251 params = [{"source": s.source_id, "suite": target_id} for s in sources]
252 self.transaction.session.execute(query, params)
253 else:
254 for s in sources:
255 for c in self._components_for_source(s, suite):
256 self.transaction.copy_source(s, suite, c)
257
259 targets = set([self.target])
260 if self.obey_build_queues:
261 targets.update([bq.suite for bq in self.target.copy_queues])
262 target_names = sorted(s.suite_name for s in targets)
263 target_name = ",".join(target_names)
264
265 new_sources = self.query_new_sources().all()
266 additional_sources = tuple(s.source_id for s in new_sources)
267 for s in new_sources:
268 self.log(["add-source", target_name, s.source, s.version])
269 if not self.dry_run:
270 for target in targets:
271 self.install_sources(new_sources, target)
272
273 new_binaries = self.query_new_binaries(additional_sources).all()
274 for b in new_binaries:
275 self.log(
276 [
277 "add-binary",
278 target_name,
279 b.package,
280 b.version,
281 b.architecture.arch_string,
282 ]
283 )
284 if not self.dry_run:
285 for target in targets:
286 self.install_binaries(new_binaries, target)
287
288 - def log(self, args):
289 if self.logger:
290 self.logger.log(args)
291 else:
292 print(args)
293
294
296 from daklib.config import Config
297
298 config = Config()
299
300 import apt_pkg
301
302 arguments = [
303 ("h", "help", "Update-Suite::Options::Help"),
304 ("n", "no-act", "Update-Suite::options::NoAct"),
305 ]
306 argv = apt_pkg.parse_commandline(config.Cnf, arguments, sys.argv)
307 try:
308 options = config.subtree("Update-Suite::Options")
309 except KeyError:
310 options = {}
311
312 if "Help" in options or len(argv) != 2:
313 usage()
314
315 origin_name = argv[0]
316 target_name = argv[1]
317 dry_run = True if "NoAct" in options else False
318
319 with ArchiveTransaction() as transaction:
320 session = transaction.session
321
322 try:
323 origin = session.query(Suite).filter_by(suite_name=origin_name).one()
324 except NoResultFound:
325 daklib.utils.fubar("Origin suite '{0}' is unknown.".format(origin_name))
326 try:
327 target = session.query(Suite).filter_by(suite_name=target_name).one()
328 except NoResultFound:
329 daklib.utils.fubar("Target suite '{0}' is unknown.".format(target_name))
330
331 su = SuiteUpdater(transaction, origin, target, dry_run=dry_run)
332 su.update_suite()
333
334 if dry_run:
335 transaction.rollback()
336 else:
337 transaction.commit()
338
339
340 if __name__ == "__main__":
341 pass
342