mirror of
https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
synced 2025-05-15 12:31:31 +00:00
Have MigrationManager keep track of active transaction
This leaves callers with only having to track the transaction they need to care about (if any). Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
parent
4803065e1a
commit
c7dbd95c0b
37
britney.py
37
britney.py
@ -179,6 +179,7 @@ does for the generation of the update excuses.
|
|||||||
|
|
||||||
* The excuses are written in an HTML file.
|
* The excuses are written in an HTML file.
|
||||||
"""
|
"""
|
||||||
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
@ -203,7 +204,6 @@ from britney2.migrationitem import MigrationItem
|
|||||||
from britney2.policies import PolicyVerdict
|
from britney2.policies import PolicyVerdict
|
||||||
from britney2.policies.policy import AgePolicy, RCBugPolicy, PiupartsPolicy, BuildDependsPolicy
|
from britney2.policies.policy import AgePolicy, RCBugPolicy, PiupartsPolicy, BuildDependsPolicy
|
||||||
from britney2.policies.autopkgtest import AutopkgtestPolicy
|
from britney2.policies.autopkgtest import AutopkgtestPolicy
|
||||||
from britney2.transaction import start_transaction
|
|
||||||
from britney2.utils import (log_and_format_old_libraries, get_dependency_solvers,
|
from britney2.utils import (log_and_format_old_libraries, get_dependency_solvers,
|
||||||
read_nuninst, write_nuninst, write_heidi,
|
read_nuninst, write_nuninst, write_heidi,
|
||||||
format_and_log_uninst, newly_uninst, make_migrationitem,
|
format_and_log_uninst, newly_uninst, make_migrationitem,
|
||||||
@ -1490,7 +1490,7 @@ class Britney(object):
|
|||||||
res.append("%s-%d" % (arch[0], n))
|
res.append("%s-%d" % (arch[0], n))
|
||||||
return "%d+%d: %s" % (total, totalbreak, ":".join(res))
|
return "%d+%d: %s" % (total, totalbreak, ":".join(res))
|
||||||
|
|
||||||
def iter_packages(self, packages, selected, nuninst=None, parent_transaction=None, try_removals=True):
|
def iter_packages(self, packages, selected, nuninst=None, try_removals=True):
|
||||||
"""Iter on the list of actions and apply them one-by-one
|
"""Iter on the list of actions and apply them one-by-one
|
||||||
|
|
||||||
This method applies the changes from `packages` to testing, checking the uninstallability
|
This method applies the changes from `packages` to testing, checking the uninstallability
|
||||||
@ -1502,8 +1502,6 @@ class Britney(object):
|
|||||||
rescheduled_packages = packages
|
rescheduled_packages = packages
|
||||||
maybe_rescheduled_packages = []
|
maybe_rescheduled_packages = []
|
||||||
output_logger = self.output_logger
|
output_logger = self.output_logger
|
||||||
suite_info = self.suite_info
|
|
||||||
all_binaries = self.all_binaries
|
|
||||||
solver = InstallabilitySolver(self.pkg_universe, self._inst_tester)
|
solver = InstallabilitySolver(self.pkg_universe, self._inst_tester)
|
||||||
mm = self._migration_manager
|
mm = self._migration_manager
|
||||||
|
|
||||||
@ -1536,12 +1534,11 @@ class Britney(object):
|
|||||||
comp = worklist.pop()
|
comp = worklist.pop()
|
||||||
comp_name = ' '.join(item.uvname for item in comp)
|
comp_name = ' '.join(item.uvname for item in comp)
|
||||||
output_logger.info("trying: %s" % comp_name)
|
output_logger.info("trying: %s" % comp_name)
|
||||||
with start_transaction(suite_info, all_binaries, parent_transaction) as transaction:
|
with mm.start_transaction() as transaction:
|
||||||
accepted = False
|
accepted = False
|
||||||
try:
|
try:
|
||||||
accepted, nuninst_after, failed_arch = mm.migrate_item_to_target_suite(comp,
|
accepted, nuninst_after, failed_arch = mm.migrate_item_to_target_suite(comp,
|
||||||
nuninst_last_accepted,
|
nuninst_last_accepted)
|
||||||
transaction)
|
|
||||||
if accepted:
|
if accepted:
|
||||||
selected.extend(comp)
|
selected.extend(comp)
|
||||||
transaction.commit()
|
transaction.commit()
|
||||||
@ -1601,7 +1598,6 @@ class Britney(object):
|
|||||||
(nuninst_last_accepted, extra) = self.iter_packages(removals,
|
(nuninst_last_accepted, extra) = self.iter_packages(removals,
|
||||||
selected,
|
selected,
|
||||||
nuninst=nuninst_last_accepted,
|
nuninst=nuninst_last_accepted,
|
||||||
parent_transaction=parent_transaction,
|
|
||||||
try_removals=False)
|
try_removals=False)
|
||||||
|
|
||||||
output_logger.info(" finish: [%s]", ",".join(x.uvname for x in selected))
|
output_logger.info(" finish: [%s]", ",".join(x.uvname for x in selected))
|
||||||
@ -1635,6 +1631,7 @@ class Britney(object):
|
|||||||
recurse = True
|
recurse = True
|
||||||
nuninst_end = None
|
nuninst_end = None
|
||||||
extra = []
|
extra = []
|
||||||
|
mm = self._migration_manager
|
||||||
|
|
||||||
if hinttype == "easy" or hinttype == "force-hint":
|
if hinttype == "easy" or hinttype == "force-hint":
|
||||||
force = hinttype == "force-hint"
|
force = hinttype == "force-hint"
|
||||||
@ -1652,18 +1649,25 @@ class Britney(object):
|
|||||||
output_logger.info("start: %s", self.eval_nuninst(nuninst_start))
|
output_logger.info("start: %s", self.eval_nuninst(nuninst_start))
|
||||||
output_logger.info("orig: %s", self.eval_nuninst(nuninst_start))
|
output_logger.info("orig: %s", self.eval_nuninst(nuninst_start))
|
||||||
|
|
||||||
with start_transaction(self.suite_info, self.all_binaries) as transaction:
|
if init and not force:
|
||||||
if not init or force:
|
# We will need to be able to roll back (e.g. easy or a "hint"-hint)
|
||||||
# Throw away the (outer) transaction as we will not be using it
|
_start_transaction = mm.start_transaction
|
||||||
transaction.rollback()
|
else:
|
||||||
transaction = None
|
# No "outer" transaction needed as we will never need to rollback
|
||||||
|
# (e.g. "force-hint" or a regular "main run"). Emulate the start_transaction
|
||||||
|
# call from the MigrationManager, so the rest of the code follows the
|
||||||
|
# same flow regardless of whether we need the transaction or not.
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def _start_transaction():
|
||||||
|
yield None
|
||||||
|
|
||||||
|
with _start_transaction() as transaction:
|
||||||
|
|
||||||
if init:
|
if init:
|
||||||
mm = self._migration_manager
|
|
||||||
# init => a hint (e.g. "easy") - so do the hint run
|
# init => a hint (e.g. "easy") - so do the hint run
|
||||||
(_, nuninst_end, _) = mm.migrate_item_to_target_suite(selected,
|
(_, nuninst_end, _) = mm.migrate_item_to_target_suite(selected,
|
||||||
self.nuninst_orig,
|
self.nuninst_orig,
|
||||||
transaction,
|
|
||||||
stop_on_first_regression=False)
|
stop_on_first_regression=False)
|
||||||
|
|
||||||
if recurse:
|
if recurse:
|
||||||
@ -1675,8 +1679,7 @@ class Britney(object):
|
|||||||
# Either the main run or the recursive run of a "hint"-hint.
|
# Either the main run or the recursive run of a "hint"-hint.
|
||||||
(nuninst_end, extra) = self.iter_packages(upgrade_me,
|
(nuninst_end, extra) = self.iter_packages(upgrade_me,
|
||||||
selected,
|
selected,
|
||||||
nuninst=nuninst_end,
|
nuninst=nuninst_end)
|
||||||
parent_transaction=transaction)
|
|
||||||
|
|
||||||
nuninst_end_str = self.eval_nuninst(nuninst_end)
|
nuninst_end_str = self.eval_nuninst(nuninst_end)
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import apt_pkg
|
import apt_pkg
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
from britney2.transaction import MigrationTransactionState
|
||||||
from britney2.utils import (
|
from britney2.utils import (
|
||||||
MigrationConstraintException, compute_reverse_tree, check_installability, clone_nuninst,
|
MigrationConstraintException, compute_reverse_tree, check_installability, clone_nuninst,
|
||||||
find_smooth_updateable_binaries,
|
find_smooth_updateable_binaries,
|
||||||
@ -14,6 +16,11 @@ class MigrationManager(object):
|
|||||||
self.all_binaries = all_binaries
|
self.all_binaries = all_binaries
|
||||||
self.pkg_universe = pkg_universe
|
self.pkg_universe = pkg_universe
|
||||||
self.constraints = constraints
|
self.constraints = constraints
|
||||||
|
self._transactions = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_transaction(self):
|
||||||
|
return self._transactions[0] if self._transactions else None
|
||||||
|
|
||||||
def _compute_groups(self,
|
def _compute_groups(self,
|
||||||
item,
|
item,
|
||||||
@ -164,12 +171,9 @@ class MigrationManager(object):
|
|||||||
|
|
||||||
return (adds, rms, smoothbins)
|
return (adds, rms, smoothbins)
|
||||||
|
|
||||||
def _apply_item_to_target_suite(self, item, transaction, removals=frozenset()):
|
def _apply_item_to_target_suite(self, item, removals=frozenset()):
|
||||||
"""Apply a change to the target suite as requested by `item`
|
"""Apply a change to the target suite as requested by `item`
|
||||||
|
|
||||||
A transaction in which all changes will be recorded. Can be None (e.g.
|
|
||||||
during a "force-hint"), when the changes will not be rolled back.
|
|
||||||
|
|
||||||
An optional set of binaries may be passed in "removals". Binaries listed
|
An optional set of binaries may be passed in "removals". Binaries listed
|
||||||
in this set will be assumed to be removed at the same time as the "item"
|
in this set will be assumed to be removed at the same time as the "item"
|
||||||
will migrate. This may change what binaries will be smooth-updated.
|
will migrate. This may change what binaries will be smooth-updated.
|
||||||
@ -194,6 +198,7 @@ class MigrationManager(object):
|
|||||||
provides_t = target_suite.provides_table
|
provides_t = target_suite.provides_table
|
||||||
pkg_universe = self.pkg_universe
|
pkg_universe = self.pkg_universe
|
||||||
eqv_set = set()
|
eqv_set = set()
|
||||||
|
transaction = self.current_transaction
|
||||||
|
|
||||||
updates, rms, _ = self._compute_groups(item, removals=removals)
|
updates, rms, _ = self._compute_groups(item, removals=removals)
|
||||||
|
|
||||||
@ -326,7 +331,7 @@ class MigrationManager(object):
|
|||||||
# return the affected packages (direct and than all)
|
# return the affected packages (direct and than all)
|
||||||
return (affected_direct, affected_all)
|
return (affected_direct, affected_all)
|
||||||
|
|
||||||
def migrate_item_to_target_suite(self, actions, nuninst_now, transaction, stop_on_first_regression=True):
|
def migrate_item_to_target_suite(self, actions, nuninst_now, stop_on_first_regression=True):
|
||||||
is_accepted = True
|
is_accepted = True
|
||||||
affected_architectures = set()
|
affected_architectures = set()
|
||||||
item = actions
|
item = actions
|
||||||
@ -341,7 +346,7 @@ class MigrationManager(object):
|
|||||||
if len(actions) == 1:
|
if len(actions) == 1:
|
||||||
item = actions[0]
|
item = actions[0]
|
||||||
# apply the changes
|
# apply the changes
|
||||||
affected_direct, affected_all = self._apply_item_to_target_suite(item, transaction)
|
affected_direct, affected_all = self._apply_item_to_target_suite(item)
|
||||||
if item.architecture == 'source':
|
if item.architecture == 'source':
|
||||||
affected_architectures = set(self.options.architectures)
|
affected_architectures = set(self.options.architectures)
|
||||||
else:
|
else:
|
||||||
@ -360,7 +365,6 @@ class MigrationManager(object):
|
|||||||
|
|
||||||
for item in actions:
|
for item in actions:
|
||||||
item_affected_direct, item_affected_all = self._apply_item_to_target_suite(item,
|
item_affected_direct, item_affected_all = self._apply_item_to_target_suite(item,
|
||||||
transaction,
|
|
||||||
removals=removals)
|
removals=removals)
|
||||||
affected_direct.update(item_affected_direct)
|
affected_direct.update(item_affected_direct)
|
||||||
affected_all.update(item_affected_all)
|
affected_all.update(item_affected_all)
|
||||||
@ -407,3 +411,17 @@ class MigrationManager(object):
|
|||||||
break
|
break
|
||||||
|
|
||||||
return (is_accepted, nuninst_after, arch)
|
return (is_accepted, nuninst_after, arch)
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def start_transaction(self):
|
||||||
|
tmts = MigrationTransactionState(self.suite_info, self.all_binaries, self.current_transaction)
|
||||||
|
self._transactions.append(tmts)
|
||||||
|
try:
|
||||||
|
yield tmts
|
||||||
|
except Exception:
|
||||||
|
if not tmts.is_committed and not tmts.is_rolled_back:
|
||||||
|
tmts.rollback()
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self._transactions.pop()
|
||||||
|
assert tmts.is_rolled_back or tmts.is_committed
|
||||||
|
@ -1,18 +1,3 @@
|
|||||||
import contextlib
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def start_transaction(suite_info, all_binaries, parent_transaction=None):
|
|
||||||
tmts = MigrationTransactionState(suite_info, all_binaries, parent_transaction)
|
|
||||||
try:
|
|
||||||
yield tmts
|
|
||||||
except Exception:
|
|
||||||
if not tmts.is_committed and not tmts.is_rolled_back:
|
|
||||||
tmts.rollback()
|
|
||||||
raise
|
|
||||||
assert tmts.is_rolled_back or tmts.is_committed
|
|
||||||
|
|
||||||
|
|
||||||
class MigrationTransactionState(object):
|
class MigrationTransactionState(object):
|
||||||
|
|
||||||
def __init__(self, suite_info, all_binaries, parent=None):
|
def __init__(self, suite_info, all_binaries, parent=None):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user