Coverage for britney2/transaction.py: 96%

75 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2024-04-18 20:48 +0000

1class MigrationTransactionState(object): 

2 

3 def __init__(self, suite_info, all_binaries, parent=None): 

4 self._suite_info = suite_info 

5 self._all_binaries = all_binaries 

6 self.parent_transaction = parent 

7 self._is_rolled_back = False 

8 self._is_committed = False 

9 self._undo_items = [] 

10 self._pending_child = False 

11 if self.parent_transaction: 

12 # Transactions can only support one child transaction at a time 

13 assert not self.parent_transaction._pending_child 

14 self.parent_transaction._pending_child = True 

15 

16 def add_undo_item(self, undo, updated_binaries): 

17 # We do not accept any changes to this transaction while it has a child transaction 

18 # (the undo code does not handle that case correctly) 

19 assert not self._pending_child 

20 self._assert_open_transaction() 

21 self._undo_items.append((undo, updated_binaries)) 

22 

23 def _assert_open_transaction(self): 

24 assert not self._is_rolled_back and not self._is_committed 

25 p = self.parent_transaction 

26 if p: 

27 p._assert_open_transaction() 

28 

29 @property 

30 def undo_items(self): 

31 """Only needed by a _apply_item_to_target_suite for the "hint"-hint case""" 

32 yield from self._undo_items 

33 

34 def commit(self): 

35 """Commit the transaction 

36 

37 After this call, it is not possible to roll these changes 

38 back (except if there is a parent transaction, which can 

39 still be rolled back). 

40 """ 

41 self._assert_open_transaction() 

42 self._is_committed = True 

43 if self.parent_transaction: 

44 self.parent_transaction._pending_child = False 

45 for undo_item in self._undo_items: 

46 self.parent_transaction.add_undo_item(*undo_item) 

47 

48 def rollback(self): 

49 """Rollback all recorded changes by this transaction 

50 

51 The parent transaction (if any) will remain unchanged 

52 """ 

53 

54 self._assert_open_transaction() 

55 self._is_rolled_back = True 

56 lundo = self._undo_items 

57 lundo.reverse() 

58 

59 all_binary_packages = self._all_binaries 

60 target_suite = self._suite_info.target_suite 

61 sources_t = target_suite.sources 

62 binaries_t = target_suite.binaries 

63 provides_t = target_suite.provides_table 

64 

65 # Historically, we have done the undo process in "4 steps" 

66 # with the rule that each step must be fully completed for 

67 # each undo-item before starting on the next. 

68 # 

69 # see commit:ef71f0e33a7c3d8ef223ec9ad5e9843777e68133 and 

70 # #624716 for the issues we had when we did not do this. 

71 # 

72 # Today, only STEP 2 and STEP 3 are known to potentially 

73 # clash. If there is a point in merging the loops/steps, 

74 # then it is now feasible. 

75 

76 # STEP 1 

77 # undo all the changes for sources 

78 for (undo, updated_binaries) in lundo: 

79 for (k, v) in undo['sources'].items(): 

80 if v is None: 

81 del sources_t[k] 

82 else: 

83 sources_t[k] = v 

84 

85 # STEP 2 

86 # undo all new/updated binaries 

87 # Note this must be completed fully before starting STEP 3 

88 # as it potentially breaks STEP 3 if the two are interleaved. 

89 for (_, updated_binaries) in lundo: 

90 for pkg_id in updated_binaries: 

91 pkg_name, _, pkg_arch = pkg_id 

92 try: 

93 del binaries_t[pkg_arch][pkg_name] 

94 except KeyError: 

95 continue 

96 

97 target_suite.remove_binary(pkg_id) 

98 

99 # STEP 3 

100 # undo all other binary package changes (except virtual packages) 

101 for (undo, updated_binaries) in lundo: 

102 for p in undo['binaries']: 

103 binary, arch = p 

104 binaries_t_a = binaries_t[arch] 

105 pkgdata = all_binary_packages[undo['binaries'][p]] 

106 binaries_t_a[binary] = pkgdata 

107 target_suite.add_binary(pkgdata.pkg_id) 

108 

109 # STEP 4 

110 # undo all changes to virtual packages 

111 for (undo, _) in lundo: 

112 for p, value in undo['virtual'].items(): 

113 provided_pkg, arch = p 

114 if value is None: 114 ↛ 115line 114 didn't jump to line 115, because the condition on line 114 was never true

115 del provides_t[arch][provided_pkg] 

116 else: 

117 provides_t[arch][provided_pkg] = undo['virtual'][p] 

118 

119 if self.parent_transaction: 

120 self.parent_transaction._pending_child = False 

121 

122 @property 

123 def is_rolled_back(self): 

124 return self._is_rolled_back 

125 

126 @property 

127 def is_committed(self): 

128 return self._is_committed