merge trunk

bzr-import-20160707
Colin Watson 11 years ago
commit 3b0a0e665a

@ -4,7 +4,7 @@
# Copyright (C) 2001-2008 Anthony Towns <ajt@debian.org> # Copyright (C) 2001-2008 Anthony Towns <ajt@debian.org>
# Andreas Barth <aba@debian.org> # Andreas Barth <aba@debian.org>
# Fabio Tranchitella <kobold@debian.org> # Fabio Tranchitella <kobold@debian.org>
# Copyright (C) 2010-2012 Adam D. Barratt <adsb@debian.org> # Copyright (C) 2010-2013 Adam D. Barratt <adsb@debian.org>
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -24,7 +24,7 @@ This is the Debian testing updater script, also known as "Britney".
Packages are usually installed into the `testing' distribution after Packages are usually installed into the `testing' distribution after
they have undergone some degree of testing in unstable. The goal of they have undergone some degree of testing in unstable. The goal of
this software is to do this task in a smart way, allowing testing this software is to do this task in a smart way, allowing testing
to be always fully installable and close to being a release candidate. to always be fully installable and close to being a release candidate.
Britney's source code is split between two different but related tasks: Britney's source code is split between two different but related tasks:
the first one is the generation of the update excuses, while the the first one is the generation of the update excuses, while the
@ -95,9 +95,9 @@ does for the generation of the update excuses.
is ignored: it will be removed and not updated. is ignored: it will be removed and not updated.
2. For every binary package built from the new source, it checks 2. For every binary package built from the new source, it checks
for unsatisfied dependencies, new binary package and updated for unsatisfied dependencies, new binary packages and updated
binary package (binNMU) excluding the architecture-independent binary packages (binNMU), excluding the architecture-independent
ones and the packages not built from the same source. ones, and packages not built from the same source.
3. For every binary package built from the old source, it checks 3. For every binary package built from the old source, it checks
if it is still built from the new source; if this is not true if it is still built from the new source; if this is not true
@ -146,7 +146,7 @@ does for the generation of the update excuses.
If this is not true, then these are called `out-of-date' If this is not true, then these are called `out-of-date'
architectures and the package is ignored. architectures and the package is ignored.
9. The source package must have at least a binary package, otherwise 9. The source package must have at least one binary package, otherwise
it is ignored. it is ignored.
10. If the suite is unstable, the new source package must have no 10. If the suite is unstable, the new source package must have no
@ -190,6 +190,7 @@ import urllib
import apt_pkg import apt_pkg
from functools import reduce, partial from functools import reduce, partial
from itertools import chain, ifilter
from operator import attrgetter from operator import attrgetter
if __name__ == '__main__': if __name__ == '__main__':
@ -208,16 +209,16 @@ if __name__ == '__main__':
sys.path.insert(0, idir) sys.path.insert(0, idir)
from excuse import Excuse from excuse import Excuse
from migrationitem import MigrationItem, HintItem from migrationitem import MigrationItem
from hints import HintCollection from hints import HintCollection
from britney import buildSystem from britney import buildSystem
from britney_util import (old_libraries_format, same_source, undo_changes, from britney_util import (old_libraries_format, same_source, undo_changes,
register_reverses, compute_reverse_tree, register_reverses, compute_reverse_tree,
read_nuninst, write_nuninst, write_heidi, read_nuninst, write_nuninst, write_heidi,
eval_uninst, newly_uninst) eval_uninst, newly_uninst, make_migrationitem)
from consts import (VERSION, SECTION, BINARIES, MAINTAINER, FAKESRC, from consts import (VERSION, SECTION, BINARIES, MAINTAINER, FAKESRC,
SOURCE, SOURCEVER, ARCHITECTURE, MULTIARCH, DEPENDS, CONFLICTS, SOURCE, SOURCEVER, ARCHITECTURE, DEPENDS, CONFLICTS,
PROVIDES, RDEPENDS, RCONFLICTS) PROVIDES, RDEPENDS, RCONFLICTS, MULTIARCH)
from autopkgtest import AutoPackageTest from autopkgtest import AutoPackageTest
__author__ = 'Fabio Tranchitella and the Debian Release Team' __author__ = 'Fabio Tranchitella and the Debian Release Team'
@ -405,7 +406,7 @@ class Britney(object):
output. The type parameter controls the urgency of the message, and output. The type parameter controls the urgency of the message, and
can be equal to `I' for `Information', `W' for `Warning' and `E' for can be equal to `I' for `Information', `W' for `Warning' and `E' for
`Error'. Warnings and errors are always printed, and information is `Error'. Warnings and errors are always printed, and information is
printed only if the verbose logging is enabled. printed only if verbose logging is enabled.
""" """
if self.options.verbose or type in ("E", "W"): if self.options.verbose or type in ("E", "W"):
print "%s: [%s] - %s" % (type, time.asctime(), msg) print "%s: [%s] - %s" % (type, time.asctime(), msg)
@ -471,7 +472,7 @@ class Britney(object):
within the directory specified as `basedir' parameter, replacing within the directory specified as `basedir' parameter, replacing
${arch} with the value of the arch parameter. Considering the ${arch} with the value of the arch parameter. Considering the
large amount of memory needed, not all the fields are loaded large amount of memory needed, not all the fields are loaded
in memory. The available fields are Version, Source, Pre-Depends, in memory. The available fields are Version, Source, Multi-Arch,
Depends, Conflicts, Provides and Architecture. Depends, Conflicts, Provides and Architecture.
After reading the packages, reverse dependencies are computed After reading the packages, reverse dependencies are computed
@ -533,7 +534,6 @@ class Britney(object):
version, version,
get_field('Architecture'), get_field('Architecture'),
get_field('Multi-Arch'), get_field('Multi-Arch'),
None, # Pre-depends - leave as None for the C-code
deps, deps,
', '.join(final_conflicts_list) or None, ', '.join(final_conflicts_list) or None,
get_field('Provides'), get_field('Provides'),
@ -701,7 +701,7 @@ class Britney(object):
object attribute `bugs'. object attribute `bugs'.
""" """
# loop on all the package names from testing and unstable bug summaries # loop on all the package names from testing and unstable bug summaries
for pkg in set(self.bugs['testing'].keys() + self.bugs['unstable'].keys()): for pkg in set(chain(self.bugs['testing'], self.bugs['unstable'])):
# make sure that the key is present in both dictionaries # make sure that the key is present in both dictionaries
if pkg not in self.bugs['testing']: if pkg not in self.bugs['testing']:
@ -729,7 +729,7 @@ class Britney(object):
<package-name> <version> <date-of-upload> <package-name> <version> <date-of-upload>
The dates are expressed as days starting from the 1970-01-01. The dates are expressed as the number of days from 1970-01-01.
The method returns a dictionary where the key is the binary package The method returns a dictionary where the key is the binary package
name and the value is a tuple with two items, the version and the date. name and the value is a tuple with two items, the version and the date.
@ -760,7 +760,7 @@ class Britney(object):
filename = os.path.join(basedir, "Dates") filename = os.path.join(basedir, "Dates")
self.__log("Writing upload data to %s" % filename) self.__log("Writing upload data to %s" % filename)
f = open(filename, 'w') f = open(filename, 'w')
for pkg in sorted(dates.keys()): for pkg in sorted(dates):
f.write("%s %s %d\n" % ((pkg,) + dates[pkg])) f.write("%s %s %d\n" % ((pkg,) + dates[pkg]))
f.close() f.close()
@ -972,7 +972,6 @@ class Britney(object):
f.write(output + "\n") f.write(output + "\n")
f.close() f.close()
# Utility methods for package analysis # Utility methods for package analysis
# ------------------------------------ # ------------------------------------
@ -1005,7 +1004,7 @@ class Britney(object):
package = binaries[0][name] package = binaries[0][name]
# check the versioned dependency and architecture qualifier # check the versioned dependency and architecture qualifier
# (if present) # (if present)
if op == '' and version == '' or apt_pkg.check_dep(package[VERSION], op, version): if (op == '' and version == '') or apt_pkg.check_dep(package[VERSION], op, version):
if archqual is None or (archqual == 'any' and package[MULTIARCH] == 'allowed'): if archqual is None or (archqual == 'any' and package[MULTIARCH] == 'allowed'):
packages.append(name) packages.append(name)
@ -1013,10 +1012,10 @@ class Britney(object):
for prov in binaries[1].get(name, []): for prov in binaries[1].get(name, []):
if prov not in binaries[0]: continue if prov not in binaries[0]: continue
package = binaries[0][prov] package = binaries[0][prov]
# A provides only satisfies an unversioned dependency # A provides only satisfies:
# (per Policy Manual §7.5) # - an unversioned dependency (per Policy Manual §7.5)
# A provides only satisfies a dependency without an # - a dependency without an architecture qualifier
# architecture qualifier (per analysis of apt code) # (per analysis of apt code)
if op == '' and version == '' and archqual is None: if op == '' and version == '' and archqual is None:
packages.append(prov) packages.append(prov)
@ -1034,7 +1033,7 @@ class Britney(object):
# retrieve the binary package from the specified suite and arch # retrieve the binary package from the specified suite and arch
binary_u = self.binaries[suite][arch][0][pkg] binary_u = self.binaries[suite][arch][0][pkg]
# local copies for better performances # local copies for better performance
parse_depends = apt_pkg.parse_depends parse_depends = apt_pkg.parse_depends
get_dependency_solvers = self.get_dependency_solvers get_dependency_solvers = self.get_dependency_solvers
@ -1043,7 +1042,7 @@ class Britney(object):
return return
deps = binary_u[DEPENDS] deps = binary_u[DEPENDS]
# for every block of dependency (which is formed as conjunction of disconjunction) # for every dependency block (formed as conjunction of disjunction)
for block, block_txt in zip(parse_depends(deps, False), deps.split(',')): for block, block_txt in zip(parse_depends(deps, False), deps.split(',')):
# if the block is satisfied in testing, then skip the block # if the block is satisfied in testing, then skip the block
solved, packages = get_dependency_solvers(block, arch, 'testing') solved, packages = get_dependency_solvers(block, arch, 'testing')
@ -1152,7 +1151,7 @@ class Britney(object):
anyworthdoing = False anyworthdoing = False
# for every binary package produced by this source in unstable for this architecture # for every binary package produced by this source in unstable for this architecture
for pkg in sorted(filter(lambda x: x.endswith("/" + arch), source_u[BINARIES]), key=lambda x: x.split("/")[0]): for pkg in sorted(ifilter(lambda x: x.endswith("/" + arch), source_u[BINARIES]), key=lambda x: x.split("/")[0]):
pkg_name = pkg.split("/")[0] pkg_name = pkg.split("/")[0]
# retrieve the testing (if present) and unstable corresponding binary packages # retrieve the testing (if present) and unstable corresponding binary packages
@ -1221,7 +1220,7 @@ class Britney(object):
arch, arch,
suite) suite)
for pkg in sorted([x.split("/")[0] for x in source_data[BINARIES] if x.endswith("/"+arch)]): for pkg in sorted(x.split("/")[0] for x in source_data[BINARIES] if x.endswith("/"+arch)):
# if the package is architecture-independent, then ignore it # if the package is architecture-independent, then ignore it
tpkg_data = self.binaries['testing'][arch][0][pkg] tpkg_data = self.binaries['testing'][arch][0][pkg]
if tpkg_data[ARCHITECTURE] == 'all': if tpkg_data[ARCHITECTURE] == 'all':
@ -1234,7 +1233,7 @@ class Britney(object):
# as otherwise the updated source will already cause the binary packages # as otherwise the updated source will already cause the binary packages
# to be updated # to be updated
if ssrc: if ssrc:
# Special-case, if the binary is a candidate for smooth update, we do not consider # Special-case, if the binary is a candidate for a smooth update, we do not consider
# it "interesting" on its own. This case happens quite often with smooth updatable # it "interesting" on its own. This case happens quite often with smooth updatable
# packages, where the old binary "survives" a full run because it still has # packages, where the old binary "survives" a full run because it still has
# reverse dependencies. # reverse dependencies.
@ -1430,7 +1429,7 @@ class Britney(object):
for arch in self.options.architectures: for arch in self.options.architectures:
oodbins = {} oodbins = {}
# for every binary package produced by this source in the suite for this architecture # for every binary package produced by this source in the suite for this architecture
for pkg in sorted([x.split("/")[0] for x in self.sources[suite][src][BINARIES] if x.endswith("/"+arch)]): for pkg in sorted(x.split("/")[0] for x in self.sources[suite][src][BINARIES] if x.endswith("/"+arch)):
if pkg not in pkgs: pkgs[pkg] = [] if pkg not in pkgs: pkgs[pkg] = []
pkgs[pkg].append(arch) pkgs[pkg].append(arch)
@ -1487,9 +1486,9 @@ class Britney(object):
# if the suite is unstable, then we have to check the release-critical bug lists before # if the suite is unstable, then we have to check the release-critical bug lists before
# updating testing; if the unstable package has RC bugs that do not apply to the testing # updating testing; if the unstable package has RC bugs that do not apply to the testing
# one, the check fails and we set update_candidate to False to block the update # one, the check fails and we set update_candidate to False to block the update
if suite == 'unstable': if suite == 'unstable':
for pkg in pkgs.keys(): for pkg in pkgs:
bugs_t = [] bugs_t = []
bugs_u = [] bugs_u = []
if pkg in self.bugs['testing']: if pkg in self.bugs['testing']:
@ -1789,7 +1788,7 @@ class Britney(object):
self.invalidate_excuses(upgrade_me, unconsidered) self.invalidate_excuses(upgrade_me, unconsidered)
# sort the list of candidates # sort the list of candidates
self.upgrade_me = sorted([ MigrationItem(x) for x in upgrade_me ]) self.upgrade_me = sorted( make_migrationitem(x, self.sources) for x in upgrade_me )
# write excuses to the output file # write excuses to the output file
if not self.options.dry_run: if not self.options.dry_run:
@ -2149,7 +2148,7 @@ class Britney(object):
to_check = [] to_check = []
# broken packages (first round) # broken packages (first round)
for p in [x[0] for x in affected if x[1] == arch]: for p in (x[0] for x in affected if x[1] == arch):
if p not in binaries[arch][0]: if p not in binaries[arch][0]:
continue continue
nuninst_arch = None nuninst_arch = None
@ -2210,7 +2209,7 @@ class Britney(object):
if lundo is None: if lundo is None:
lundo = [] lundo = []
if not hint: if not hint:
self.output_write("recur: [%s] %s %d/%d\n" % ("", ",".join([x.uvname for x in selected]), len(packages), len(extra))) self.output_write("recur: [%s] %s %d/%d\n" % ("", ",".join(x.uvname for x in selected), len(packages), len(extra)))
# loop on the packages (or better, actions) # loop on the packages (or better, actions)
while packages: while packages:
@ -2228,14 +2227,14 @@ class Britney(object):
defer = False defer = False
for p in dependencies.get(pkg, []): for p in dependencies.get(pkg, []):
if p in skipped: if p in skipped:
deferred.append(pkg) deferred.append(make_migrationitem(pkg, self.sources))
skipped.append(pkg) skipped.append(make_migrationitem(pkg, self.sources))
defer = True defer = True
break break
if defer: continue if defer: continue
if not hint: if not hint:
self.output_write("trying: %s\n" % (pkg)) self.output_write("trying: %s\n" % (pkg.uvname))
better = True better = True
nuninst = {} nuninst = {}
@ -2254,10 +2253,10 @@ class Britney(object):
skip_archall = True skip_archall = True
else: skip_archall = False else: skip_archall = False
nuninst[arch] = set([x for x in nuninst_comp[arch] if x in binaries[arch][0]]) nuninst[arch] = set(x for x in nuninst_comp[arch] if x in binaries[arch][0])
nuninst[arch + "+all"] = set([x for x in nuninst_comp[arch + "+all"] if x in binaries[arch][0]]) nuninst[arch + "+all"] = set(x for x in nuninst_comp[arch + "+all"] if x in binaries[arch][0])
check_packages(arch, affected, skip_archall, nuninst, pkg) check_packages(arch, affected, skip_archall, nuninst, pkg.uvname)
# if we are processing hints, go ahead # if we are processing hints, go ahead
if hint: if hint:
@ -2280,24 +2279,24 @@ class Britney(object):
selected.append(pkg) selected.append(pkg)
packages.extend(extra) packages.extend(extra)
extra = [] extra = []
self.output_write("accepted: %s\n" % (pkg)) self.output_write("accepted: %s\n" % (pkg.uvname))
self.output_write(" ori: %s\n" % (self.eval_nuninst(self.nuninst_orig))) self.output_write(" ori: %s\n" % (self.eval_nuninst(self.nuninst_orig)))
self.output_write(" pre: %s\n" % (self.eval_nuninst(nuninst_comp))) self.output_write(" pre: %s\n" % (self.eval_nuninst(nuninst_comp)))
self.output_write(" now: %s\n" % (self.eval_nuninst(nuninst, nuninst_comp))) self.output_write(" now: %s\n" % (self.eval_nuninst(nuninst, nuninst_comp)))
if len(selected) <= 20: if len(selected) <= 20:
self.output_write(" all: %s\n" % (" ".join([ x.uvname for x in selected ]))) self.output_write(" all: %s\n" % (" ".join( x.uvname for x in selected )))
else: else:
self.output_write(" most: (%d) .. %s\n" % (len(selected), " ".join([x.uvname for x in selected][-20:]))) self.output_write(" most: (%d) .. %s\n" % (len(selected), " ".join(x.uvname for x in selected[-20:])))
for k in nuninst: for k in nuninst:
nuninst_comp[k] = nuninst[k] nuninst_comp[k] = nuninst[k]
else: else:
self.output_write("skipped: %s (%d <- %d)\n" % (pkg, len(extra), len(packages))) self.output_write("skipped: %s (%d <- %d)\n" % (pkg.uvname, len(extra), len(packages)))
self.output_write(" got: %s\n" % (self.eval_nuninst(nuninst, pkg.architecture != 'source' and nuninst_comp or None))) self.output_write(" got: %s\n" % (self.eval_nuninst(nuninst, pkg.architecture != 'source' and nuninst_comp or None)))
self.output_write(" * %s: %s\n" % (arch, ", ".join(sorted([b for b in nuninst[arch] if b not in nuninst_comp[arch]])))) self.output_write(" * %s: %s\n" % (arch, ", ".join(sorted(b for b in nuninst[arch] if b not in nuninst_comp[arch]))))
extra.append(pkg) extra.append(item)
if not mark_passed: if not mark_passed:
skipped.append(pkg) skipped.append(item)
single_undo = [(undo, item)] single_undo = [(undo, item)]
# (local-scope) binaries is actually self.binaries["testing"] so we cannot use it here. # (local-scope) binaries is actually self.binaries["testing"] so we cannot use it here.
undo_changes(single_undo, systems, sources, self.binaries) undo_changes(single_undo, systems, sources, self.binaries)
@ -2306,7 +2305,7 @@ class Britney(object):
if hint: if hint:
return (nuninst_comp, []) return (nuninst_comp, [])
self.output_write(" finish: [%s]\n" % ",".join([ x.uvname for x in selected ])) self.output_write(" finish: [%s]\n" % ",".join( x.uvname for x in selected ))
self.output_write("endloop: %s\n" % (self.eval_nuninst(self.nuninst_orig))) self.output_write("endloop: %s\n" % (self.eval_nuninst(self.nuninst_orig)))
self.output_write(" now: %s\n" % (self.eval_nuninst(nuninst_comp))) self.output_write(" now: %s\n" % (self.eval_nuninst(nuninst_comp)))
self.output_write(eval_uninst(self.options.architectures, self.output_write(eval_uninst(self.options.architectures,
@ -2343,7 +2342,7 @@ class Britney(object):
if init: if init:
if not force: if not force:
lundo = [] lundo = []
self.output_write("leading: %s\n" % (",".join([ x.uvname for x in init ]))) self.output_write("leading: %s\n" % (",".join( x.uvname for x in init )))
for x in init: for x in init:
if x not in upgrade_me: if x not in upgrade_me:
self.output_write("failed: %s\n" % (x.uvname)) self.output_write("failed: %s\n" % (x.uvname))
@ -2380,7 +2379,7 @@ class Britney(object):
# Result accepted either by force or by being better than the original result. # Result accepted either by force or by being better than the original result.
if recurse: if recurse:
self.output_write("Apparently successful\n") self.output_write("Apparently successful\n")
self.output_write("final: %s\n" % ",".join(sorted([ x.uvname for x in selected ]))) self.output_write("final: %s\n" % ",".join(sorted( x.uvname for x in selected )))
self.output_write("start: %s\n" % self.eval_nuninst(nuninst_start)) self.output_write("start: %s\n" % self.eval_nuninst(nuninst_start))
if not force: if not force:
self.output_write(" orig: %s\n" % self.eval_nuninst(self.nuninst_orig)) self.output_write(" orig: %s\n" % self.eval_nuninst(self.nuninst_orig))
@ -2450,7 +2449,7 @@ class Britney(object):
allpackages += self.upgrade_me allpackages += self.upgrade_me
for a in self.options.break_arches.split(): for a in self.options.break_arches.split():
backup = self.options.break_arches backup = self.options.break_arches
self.options.break_arches = " ".join([x for x in self.options.break_arches.split() if x != a]) self.options.break_arches = " ".join(x for x in self.options.break_arches.split() if x != a)
self.upgrade_me = archpackages[a] self.upgrade_me = archpackages[a]
self.output_write("info: broken arch run for %s\n" % (a)) self.output_write("info: broken arch run for %s\n" % (a))
self.do_all() self.do_all()
@ -2487,7 +2486,7 @@ class Britney(object):
for arch in binaries for arch in binaries
for binary in binaries[arch][0] for binary in binaries[arch][0]
) )
removals = [ HintItem("-%s/%s" % (source, sources[source][VERSION])) removals = [ MigrationItem("-%s/%s" % (source, sources[source][VERSION]))
for source in sources if source not in used for source in sources if source not in used
] ]
if len(removals) > 0: if len(removals) > 0:
@ -2501,7 +2500,7 @@ class Britney(object):
if len(removals) > 0: if len(removals) > 0:
self.output_write("Removing packages left in testing for smooth updates (%d):\n%s" % \ self.output_write("Removing packages left in testing for smooth updates (%d):\n%s" % \
(len(removals), old_libraries_format(removals))) (len(removals), old_libraries_format(removals)))
self.do_all(actions=[ MigrationItem(x) for x in removals ]) self.do_all(actions=removals)
removals = self.old_libraries() removals = self.old_libraries()
else: else:
removals = () removals = ()
@ -2603,7 +2602,7 @@ class Britney(object):
""" """
if isinstance(pkgvers[0], tuple) or isinstance(pkgvers[0], list): if isinstance(pkgvers[0], tuple) or isinstance(pkgvers[0], list):
_pkgvers = [ HintItem('%s/%s' % (p, v)) for (p,v) in pkgvers ] _pkgvers = [ MigrationItem('%s/%s' % (p, v)) for (p,v) in pkgvers ]
else: else:
_pkgvers = pkgvers _pkgvers = pkgvers
@ -2677,7 +2676,7 @@ class Britney(object):
self.dependencies[e.name] = e.deps self.dependencies[e.name] = e.deps
# replace the list of actions with the new one # replace the list of actions with the new one
self.upgrade_me = [ MigrationItem(x) for x in upgrade_me ] self.upgrade_me = [ make_migrationitem(x, self.sources) for x in upgrade_me ]
def auto_hinter(self): def auto_hinter(self):
"""Auto-generate "easy" hints. """Auto-generate "easy" hints.
@ -2698,7 +2697,7 @@ class Britney(object):
self.__log("> Processing hints from the auto hinter", type="I") self.__log("> Processing hints from the auto hinter", type="I")
# consider only excuses which are valid candidates # consider only excuses which are valid candidates
excuses = dict([(x.name, x) for x in self.excuses if x.name in [y.uvname for y in self.upgrade_me]]) excuses = dict((x.name, x) for x in self.excuses if x.name in [y.uvname for y in self.upgrade_me])
def find_related(e, hint, circular_first=False): def find_related(e, hint, circular_first=False):
if e not in excuses: if e not in excuses:
@ -2732,9 +2731,9 @@ class Britney(object):
looped = False looped = False
for item, ver in items: for item, ver in items:
# excuses which depend on "item" or are depended on by it # excuses which depend on "item" or are depended on by it
items.extend( [ (x, excuses[x].ver[1]) for x in excuses if \ items.extend( (x, excuses[x].ver[1]) for x in excuses if \
(item in excuses[x].deps or x in excuses[item].deps) \ (item in excuses[x].deps or x in excuses[item].deps) \
and (x, excuses[x].ver[1]) not in items ] ) and (x, excuses[x].ver[1]) not in items )
if not looped and len(items) > 1: if not looped and len(items) > 1:
mincands.append(items[:]) mincands.append(items[:])
looped = True looped = True
@ -2756,7 +2755,7 @@ class Britney(object):
to_skip.append(i) to_skip.append(i)
for i in range(len(l)): for i in range(len(l)):
if i not in to_skip: if i not in to_skip:
self.do_hint("easy", "autohinter", [ HintItem("%s/%s" % (x[0], x[1])) for x in l[i] ]) self.do_hint("easy", "autohinter", [ MigrationItem("%s/%s" % (x[0], x[1])) for x in l[i] ])
def old_libraries(self, same_source=same_source): def old_libraries(self, same_source=same_source):
"""Detect old libraries left in testing for smooth transitions """Detect old libraries left in testing for smooth transitions
@ -2777,7 +2776,7 @@ class Britney(object):
pkg = testing[arch][0][pkg_name] pkg = testing[arch][0][pkg_name]
if pkg_name not in unstable[arch][0] and \ if pkg_name not in unstable[arch][0] and \
not same_source(sources[pkg[SOURCE]][VERSION], pkg[SOURCEVER]): not same_source(sources[pkg[SOURCE]][VERSION], pkg[SOURCEVER]):
removals.append("-" + pkg_name + "/" + arch) removals.append(MigrationItem("-" + pkg_name + "/" + arch + "/" + pkg[SOURCEVER]))
return removals return removals
def nuninst_arch_report(self, nuninst, arch): def nuninst_arch_report(self, nuninst, arch):
@ -2789,7 +2788,7 @@ class Britney(object):
print '* %s' % (arch,) print '* %s' % (arch,)
for (src, ver), pkgs in sorted(all.items()): for (src, ver), pkgs in sorted(all.iteritems()):
print ' %s (%s): %s' % (src, ver, ' '.join(sorted(pkgs))) print ' %s (%s): %s' % (src, ver, ' '.join(sorted(pkgs)))
print print

@ -6,6 +6,9 @@
# Fabio Tranchitella <kobold@debian.org> # Fabio Tranchitella <kobold@debian.org>
# Copyright (C) 2010-2012 Adam D. Barratt <adsb@debian.org> # Copyright (C) 2010-2012 Adam D. Barratt <adsb@debian.org>
# Copyright (C) 2012 Niels Thykier <niels@thykier.net> # Copyright (C) 2012 Niels Thykier <niels@thykier.net>
#
# New portions
# Copyright (C) 2013 Adam D. Barratt <adsb@debian.org>
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -23,7 +26,7 @@ from functools import partial
from itertools import chain, ifilter, ifilterfalse, izip, repeat from itertools import chain, ifilter, ifilterfalse, izip, repeat
import re import re
import time import time
from migrationitem import MigrationItem, UnversionnedMigrationItem
from consts import (VERSION, BINARIES, PROVIDES, DEPENDS, CONFLICTS, from consts import (VERSION, BINARIES, PROVIDES, DEPENDS, CONFLICTS,
RDEPENDS, RCONFLICTS, ARCHITECTURE, SECTION) RDEPENDS, RCONFLICTS, ARCHITECTURE, SECTION)
@ -154,12 +157,11 @@ def old_libraries_format(libs):
"""Format old libraries in a smart table""" """Format old libraries in a smart table"""
libraries = {} libraries = {}
for i in libs: for i in libs:
pkg, arch = i.split("/") pkg = i.package
pkg = pkg[1:]
if pkg in libraries: if pkg in libraries:
libraries[pkg].append(arch) libraries[pkg].append(i.architecture)
else: else:
libraries[pkg] = [arch] libraries[pkg] = [i.architecture]
return "\n".join(" " + k + ": " + " ".join(libraries[k]) for k in libraries) + "\n" return "\n".join(" " + k + ": " + " ".join(libraries[k]) for k in libraries) + "\n"
@ -273,7 +275,8 @@ def write_nuninst(filename, nuninst):
# redundant. # redundant.
f.write("Built on: " + time.strftime("%Y.%m.%d %H:%M:%S %z", time.gmtime(time.time())) + "\n") f.write("Built on: " + time.strftime("%Y.%m.%d %H:%M:%S %z", time.gmtime(time.time())) + "\n")
f.write("Last update: " + time.strftime("%Y.%m.%d %H:%M:%S %z", time.gmtime(time.time())) + "\n\n") f.write("Last update: " + time.strftime("%Y.%m.%d %H:%M:%S %z", time.gmtime(time.time())) + "\n\n")
f.write("".join([k + ": " + " ".join(nuninst[k]) + "\n" for k in nuninst])) for k in nuninst:
f.write("%s: %s\n" % (k, " ".join(nuninst[k])))
def read_nuninst(filename, architectures): def read_nuninst(filename, architectures):
@ -360,3 +363,13 @@ def write_heidi(filename, sources_t, packages_t,
srcv = src[VERSION] srcv = src[VERSION]
srcsec = src[SECTION] or 'unknown' srcsec = src[SECTION] or 'unknown'
f.write('%s %s source %s\n' % (src_name, srcv, srcsec)) f.write('%s %s source %s\n' % (src_name, srcv, srcsec))
def make_migrationitem(package, sources, VERSION=VERSION):
"""Convert a textual package specification to a MigrationItem
sources is a list of source packages in each suite, used to determine
the version which should be used for the MigrationItem.
"""
item = UnversionnedMigrationItem(package)
return MigrationItem("%s/%s" % (item.uvname, sources[item.suite][item.package][VERSION]))

@ -30,11 +30,8 @@ SOURCE = 2
SOURCEVER = 3 SOURCEVER = 3
ARCHITECTURE = 4 ARCHITECTURE = 4
MULTIARCH = 5 MULTIARCH = 5
# PREDEPENDS = 6 - No longer used by the python code DEPENDS = 6
# - The C-code needs it for alignment reasons and still check it CONFLICTS = 7
# but ignore it if it is None (so keep it None). PROVIDES = 8
DEPENDS = 7 RDEPENDS = 9
CONFLICTS = 8 RCONFLICTS = 10
PROVIDES = 9
RDEPENDS = 10
RCONFLICTS = 11

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2011 Adam D. Barratt <adsb@debian.org> # Copyright (C) 2013 Adam D. Barratt <adsb@debian.org>
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -12,7 +12,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
from migrationitem import HintItem from migrationitem import MigrationItem
class HintCollection(object): class HintCollection(object):
def __init__(self): def __init__(self):
@ -36,6 +36,8 @@ class HintCollection(object):
self._hints.append(Hint(hint, user)) self._hints.append(Hint(hint, user))
class Hint(object): class Hint(object):
NO_VERSION = [ 'block', 'block-all', 'block-udeb' ]
def __init__(self, hint, user): def __init__(self, hint, user):
self._hint = hint self._hint = hint
self._user = user self._user = user
@ -57,7 +59,16 @@ class Hint(object):
if isinstance(self._packages, str): if isinstance(self._packages, str):
self._packages = self._packages.split(' ') self._packages = self._packages.split(' ')
self._packages = [HintItem(x) for x in self._packages] self._packages = [MigrationItem(x) for x in self._packages]
self.check()
def check(self):
for package in self.packages:
if self.type in self.__class__.NO_VERSION:
assert package.version is None, package
else:
assert package.version is not None, package
def set_active(self, active): def set_active(self, active):
self._active = active self._active = active
@ -66,7 +77,12 @@ class Hint(object):
return self._hint return self._hint
def __eq__(self, other): def __eq__(self, other):
return str(self) == str(other) if self.type != other.type:
return False
elif self.type == 'age-days' and self.days != other.days:
return False
else:
return frozenset(self.packages) == frozenset(other.packages)
@property @property
def type(self): def type(self):

@ -85,6 +85,7 @@ static PyObject *dpkgpackages_add_binary(dpkgpackages *self, PyObject *args) {
pkg->package = strdup(pkg_name); pkg->package = strdup(pkg_name);
pkg->priority = 0; pkg->priority = 0;
pkg->details = NULL; pkg->details = NULL;
pkg->depends[1] = NULL;
pkg->depends[2] = NULL; pkg->depends[2] = NULL;
pkg->depends[3] = NULL; pkg->depends[3] = NULL;
@ -118,12 +119,6 @@ static PyObject *dpkgpackages_add_binary(dpkgpackages *self, PyObject *args) {
pyString = PyList_GetItem(value, 7); pyString = PyList_GetItem(value, 7);
if (pyString == NULL) return NULL; if (pyString == NULL) return NULL;
if (pyString != Py_None) {
pkg->depends[1] = read_dep_andor(PyString_AsString(pyString));
} else pkg->depends[1] = NULL;
pyString = PyList_GetItem(value, 8);
if (pyString == NULL) return NULL;
if (pyString != Py_None) { if (pyString != Py_None) {
pkg->conflicts = read_dep_and(PyString_AsString(pyString)); pkg->conflicts = read_dep_and(PyString_AsString(pyString));
} else pkg->conflicts = NULL; } else pkg->conflicts = NULL;
@ -211,12 +206,11 @@ static PyObject *build_system(PyObject *self, PyObject *args) {
# SOURCEVER = 3 # SOURCEVER = 3
# ARCHITECTURE = 4 # ARCHITECTURE = 4
# MULTIARCH = 5 # MULTIARCH = 5
# PREDEPENDS = 6 # DEPENDS = 6
# DEPENDS = 7 # CONFLICTS = 7
# CONFLICTS = 8 # PROVIDES = 8
# PROVIDES = 9 # RDEPENDS = 9
# RDEPENDS = 10 # RCONFLICTS = 10
# RCONFLICTS = 11
*/ */
dpkg_packages *dpkg_pkgs = new_packages(arch); dpkg_packages *dpkg_pkgs = new_packages(arch);
@ -230,6 +224,7 @@ static PyObject *build_system(PyObject *self, PyObject *args) {
pkg->package = strdup(PyString_AsString(key)); pkg->package = strdup(PyString_AsString(key));
pkg->priority = 0; pkg->priority = 0;
pkg->details = NULL; pkg->details = NULL;
pkg->depends[1] = NULL;
pkg->depends[2] = NULL; pkg->depends[2] = NULL;
pkg->depends[3] = NULL; pkg->depends[3] = NULL;
@ -263,12 +258,6 @@ static PyObject *build_system(PyObject *self, PyObject *args) {
pyString = PyList_GetItem(value, 7); pyString = PyList_GetItem(value, 7);
if (pyString == NULL) continue; if (pyString == NULL) continue;
if (pyString != Py_None) {
pkg->depends[1] = read_dep_andor(PyString_AsString(pyString));
} else pkg->depends[1] = NULL;
pyString = PyList_GetItem(value, 8);
if (pyString == NULL) continue;
if (pyString != Py_None) { if (pyString != Py_None) {
pkg->conflicts = read_dep_and(PyString_AsString(pyString)); pkg->conflicts = read_dep_and(PyString_AsString(pyString));
} else pkg->conflicts = NULL; } else pkg->conflicts = NULL;

@ -521,7 +521,7 @@ static collpackagelist **get_matching_low(collpackagelist **addto,
if (dep->archqual != NULL) { if (dep->archqual != NULL) {
if (strcmp(dep->archqual, "any") == 0) { if (strcmp(dep->archqual, "any") == 0) {
if (strcmp(vpkg->value.multiarch, "allowed") != 0) if (vpkg->value.multiarch == NULL || strcmp(vpkg->value.multiarch, "allowed") != 0)
add = 0; add = 0;
} else } else
add = 0; add = 0;

@ -23,7 +23,7 @@ class MigrationItem(object):
def get_architectures(cls): def get_architectures(cls):
return cls._architectures return cls._architectures
def __init__(self, name = None, versionned = False): def __init__(self, name = None, versionned = True):
self._name = None self._name = None
self._uvname = None self._uvname = None
self._package = None self._package = None
@ -141,6 +141,6 @@ class MigrationItem(object):
def uvname(self): def uvname(self):
return self._uvname return self._uvname
class HintItem(MigrationItem): class UnversionnedMigrationItem(MigrationItem):
def __init__(self, name = None): def __init__(self, name = None):
MigrationItem.__init__(self, name = name, versionned = True) MigrationItem.__init__(self, name = name, versionned = False)

Loading…
Cancel
Save