X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=dak%2Fcontrol_suite.py;h=3ba5acdced15ae8f5bc731f00ce754d86238d15e;hb=d092db5a64fc5ee4143493a7f2bbb327077e08a3;hp=1d5eb7accc227d6dcfe34de3287686a987b48b1f;hpb=0dada7c5846e0ae676bbe0b81c1065fe75ca9b86;p=dak.git diff --git a/dak/control_suite.py b/dak/control_suite.py index 1d5eb7ac..3ba5acdc 100755 --- a/dak/control_suite.py +++ b/dak/control_suite.py @@ -43,11 +43,13 @@ import sys import apt_pkg +import os from daklib.config import Config from daklib.dbconn import * from daklib import daklog from daklib import utils +from daklib.queue import get_suite_version_by_package, get_suite_version_by_source ####################################################################################### @@ -63,7 +65,8 @@ Display or alter the contents of a suite using FILE(s), or stdin. -h, --help show this help and exit -l, --list=SUITE list the contents of SUITE -r, --remove=SUITE remove from SUITE - -s, --set=SUITE set SUITE""" + -s, --set=SUITE set SUITE + -b, --britney generate changelog entry for britney runs""" sys.exit(exit_code) @@ -93,7 +96,115 @@ def get_id(package, version, architecture, session): ####################################################################################### -def set_suite(file, suite, session): +def britney_changelog(packages, suite, session): + + old = {} + current = {} + Cnf = utils.get_conf() + + try: + q = session.execute("SELECT changelog FROM suite WHERE id = :suiteid", \ + {'suiteid': suite.suite_id}) + brit_file = q.fetchone()[0] + except: + brit_file = None + + if brit_file: + brit_file = os.path.join(Cnf['Dir::Root'], brit_file) + else: + return + + q = session.execute("""SELECT s.source, s.version, sa.id + FROM source s, src_associations sa + WHERE sa.suite = :suiteid + AND sa.source = s.id""", {'suiteid': suite.suite_id}) + + for p in q.fetchall(): + current[p[0]] = p[1] + for p in packages.keys(): + p = p.split() + if p[2] == "source": + old[p[0]] = p[1] + + new = {} + for p in current.keys(): + if p in old.keys(): + if apt_pkg.VersionCompare(current[p], old[p]) > 0: + new[p] = [current[p], old[p]] + else: + new[p] = [current[p], 0] + + query = "SELECT source, changelog FROM changelogs WHERE" + for p in new.keys(): + query += " source = '%s' AND version > '%s' AND version <= '%s'" \ + % (p, new[p][1], new[p][0]) + query += " AND architecture LIKE '%source%' AND distribution in \ + ('unstable', 'experimental', 'testing-proposed-updates') OR" + query += " False ORDER BY source, version DESC" + q = session.execute(query) + + pu = None + brit = utils.open_file(brit_file, 'w') + + for u in q: + if pu and pu != u[0]: + brit.write("\n") + brit.write("%s\n" % u[1]) + pu = u[0] + if q.rowcount: brit.write("\n\n\n") + + for p in list(set(old.keys()).difference(current.keys())): + brit.write("REMOVED: %s %s\n" % (p, old[p])) + + brit.flush() + brit.close() + +####################################################################################### + +def version_checks(package, architecture, target_suite, new_version, session, force = False): + if architecture == "source": + suite_version_list = get_suite_version_by_source(package, session) + else: + suite_version_list = get_suite_version_by_package(package, architecture, session) + + must_be_newer_than = [ vc.reference.suite_name for vc in get_version_checks(target_suite, "MustBeNewerThan") ] + must_be_older_than = [ vc.reference.suite_name for vc in get_version_checks(target_suite, "MustBeOlderThan") ] + + # Must be newer than an existing version in target_suite + if target_suite not in must_be_newer_than: + must_be_newer_than.append(target_suite) + + violations = False + + for suite, version in suite_version_list: + cmp = apt_pkg.VersionCompare(new_version, version) + if suite in must_be_newer_than and cmp < 1: + utils.warn("%s (%s): version check violated: %s targeted at %s is *not* newer than %s in %s" % (package, architecture, new_version, target_suite, version, suite)) + violations = True + if suite in must_be_older_than and cmp > 1: + utils.warn("%s (%s): version check violated: %s targeted at %s is *not* older than %s in %s" % (package, architecture, new_version, target_suite, version, suite)) + violations = True + + if violations: + if force: + utils.warn("Continuing anyway (forced)...") + else: + utils.fubar("Aborting. Version checks violated and not forced.") + +####################################################################################### + +def cmp_package_version(a, b): + """ + comparison function for tuples of the form (package-name, version ...) + """ + cmp_package = cmp(a[0], b[0]) + if cmp_package != 0: + return cmp_package + return apt_pkg.VersionCompare(a[1], b[1]) + +####################################################################################### + +def set_suite(file, suite, session, britney=False, force=False): suite_id = suite.suite_id lines = file.readlines() @@ -127,21 +238,11 @@ def set_suite(file, suite, session): key = " ".join(split_line) desired[key] = "" - # Check to see which packages need removed and remove them - for key in current.keys(): - if not desired.has_key(key): - (package, version, architecture) = key.split() - pkid = current[key] - if architecture == "source": - session.execute("""DELETE FROM src_associations WHERE id = :pkid""", {'pkid': pkid}) - else: - session.execute("""DELETE FROM bin_associations WHERE id = :pkid""", {'pkid': pkid}) - Logger.log(["removed", key, pkid]) - # Check to see which packages need added and add them - for key in desired.keys(): + for key in sorted(desired.keys(), cmp=cmp_package_version): if not current.has_key(key): (package, version, architecture) = key.split() + version_checks(package, architecture, suite.suite_name, version, session, force) pkid = get_id (package, version, architecture, session) if not pkid: continue @@ -153,32 +254,52 @@ def set_suite(file, suite, session): VALUES (:suiteid, :pkid)""", {'suiteid': suite_id, 'pkid': pkid}) Logger.log(["added", key, pkid]) + # Check to see which packages need removed and remove them + for key in current.keys(): + if not desired.has_key(key): + (package, version, architecture) = key.split() + pkid = current[key] + if architecture == "source": + session.execute("""DELETE FROM src_associations WHERE id = :pkid""", {'pkid': pkid}) + else: + session.execute("""DELETE FROM bin_associations WHERE id = :pkid""", {'pkid': pkid}) + Logger.log(["removed", key, pkid]) + session.commit() + if britney: + britney_changelog(current, suite, session) + ####################################################################################### -def process_file(file, suite, action, session): +def process_file(file, suite, action, session, britney=False, force=False): if action == "set": - set_suite(file, suite, session) + set_suite(file, suite, session, britney, force) return suite_id = suite.suite_id - lines = file.readlines() + request = [] # Our session is already in a transaction - for line in lines: + for line in file: split_line = line.strip().split() if len(split_line) != 3: utils.warn("'%s' does not break into 'package version architecture'." % (line[:-1])) continue + request.append(split_line) - (package, version, architecture) = split_line + request.sort(cmp=cmp_package_version) + for package, version, architecture in request: pkid = get_id(package, version, architecture, session) if not pkid: continue + # Do version checks when adding packages + if action == "add": + version_checks(package, architecture, suite.suite_name, version, session, force) + if architecture == "source": # Find the existing association ID, if any q = session.execute("""SELECT id FROM src_associations @@ -223,7 +344,7 @@ def process_file(file, suite, action, session): continue else: session.execute("""INSERT INTO bin_associations (suite, bin) - VALUES (%s, %s)""", + VALUES (:suiteid, :pkid)""", {'suiteid': suite_id, 'pkid': pkid}) elif action == "remove": if association_id == None: @@ -262,18 +383,20 @@ def main (): cnf = Config() Arguments = [('a',"add","Control-Suite::Options::Add", "HasArg"), + ('b',"britney","Control-Suite::Options::Britney"), + ('f','force','Control-Suite::Options::Force'), ('h',"help","Control-Suite::Options::Help"), ('l',"list","Control-Suite::Options::List","HasArg"), ('r',"remove", "Control-Suite::Options::Remove", "HasArg"), ('s',"set", "Control-Suite::Options::Set", "HasArg")] - for i in ["add", "help", "list", "remove", "set", "version" ]: + for i in ["add", "britney", "help", "list", "remove", "set", "version" ]: if not cnf.has_key("Control-Suite::Options::%s" % (i)): cnf["Control-Suite::Options::%s" % (i)] = "" try: file_list = apt_pkg.ParseCommandLine(cnf.Cnf, Arguments, sys.argv); - except SystemError, e: + except SystemError as e: print "%s\n" % e usage(1) Options = cnf.SubTree("Control-Suite::Options") @@ -283,6 +406,8 @@ def main (): session = DBConn().session() + force = Options.has_key("Force") and Options["Force"] + action = None for i in ("add", "list", "remove", "set"): @@ -296,24 +421,30 @@ def main (): utils.fubar("Can only perform one action at a time.") action = i + # Safety/Sanity check + if action == "set" and (not suite.allowcsset): + if force: + utils.warn("Would not normally allow setting suite %s (allowsetcs is FALSE), but --force used" % (suite_name)) + else: + utils.fubar("Will not reset suite %s due to its database configuration (allowsetcs is FALSE)" % (suite_name)) + # Need an action... if action == None: utils.fubar("No action specified.") - # Safety/Sanity check - # XXX: This should be stored in the database - if action == "set" and suite_name not in ["testing", "etch-m68k"]: - utils.fubar("Will not reset suite %s" % (suite_name)) + britney = False + if action == "set" and cnf["Control-Suite::Options::Britney"]: + britney = True if action == "list": get_list(suite, session) else: - Logger = daklog.Logger(cnf.Cnf, "control-suite") + Logger = daklog.Logger("control-suite") if file_list: for f in file_list: - process_file(utils.open_file(f), suite, action, session) + process_file(utils.open_file(f), suite, action, session, britney, force) else: - process_file(sys.stdin, suite, action, session) + process_file(sys.stdin, suite, action, session, britney, force) Logger.close() #######################################################################################