Package dak :: Module dominate
[hide private]
[frames] | no frames]

Source Code for Module dak.dominate

  1  #! /usr/bin/env python3 
  2   
  3  """ 
  4  Remove obsolete source and binary associations from suites. 
  5   
  6  @contact: Debian FTP Master <ftpmaster@debian.org> 
  7  @copyright: 2009  Torsten Werner <twerner@debian.org> 
  8  @license: GNU General Public License version 2 or later 
  9  """ 
 10   
 11  # This program is free software; you can redistribute it and/or modify 
 12  # it under the terms of the GNU General Public License as published by 
 13  # the Free Software Foundation; either version 2 of the License, or 
 14  # (at your option) any later version. 
 15   
 16  # This program is distributed in the hope that it will be useful, 
 17  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 18  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 19  # GNU General Public License for more details. 
 20   
 21  # You should have received a copy of the GNU General Public License 
 22  # along with this program; if not, write to the Free Software 
 23  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 24   
 25  import sys 
 26   
 27  import apt_pkg 
 28  from sqlalchemy.sql import exists, text 
 29  from tabulate import tabulate 
 30   
 31  from daklib import daklog, utils 
 32  from daklib.config import Config 
 33  from daklib.dbconn import DBConn, PolicyQueue, Suite 
 34   
 35  Options = None 
 36  Logger = None 
 37   
 38   
39 -def retrieve_associations(suites, session):
40 return session.execute( 41 text( 42 """ 43 WITH 44 -- Provide (source, suite) tuple of all source packages to remain 45 remain_source AS ( 46 SELECT 47 * 48 FROM ( 49 SELECT 50 source.id AS source_id, 51 src_associations.suite AS suite_id, 52 -- generate rank over versions of a source package in one suite 53 -- "1" being the newest 54 dense_rank() OVER ( 55 PARTITION BY source.source, src_associations.suite 56 ORDER BY source.version DESC 57 ) AS version_rank 58 FROM 59 source 60 INNER JOIN src_associations ON 61 src_associations.source = source.id 62 AND src_associations.suite = ANY(:suite_ids) 63 ) AS source_ranked 64 WHERE 65 version_rank = 1 66 ), 67 -- Provide (source, arch, suite) tuple of all binary packages to remain 68 remain_binaries AS ( 69 SELECT 70 * 71 FROM ( 72 SELECT 73 binaries.id, 74 binaries.architecture AS arch_id, 75 bin_associations.suite AS suite_id, 76 source.id AS source_id, 77 architecture.arch_string AS arch, 78 -- arch of newest version 79 first_value(architecture.arch_string) OVER ( 80 PARTITION BY binaries.package, bin_associations.suite 81 ORDER BY binaries.version DESC 82 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 83 ) as arch_first, 84 -- generate rank over versions of a source package in one suite 85 -- "1" being the newest 86 -- if newest package is arch-any, we use the rank only over current arch 87 dense_rank() OVER ( 88 PARTITION BY binaries.package, binaries.architecture, bin_associations.suite 89 ORDER BY binaries.version DESC 90 ) AS version_rank_any, 91 -- if newest package is arch-all, we use the rank over all arches 92 -- this makes it possible to replace all by any and any by all 93 dense_rank() OVER ( 94 PARTITION BY binaries.package, bin_associations.suite 95 ORDER BY binaries.version DESC 96 ) AS version_rank_all 97 FROM 98 binaries 99 INNER JOIN source ON source.id = binaries.source 100 INNER JOIN bin_associations ON 101 bin_associations.bin = binaries.id 102 AND bin_associations.suite = ANY(:suite_ids) 103 INNER JOIN architecture ON architecture.id = binaries.architecture 104 ) AS source_rank 105 WHERE 106 -- we only want to retain the newest of each 107 CASE 108 WHEN arch != 'all' AND arch_first != 'all' THEN version_rank_any = 1 109 ELSE version_rank_all = 1 110 END 111 ), 112 -- Figure out which source we should remove 113 -- A binary forces the corresponding source to remain 114 dominate_source AS ( 115 SELECT 116 source.source AS source_package, 117 source.version AS source_version, 118 source.source AS package, 119 source.version, 120 'source'::text AS arch, 121 suite.suite_name AS suite, 122 src_associations.id AS assoc_id 123 FROM 124 source 125 INNER JOIN src_associations ON 126 src_associations.source = source.id 127 AND src_associations.suite = ANY(:suite_ids) 128 INNER join suite ON suite.id = src_associations.suite 129 LEFT JOIN remain_binaries ON 130 remain_binaries.source_id = source.id 131 AND remain_binaries.suite_id = src_associations.suite 132 LEFT JOIN remain_source ON 133 remain_source.source_id = source.id 134 AND remain_source.suite_id = src_associations.suite 135 WHERE 136 remain_binaries.source_id IS NULL 137 AND remain_source.source_id IS NULL 138 ), 139 -- Figure out which arch-any binaries we should remove 140 dominate_binaries AS ( 141 SELECT 142 source.source AS source_package, 143 source.version AS source_version, 144 binaries.package AS package, 145 binaries.version, 146 architecture.arch_string AS arch, 147 suite.suite_name AS suite, 148 bin_associations.id AS assoc_id 149 FROM 150 binaries 151 INNER JOIN source ON source.id = binaries.source 152 INNER JOIN bin_associations ON 153 bin_associations.bin = binaries.id 154 AND bin_associations.suite = ANY(:suite_ids) 155 INNER JOIN architecture ON architecture.id = binaries.architecture 156 INNER join suite ON suite.id = bin_associations.suite 157 LEFT JOIN remain_binaries ON 158 remain_binaries.id = binaries.id 159 AND remain_binaries.arch_id = binaries.architecture 160 AND remain_binaries.suite_id = bin_associations.suite 161 WHERE 162 remain_binaries.source_id IS NULL 163 AND binaries.architecture != (SELECT id from architecture WHERE arch_string = 'all') 164 ), 165 -- Figure out which arch-all binaries we should remove 166 -- A arch-any binary forces the related arch-all binaries to remain 167 dominate_binaries_all AS ( 168 SELECT 169 source.source AS source_package, 170 source.version AS source_version, 171 binaries.package AS package, 172 binaries.version, 173 architecture.arch_string AS arch, 174 suite.suite_name AS suite, 175 bin_associations.id AS assoc_id 176 FROM 177 binaries 178 INNER JOIN source ON source.id = binaries.source 179 INNER JOIN bin_associations ON 180 bin_associations.bin = binaries.id 181 AND bin_associations.suite = ANY(:suite_ids) 182 INNER JOIN architecture ON architecture.id = binaries.architecture 183 INNER join suite ON suite.id = bin_associations.suite 184 LEFT JOIN remain_binaries ON 185 remain_binaries.id = binaries.id 186 AND remain_binaries.arch_id = binaries.architecture 187 AND remain_binaries.suite_id = bin_associations.suite 188 LEFT JOIN remain_binaries AS remain_binaries_any ON 189 remain_binaries_any.source_id = source.id 190 AND remain_binaries_any.suite_id = bin_associations.suite 191 AND remain_binaries_any.arch_id != (SELECT id from architecture WHERE arch_string = 'all') 192 WHERE 193 remain_binaries.source_id IS NULL 194 AND remain_binaries_any.source_id IS NULL 195 AND binaries.architecture = (SELECT id from architecture WHERE arch_string = 'all') 196 ) 197 SELECT 198 * 199 FROM 200 dominate_source 201 UNION SELECT 202 * 203 FROM 204 dominate_binaries 205 UNION SELECT 206 * 207 FROM 208 dominate_binaries_all 209 ORDER BY 210 source_package, source_version, package, version, arch, suite 211 """ 212 ).params( 213 suite_ids=[s.suite_id for s in suites], 214 ) 215 )
216 217
218 -def delete_associations_table(table, ids, session):
219 result = session.execute( 220 text( 221 """ 222 DELETE 223 FROM {} 224 WHERE id = ANY(:assoc_ids) 225 """.format( 226 table 227 ) 228 ).params( 229 assoc_ids=list(ids), 230 ) 231 ) 232 233 assert result.rowcount == len( 234 ids 235 ), "Rows deleted are not equal to deletion requests"
236 237
238 -def delete_associations(assocs, session):
239 ids_bin = set() 240 ids_src = set() 241 242 for e in assocs: 243 Logger.log(["newer", e.package, e.version, e.suite, e.arch, e.assoc_id]) 244 245 if e.arch == "source": 246 ids_src.add(e.assoc_id) 247 else: 248 ids_bin.add(e.assoc_id) 249 250 delete_associations_table("bin_associations", ids_bin, session) 251 delete_associations_table("src_associations", ids_src, session)
252 253
254 -def usage():
255 print( 256 """Usage: dak dominate [OPTIONS] 257 Remove obsolete source and binary associations from suites. 258 259 -s, --suite=SUITE act on this suite 260 -h, --help show this help and exit 261 -n, --no-action don't commit changes 262 -f, --force also clean up untouchable suites 263 264 SUITE can be comma (or space) separated list, e.g. 265 --suite=testing,unstable""" 266 ) 267 sys.exit()
268 269
270 -def main():
271 global Options, Logger 272 cnf = Config() 273 Arguments = [ 274 ("h", "help", "Obsolete::Options::Help"), 275 ("s", "suite", "Obsolete::Options::Suite", "HasArg"), 276 ("n", "no-action", "Obsolete::Options::No-Action"), 277 ("f", "force", "Obsolete::Options::Force"), 278 ] 279 cnf["Obsolete::Options::Help"] = "" 280 cnf["Obsolete::Options::No-Action"] = "" 281 cnf["Obsolete::Options::Force"] = "" 282 apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) 283 Options = cnf.subtree("Obsolete::Options") 284 if Options["Help"]: 285 usage() 286 287 if not Options["No-Action"]: 288 Logger = daklog.Logger("dominate") 289 session = DBConn().session() 290 291 suites_query = ( 292 session.query(Suite) 293 .order_by(Suite.suite_name) 294 .filter(~exists().where(Suite.suite_id == PolicyQueue.suite_id)) 295 ) 296 if "Suite" in Options: 297 suites_query = suites_query.filter( 298 Suite.suite_name.in_(utils.split_args(Options["Suite"])) 299 ) 300 if not Options["Force"]: 301 suites_query = suites_query.filter_by(untouchable=False) 302 suites = suites_query.all() 303 304 assocs = list(retrieve_associations(suites, session)) 305 306 if Options["No-Action"]: 307 headers = ( 308 "source package", 309 "source version", 310 "package", 311 "version", 312 "arch", 313 "suite", 314 "id", 315 ) 316 print((tabulate(assocs, headers, tablefmt="orgtbl"))) 317 session.rollback() 318 319 else: 320 delete_associations(assocs, session) 321 session.commit() 322 323 if Logger: 324 Logger.close()
325 326 327 if __name__ == "__main__": 328 main() 329