Merge lp:~jelmer/qbrz/context-managers into lp:qbrz
- context-managers
- Merge into trunk
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | 1653 |
Merged at revision: | 1650 |
Proposed branch: | lp:~jelmer/qbrz/context-managers |
Merge into: | lp:qbrz |
Diff against target: |
1586 lines (+198/-535) 25 files modified
extras/build_pot.py (+2/-8) extras/import_po.py (+1/-4) lib/annotate.py (+3/-12) lib/browse.py (+29/-33) lib/cat.py (+3/-14) lib/cleanup.py (+0/-184) lib/commands.py (+4/-14) lib/commit.py (+2/-5) lib/commit_data.py (+2/-8) lib/diff.py (+20/-39) lib/diff_arg.py (+8/-11) lib/diffview.py (+1/-1) lib/diffwindow.py (+7/-11) lib/extra/isignored.py (+1/-1) lib/extra/isversioned.py (+1/-1) lib/lazycachedrevloader.py (+14/-17) lib/log.py (+4/-13) lib/loggraphviz.py (+4/-17) lib/spellcheck_enchant.py (+2/-2) lib/subprocess.py (+2/-8) lib/tests/test_extdiff.py (+4/-4) lib/tests/test_guidebar.py (+1/-1) lib/treewidget.py (+7/-32) lib/widgets/shelve.py (+69/-81) lib/widgets/shelvelist.py (+7/-14) |
To merge this branch: | bzr merge lp:~jelmer/qbrz/context-managers |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+426396@code.launchpad.net |
Commit message
Use more context managers.
Description of the change
Use more context managers.
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Revision history for this message
Aleksandr Smyshliaev (a1s) : | # |
Revision history for this message
Aleksandr Smyshliaev (a1s) : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'extras/build_pot.py' | |||
2 | --- extras/build_pot.py 2020-07-15 09:34:25 +0000 | |||
3 | +++ extras/build_pot.py 2022-07-06 15:37:54 +0000 | |||
4 | @@ -63,18 +63,12 @@ | |||
5 | 63 | raise DistutilsOptionError("You can't use options --lang=XXX and --no-lang in the same time.") | 63 | raise DistutilsOptionError("You can't use options --lang=XXX and --no-lang in the same time.") |
6 | 64 | 64 | ||
7 | 65 | def _force_LF(self, src, dst=None): | 65 | def _force_LF(self, src, dst=None): |
10 | 66 | f = open(src, 'rU') | 66 | with open(src, 'rU') as f: |
9 | 67 | try: | ||
11 | 68 | content = f.read() | 67 | content = f.read() |
12 | 69 | finally: | ||
13 | 70 | f.close() | ||
14 | 71 | if dst is None: | 68 | if dst is None: |
15 | 72 | dst = src | 69 | dst = src |
18 | 73 | f = open(dst, 'wb') | 70 | with open(dst, 'wb') as f: |
17 | 74 | try: | ||
19 | 75 | f.write(content) | 71 | f.write(content) |
20 | 76 | finally: | ||
21 | 77 | f.close() | ||
22 | 78 | 72 | ||
23 | 79 | def run(self): | 73 | def run(self): |
24 | 80 | """Run xgettext for project sources""" | 74 | """Run xgettext for project sources""" |
25 | 81 | 75 | ||
26 | === modified file 'extras/import_po.py' | |||
27 | --- extras/import_po.py 2019-10-27 14:48:19 +0000 | |||
28 | +++ extras/import_po.py 2022-07-06 15:37:54 +0000 | |||
29 | @@ -80,11 +80,8 @@ | |||
30 | 80 | for n, fn in entries: | 80 | for n, fn in entries: |
31 | 81 | log.info(' %s -> %s' % (n, fn)) | 81 | log.info(' %s -> %s' % (n, fn)) |
32 | 82 | ft = t.extractfile(n) | 82 | ft = t.extractfile(n) |
35 | 83 | fd = open(fn, 'wb') | 83 | with open(fn, 'wb') as fd: |
34 | 84 | try: | ||
36 | 85 | fd.write(ft.read()) | 84 | fd.write(ft.read()) |
37 | 86 | finally: | ||
38 | 87 | fd.close() | ||
39 | 88 | if pot_file: | 85 | if pot_file: |
40 | 89 | if find_executable('msginit') is None: | 86 | if find_executable('msginit') is None: |
41 | 90 | log.warn("GNU gettext msginit utility not found!") | 87 | log.warn("GNU gettext msginit utility not found!") |
42 | 91 | 88 | ||
43 | === modified file 'lib/annotate.py' | |||
44 | --- lib/annotate.py 2022-01-07 14:04:10 +0000 | |||
45 | +++ lib/annotate.py 2022-07-06 15:37:54 +0000 | |||
46 | @@ -410,12 +410,9 @@ | |||
47 | 410 | QtCore.QCoreApplication.processEvents() | 410 | QtCore.QCoreApplication.processEvents() |
48 | 411 | self.encoding = get_set_encoding(self.encoding, self.branch) | 411 | self.encoding = get_set_encoding(self.encoding, self.branch) |
49 | 412 | self.encoding_selector.encoding = self.encoding | 412 | self.encoding_selector.encoding = self.encoding |
52 | 413 | self.branch.lock_read() | 413 | with self.branch.lock_read(): |
51 | 414 | try: | ||
53 | 415 | self.set_annotate_title() | 414 | self.set_annotate_title() |
54 | 416 | self.annotate(self.annotate_tree, self.fileId, self.path) | 415 | self.annotate(self.annotate_tree, self.fileId, self.path) |
55 | 417 | finally: | ||
56 | 418 | self.branch.unlock() | ||
57 | 419 | finally: | 416 | finally: |
58 | 420 | self.throbber.hide() | 417 | self.throbber.hide() |
59 | 421 | QtCore.QTimer.singleShot(1, self._activate_line) | 418 | QtCore.QTimer.singleShot(1, self._activate_line) |
60 | @@ -634,8 +631,7 @@ | |||
61 | 634 | def set_annotate_revision(self): | 631 | def set_annotate_revision(self): |
62 | 635 | self.throbber.show() | 632 | self.throbber.show() |
63 | 636 | try: | 633 | try: |
66 | 637 | self.branch.lock_read() | 634 | with self.branch.lock_read(): |
65 | 638 | try: | ||
67 | 639 | revid = self.log_list.currentIndex().data(logmodel.RevIdRole) | 635 | revid = self.log_list.currentIndex().data(logmodel.RevIdRole) |
68 | 640 | if revid.startswith(CURRENT_REVISION): | 636 | if revid.startswith(CURRENT_REVISION): |
69 | 641 | rev = cached_revisions[revid] | 637 | rev = cached_revisions[revid] |
70 | @@ -646,8 +642,6 @@ | |||
71 | 646 | self.set_annotate_title() | 642 | self.set_annotate_title() |
72 | 647 | self.processEvents() | 643 | self.processEvents() |
73 | 648 | self.annotate(self.annotate_tree, self.fileId, self.path) | 644 | self.annotate(self.annotate_tree, self.fileId, self.path) |
74 | 649 | finally: | ||
75 | 650 | self.branch.unlock() | ||
76 | 651 | finally: | 645 | finally: |
77 | 652 | self.throbber.hide() | 646 | self.throbber.hide() |
78 | 653 | 647 | ||
79 | @@ -657,11 +651,8 @@ | |||
80 | 657 | get_set_encoding(encoding, self.branch) | 651 | get_set_encoding(encoding, self.branch) |
81 | 658 | self.throbber.show() | 652 | self.throbber.show() |
82 | 659 | try: | 653 | try: |
85 | 660 | self.branch.lock_read() | 654 | with self.branch.lock_read(): |
84 | 661 | try: | ||
86 | 662 | self.annotate(self.annotate_tree, self.fileId, self.path) | 655 | self.annotate(self.annotate_tree, self.fileId, self.path) |
87 | 663 | finally: | ||
88 | 664 | self.branch.unlock() | ||
89 | 665 | finally: | 656 | finally: |
90 | 666 | self.throbber.hide() | 657 | self.throbber.hide() |
91 | 667 | 658 | ||
92 | 668 | 659 | ||
93 | === modified file 'lib/browse.py' | |||
94 | --- lib/browse.py 2021-01-08 13:56:34 +0000 | |||
95 | +++ lib/browse.py 2022-07-06 15:37:54 +0000 | |||
96 | @@ -158,49 +158,45 @@ | |||
97 | 158 | self.diffbuttons, | 158 | self.diffbuttons, |
98 | 159 | self.refresh_button) | 159 | self.refresh_button) |
99 | 160 | state = self.file_tree.get_state() | 160 | state = self.file_tree.get_state() |
101 | 161 | if text=="wt:": | 161 | if text == "wt:": |
102 | 162 | self.tree = self.workingtree | 162 | self.tree = self.workingtree |
104 | 163 | self.tree.lock_read() | 163 | with self.tree.lock_read(): |
105 | 164 | try: | 164 | try: |
106 | 165 | self.file_tree.set_tree(self.workingtree, self.branch) | 165 | self.file_tree.set_tree(self.workingtree, self.branch) |
107 | 166 | self.file_tree.restore_state(state) | 166 | self.file_tree.restore_state(state) |
108 | 167 | finally: | ||
109 | 168 | self.tree.unlock() | ||
110 | 169 | for button in buttons: | 167 | for button in buttons: |
111 | 170 | button.setEnabled(True) | 168 | button.setEnabled(True) |
112 | 171 | else: | 169 | else: |
113 | 172 | branch = self.branch | 170 | branch = self.branch |
135 | 173 | branch.lock_read() | 171 | with branch.lock_read(): |
115 | 174 | self.processEvents() | ||
116 | 175 | |||
117 | 176 | for button in buttons: | ||
118 | 177 | button.setEnabled(False) | ||
119 | 178 | fmodel = self.file_tree.tree_filter_model | ||
120 | 179 | fmodel.setFilter(fmodel.UNCHANGED, True) | ||
121 | 180 | self.filter_menu.set_filters(fmodel.filters) | ||
122 | 181 | |||
123 | 182 | try: | ||
124 | 183 | if revision_id is None: | ||
125 | 184 | text = revspec.spec or '' | ||
126 | 185 | if revspec.in_branch == revspec.in_history: | ||
127 | 186 | args = [branch] | ||
128 | 187 | else: | ||
129 | 188 | args = [branch, False] | ||
130 | 189 | |||
131 | 190 | revision_id = revspec.in_branch(*args).rev_id | ||
132 | 191 | |||
133 | 192 | self.revision_id = revision_id | ||
134 | 193 | self.tree = branch.repository.revision_tree(revision_id) | ||
136 | 194 | self.processEvents() | 172 | self.processEvents() |
140 | 195 | self.file_tree.set_tree(self.tree, self.branch) | 173 | |
141 | 196 | self.file_tree.restore_state(state) | 174 | for button in buttons: |
142 | 197 | if self.revno_map is None: | 175 | button.setEnabled(False) |
143 | 176 | fmodel = self.file_tree.tree_filter_model | ||
144 | 177 | fmodel.setFilter(fmodel.UNCHANGED, True) | ||
145 | 178 | self.filter_menu.set_filters(fmodel.filters) | ||
146 | 179 | |||
147 | 180 | try: | ||
148 | 181 | if revision_id is None: | ||
149 | 182 | text = revspec.spec or '' | ||
150 | 183 | if revspec.in_branch == revspec.in_history: | ||
151 | 184 | args = [branch] | ||
152 | 185 | else: | ||
153 | 186 | args = [branch, False] | ||
154 | 187 | |||
155 | 188 | revision_id = revspec.in_branch(*args).rev_id | ||
156 | 189 | |||
157 | 190 | self.revision_id = revision_id | ||
158 | 191 | self.tree = branch.repository.revision_tree(revision_id) | ||
159 | 198 | self.processEvents() | 192 | self.processEvents() |
165 | 199 | # XXX make this operation lazy? how? | 193 | self.file_tree.set_tree(self.tree, self.branch) |
166 | 200 | self.revno_map = self.branch.get_revision_id_to_revno_map() | 194 | self.file_tree.restore_state(state) |
167 | 201 | self.file_tree.tree_model.set_revno_map(self.revno_map) | 195 | if self.revno_map is None: |
168 | 202 | finally: | 196 | self.processEvents() |
169 | 203 | branch.unlock() | 197 | # XXX make this operation lazy? how? |
170 | 198 | self.revno_map = self.branch.get_revision_id_to_revno_map() | ||
171 | 199 | self.file_tree.tree_model.set_revno_map(self.revno_map) | ||
172 | 204 | self.revision_edit.setText(text) | 200 | self.revision_edit.setText(text) |
173 | 205 | finally: | 201 | finally: |
174 | 206 | self.throbber.hide() | 202 | self.throbber.hide() |
175 | 207 | 203 | ||
176 | === modified file 'lib/cat.py' | |||
177 | --- lib/cat.py 2021-01-08 08:16:13 +0000 | |||
178 | +++ lib/cat.py 2022-07-06 15:37:54 +0000 | |||
179 | @@ -142,8 +142,7 @@ | |||
180 | 142 | "%r is not present in revision %s" % ( | 142 | "%r is not present in revision %s" % ( |
181 | 143 | self.filename, self.tree.get_revision_id())) | 143 | self.filename, self.tree.get_revision_id())) |
182 | 144 | 144 | ||
185 | 145 | self.tree.lock_read() | 145 | with self.tree.lock_read(): |
184 | 146 | try: | ||
186 | 147 | kind = self.tree.kind(self.filename) | 146 | kind = self.tree.kind(self.filename) |
187 | 148 | if kind == 'file': | 147 | if kind == 'file': |
188 | 149 | text = self.tree.get_file_text(self.filename) | 148 | text = self.tree.get_file_text(self.filename) |
189 | @@ -151,8 +150,6 @@ | |||
190 | 151 | text = self.tree.get_symlink_target(self.filename) | 150 | text = self.tree.get_symlink_target(self.filename) |
191 | 152 | else: | 151 | else: |
192 | 153 | text = '' | 152 | text = '' |
193 | 154 | finally: | ||
194 | 155 | self.tree.unlock() | ||
195 | 156 | self.processEvents() | 153 | self.processEvents() |
196 | 157 | 154 | ||
197 | 158 | self.text = text | 155 | self.text = text |
198 | @@ -304,11 +301,8 @@ | |||
199 | 304 | kind = osutils.file_kind(self.filename) | 301 | kind = osutils.file_kind(self.filename) |
200 | 305 | text = '' | 302 | text = '' |
201 | 306 | if kind == 'file': | 303 | if kind == 'file': |
204 | 307 | f = open(self.filename, 'rb') | 304 | with open(self.filename, 'rb') as f: |
203 | 308 | try: | ||
205 | 309 | text = f.read() | 305 | text = f.read() |
206 | 310 | finally: | ||
207 | 311 | f.close() | ||
208 | 312 | elif kind == 'symlink': | 306 | elif kind == 'symlink': |
209 | 313 | text = os.readlink(self.filename) | 307 | text = os.readlink(self.filename) |
210 | 314 | self.text = text | 308 | self.text = text |
211 | @@ -337,13 +331,8 @@ | |||
212 | 337 | os.makedirs(qdir) | 331 | os.makedirs(qdir) |
213 | 338 | basename = os.path.basename(relpath) | 332 | basename = os.path.basename(relpath) |
214 | 339 | fname = os.path.join(qdir, basename) | 333 | fname = os.path.join(qdir, basename) |
218 | 340 | f = open(fname, 'wb') | 334 | with open(fname, 'wb') as f, tree.lock_read(): |
216 | 341 | tree.lock_read() | ||
217 | 342 | try: | ||
219 | 343 | f.write(tree.get_file_text(relpath)) | 335 | f.write(tree.get_file_text(relpath)) |
220 | 344 | finally: | ||
221 | 345 | tree.unlock() | ||
222 | 346 | f.close() | ||
223 | 347 | # open it | 336 | # open it |
224 | 348 | url = QtCore.QUrl.fromLocalFile(fname) | 337 | url = QtCore.QUrl.fromLocalFile(fname) |
225 | 349 | result = QtGui.QDesktopServices.openUrl(url) | 338 | result = QtGui.QDesktopServices.openUrl(url) |
226 | 350 | 339 | ||
227 | === removed file 'lib/cleanup.py' | |||
228 | --- lib/cleanup.py 2020-07-14 15:58:13 +0000 | |||
229 | +++ lib/cleanup.py 1970-01-01 00:00:00 +0000 | |||
230 | @@ -1,184 +0,0 @@ | |||
231 | 1 | # Copyright (C) 2009, 2010 Canonical Ltd | ||
232 | 2 | # | ||
233 | 3 | # This program is free software; you can redistribute it and/or modify | ||
234 | 4 | # it under the terms of the GNU General Public License as published by | ||
235 | 5 | # the Free Software Foundation; either version 2 of the License, or | ||
236 | 6 | # (at your option) any later version. | ||
237 | 7 | # | ||
238 | 8 | # This program is distributed in the hope that it will be useful, | ||
239 | 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
240 | 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
241 | 11 | # GNU General Public License for more details. | ||
242 | 12 | # | ||
243 | 13 | # You should have received a copy of the GNU General Public License | ||
244 | 14 | # along with this program; if not, write to the Free Software | ||
245 | 15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
246 | 16 | |||
247 | 17 | """Helpers for managing cleanup functions and the errors they might raise. | ||
248 | 18 | |||
249 | 19 | The usual way to run cleanup code in Python is:: | ||
250 | 20 | |||
251 | 21 | try: | ||
252 | 22 | do_something() | ||
253 | 23 | finally: | ||
254 | 24 | cleanup_something() | ||
255 | 25 | |||
256 | 26 | However if both `do_something` and `cleanup_something` raise an exception | ||
257 | 27 | Python will forget the original exception and propagate the one from | ||
258 | 28 | cleanup_something. Unfortunately, this is almost always much less useful than | ||
259 | 29 | the original exception. | ||
260 | 30 | |||
261 | 31 | If you want to be certain that the first, and only the first, error is raised, | ||
262 | 32 | then use:: | ||
263 | 33 | |||
264 | 34 | operation = OperationWithCleanups(do_something) | ||
265 | 35 | operation.add_cleanup(cleanup_something) | ||
266 | 36 | operation.run_simple() | ||
267 | 37 | |||
268 | 38 | This is more inconvenient (because you need to make every try block a | ||
269 | 39 | function), but will ensure that the first error encountered is the one raised, | ||
270 | 40 | while also ensuring all cleanups are run. See OperationWithCleanups for more | ||
271 | 41 | details. | ||
272 | 42 | """ | ||
273 | 43 | |||
274 | 44 | from __future__ import absolute_import | ||
275 | 45 | |||
276 | 46 | from collections import deque | ||
277 | 47 | # import sys | ||
278 | 48 | # from . import ( | ||
279 | 49 | # debug, | ||
280 | 50 | # trace, | ||
281 | 51 | # ) | ||
282 | 52 | |||
283 | 53 | from breezy import ( | ||
284 | 54 | debug, | ||
285 | 55 | trace, | ||
286 | 56 | ) | ||
287 | 57 | |||
288 | 58 | |||
289 | 59 | def _log_cleanup_error(exc): | ||
290 | 60 | trace.mutter('Cleanup failed:') | ||
291 | 61 | trace.log_exception_quietly() | ||
292 | 62 | if 'cleanup' in debug.debug_flags: | ||
293 | 63 | trace.warning('brz: warning: Cleanup failed: %s', exc) | ||
294 | 64 | |||
295 | 65 | |||
296 | 66 | def _run_cleanup(func, *args, **kwargs): | ||
297 | 67 | """Run func(*args, **kwargs), logging but not propagating any error it | ||
298 | 68 | raises. | ||
299 | 69 | |||
300 | 70 | :returns: True if func raised no errors, else False. | ||
301 | 71 | """ | ||
302 | 72 | try: | ||
303 | 73 | func(*args, **kwargs) | ||
304 | 74 | except KeyboardInterrupt: | ||
305 | 75 | raise | ||
306 | 76 | except Exception as exc: | ||
307 | 77 | _log_cleanup_error(exc) | ||
308 | 78 | return False | ||
309 | 79 | return True | ||
310 | 80 | |||
311 | 81 | |||
312 | 82 | def _run_cleanups(funcs): | ||
313 | 83 | """Run a series of cleanup functions.""" | ||
314 | 84 | for func, args, kwargs in funcs: | ||
315 | 85 | _run_cleanup(func, *args, **kwargs) | ||
316 | 86 | |||
317 | 87 | |||
318 | 88 | class ObjectWithCleanups(object): | ||
319 | 89 | """A mixin for objects that hold a cleanup list. | ||
320 | 90 | |||
321 | 91 | Subclass or client code can call add_cleanup and then later `cleanup_now`. | ||
322 | 92 | """ | ||
323 | 93 | def __init__(self): | ||
324 | 94 | self.cleanups = deque() | ||
325 | 95 | |||
326 | 96 | def add_cleanup(self, cleanup_func, *args, **kwargs): | ||
327 | 97 | """Add a cleanup to run. | ||
328 | 98 | |||
329 | 99 | Cleanups may be added at any time. | ||
330 | 100 | Cleanups will be executed in LIFO order. | ||
331 | 101 | """ | ||
332 | 102 | self.cleanups.appendleft((cleanup_func, args, kwargs)) | ||
333 | 103 | |||
334 | 104 | def cleanup_now(self): | ||
335 | 105 | _run_cleanups(self.cleanups) | ||
336 | 106 | self.cleanups.clear() | ||
337 | 107 | |||
338 | 108 | |||
339 | 109 | class OperationWithCleanups(ObjectWithCleanups): | ||
340 | 110 | """A way to run some code with a dynamic cleanup list. | ||
341 | 111 | |||
342 | 112 | This provides a way to add cleanups while the function-with-cleanups is | ||
343 | 113 | running. | ||
344 | 114 | |||
345 | 115 | Typical use:: | ||
346 | 116 | |||
347 | 117 | operation = OperationWithCleanups(some_func) | ||
348 | 118 | operation.run(args...) | ||
349 | 119 | |||
350 | 120 | where `some_func` is:: | ||
351 | 121 | |||
352 | 122 | def some_func(operation, args, ...): | ||
353 | 123 | do_something() | ||
354 | 124 | operation.add_cleanup(something) | ||
355 | 125 | # etc | ||
356 | 126 | |||
357 | 127 | Note that the first argument passed to `some_func` will be the | ||
358 | 128 | OperationWithCleanups object. To invoke `some_func` without that, use | ||
359 | 129 | `run_simple` instead of `run`. | ||
360 | 130 | """ | ||
361 | 131 | |||
362 | 132 | def __init__(self, func): | ||
363 | 133 | super(OperationWithCleanups, self).__init__() | ||
364 | 134 | self.func = func | ||
365 | 135 | |||
366 | 136 | def run(self, *args, **kwargs): | ||
367 | 137 | return _do_with_cleanups(self.cleanups, self.func, self, *args, **kwargs) | ||
368 | 138 | |||
369 | 139 | def run_simple(self, *args, **kwargs): | ||
370 | 140 | return _do_with_cleanups(self.cleanups, self.func, *args, **kwargs) | ||
371 | 141 | |||
372 | 142 | |||
373 | 143 | def _do_with_cleanups(cleanup_funcs, func, *args, **kwargs): | ||
374 | 144 | """Run `func`, then call all the cleanup_funcs. | ||
375 | 145 | |||
376 | 146 | All the cleanup_funcs are guaranteed to be run. The first exception raised | ||
377 | 147 | by func or any of the cleanup_funcs is the one that will be propagted by | ||
378 | 148 | this function (subsequent errors are caught and logged). | ||
379 | 149 | |||
380 | 150 | Conceptually similar to:: | ||
381 | 151 | |||
382 | 152 | try: | ||
383 | 153 | return func(*args, **kwargs) | ||
384 | 154 | finally: | ||
385 | 155 | for cleanup, cargs, ckwargs in cleanup_funcs: | ||
386 | 156 | cleanup(*cargs, **ckwargs) | ||
387 | 157 | |||
388 | 158 | It avoids several problems with using try/finally directly: | ||
389 | 159 | * an exception from func will not be obscured by a subsequent exception | ||
390 | 160 | from a cleanup. | ||
391 | 161 | * an exception from a cleanup will not prevent other cleanups from | ||
392 | 162 | running (but the first exception encountered is still the one | ||
393 | 163 | propagated). | ||
394 | 164 | |||
395 | 165 | Unike `_run_cleanup`, `_do_with_cleanups` can propagate an exception from a | ||
396 | 166 | cleanup, but only if there is no exception from func. | ||
397 | 167 | """ | ||
398 | 168 | try: | ||
399 | 169 | result = func(*args, **kwargs) | ||
400 | 170 | except: | ||
401 | 171 | # We have an exception from func already, so suppress cleanup errors. | ||
402 | 172 | _run_cleanups(cleanup_funcs) | ||
403 | 173 | raise | ||
404 | 174 | # No exception from func, so allow first cleanup error to propgate. | ||
405 | 175 | pending_cleanups = iter(cleanup_funcs) | ||
406 | 176 | try: | ||
407 | 177 | for cleanup, c_args, c_kwargs in pending_cleanups: | ||
408 | 178 | cleanup(*c_args, **c_kwargs) | ||
409 | 179 | except: | ||
410 | 180 | # Still run the remaining cleanups but suppress any further errors. | ||
411 | 181 | _run_cleanups(pending_cleanups) | ||
412 | 182 | raise | ||
413 | 183 | # No error, so we can return the result | ||
414 | 184 | return result | ||
415 | 185 | 0 | ||
416 | === modified file 'lib/commands.py' | |||
417 | --- lib/commands.py 2021-08-05 11:12:43 +0000 | |||
418 | +++ lib/commands.py 2022-07-06 15:37:54 +0000 | |||
419 | @@ -367,11 +367,8 @@ | |||
420 | 367 | if message is not None and file: | 367 | if message is not None and file: |
421 | 368 | raise errors.BzrCommandError("please specify either --message or --file") | 368 | raise errors.BzrCommandError("please specify either --message or --file") |
422 | 369 | if file: | 369 | if file: |
425 | 370 | f = open(file) | 370 | with open(file) as f: |
424 | 371 | try: | ||
426 | 372 | message = f.read().decode(file_encoding or osutils.get_user_encoding()) | 371 | message = f.read().decode(file_encoding or osutils.get_user_encoding()) |
427 | 373 | finally: | ||
428 | 374 | f.close() | ||
429 | 375 | tree, selected_list = WorkingTree.open_containing_paths(selected_list) | 372 | tree, selected_list = WorkingTree.open_containing_paths(selected_list) |
430 | 376 | if selected_list == ['']: | 373 | if selected_list == ['']: |
431 | 377 | selected_list = None | 374 | selected_list = None |
432 | @@ -403,18 +400,11 @@ | |||
433 | 403 | takes_options.append('change') | 400 | takes_options.append('change') |
434 | 404 | aliases = ['qdi'] | 401 | aliases = ['qdi'] |
435 | 405 | 402 | ||
444 | 406 | def get_diff_window_args(self, processEvents, add_cleanup): | 403 | def get_diff_window_args(self, processEvents, es): |
437 | 407 | # RJL if you get a ``AttributeError: 'function' object has no attribute 'enter_context'`` | ||
438 | 408 | # error, or something similar, use something like: | ||
439 | 409 | # | ||
440 | 410 | # exit_stack = contextlib.ExitStack() | ||
441 | 411 | # | ||
442 | 412 | # and pass that as add_cleanup | ||
443 | 413 | # | ||
445 | 414 | args = {} | 404 | args = {} |
446 | 415 | (args["old_tree"], args["new_tree"], | 405 | (args["old_tree"], args["new_tree"], |
447 | 416 | args["old_branch"], args["new_branch"], | 406 | args["old_branch"], args["new_branch"], |
449 | 417 | args["specific_files"], _) = get_trees_and_branches_to_diff_locked(self.file_list, self.revision, self.old, self.new, add_cleanup) | 407 | args["specific_files"], _) = get_trees_and_branches_to_diff_locked(self.file_list, self.revision, self.old, self.new, es) |
450 | 418 | args["ignore_whitespace"] = self.ignore_whitespace | 408 | args["ignore_whitespace"] = self.ignore_whitespace |
451 | 419 | return args | 409 | return args |
452 | 420 | 410 | ||
453 | @@ -716,7 +706,7 @@ | |||
454 | 716 | del kw['encoding'] | 706 | del kw['encoding'] |
455 | 717 | return breezy.builtins.cmd_merge.run(self, *args, **kw) | 707 | return breezy.builtins.cmd_merge.run(self, *args, **kw) |
456 | 718 | 708 | ||
458 | 719 | def get_diff_window_args(self, processEvents, add_cleanup): | 709 | def get_diff_window_args(self, processEvents, es): |
459 | 720 | tree_merger = self.merger.make_merger() | 710 | tree_merger = self.merger.make_merger() |
460 | 721 | self.tt = tree_merger.make_preview_transform() | 711 | self.tt = tree_merger.make_preview_transform() |
461 | 722 | result_tree = self.tt.get_preview_tree() | 712 | result_tree = self.tt.get_preview_tree() |
462 | 723 | 713 | ||
463 | === modified file 'lib/commit.py' | |||
464 | --- lib/commit.py 2022-01-07 15:10:55 +0000 | |||
465 | +++ lib/commit.py 2022-07-06 15:37:54 +0000 | |||
466 | @@ -465,8 +465,7 @@ | |||
467 | 465 | self.throbber.show() | 465 | self.throbber.show() |
468 | 466 | self.refresh_button.setDisabled(True) | 466 | self.refresh_button.setDisabled(True) |
469 | 467 | try: | 467 | try: |
472 | 468 | self.tree.lock_read() | 468 | with self.tree.lock_read(): |
471 | 469 | try: | ||
473 | 470 | if self.pending_merges_list: | 469 | if self.pending_merges_list: |
474 | 471 | self.pending_merges_list.load_tree(self.tree) | 470 | self.pending_merges_list.load_tree(self.tree) |
475 | 472 | # Force the loading of the revisions, before we start | 471 | # Force the loading of the revisions, before we start |
476 | @@ -488,7 +487,7 @@ | |||
477 | 488 | # if there are any paths from the command line that | 487 | # if there are any paths from the command line that |
478 | 489 | # are not versioned, we want_unversioned. | 488 | # are not versioned, we want_unversioned. |
479 | 490 | for path in self.initial_selected_list: | 489 | for path in self.initial_selected_list: |
481 | 491 | if not self.tree.path2id(path): | 490 | if not self.tree.is_versioned(path): |
482 | 492 | want_unversioned = True | 491 | want_unversioned = True |
483 | 493 | break | 492 | break |
484 | 494 | 493 | ||
485 | @@ -504,8 +503,6 @@ | |||
486 | 504 | self.is_loading = False | 503 | self.is_loading = False |
487 | 505 | self.processEvents() | 504 | self.processEvents() |
488 | 506 | self.update_compleater_words() | 505 | self.update_compleater_words() |
489 | 507 | finally: | ||
490 | 508 | self.tree.unlock() | ||
491 | 509 | finally: | 506 | finally: |
492 | 510 | self.throbber.hide() | 507 | self.throbber.hide() |
493 | 511 | self.refresh_button.setDisabled(False) | 508 | self.refresh_button.setDisabled(False) |
494 | 512 | 509 | ||
495 | === modified file 'lib/commit_data.py' | |||
496 | --- lib/commit_data.py 2019-10-27 14:48:19 +0000 | |||
497 | +++ lib/commit_data.py 2022-07-06 15:37:54 +0000 | |||
498 | @@ -164,14 +164,11 @@ | |||
499 | 164 | def save(self): | 164 | def save(self): |
500 | 165 | """Save data to the branch/tree.""" | 165 | """Save data to the branch/tree.""" |
501 | 166 | br = self._get_branch() | 166 | br = self._get_branch() |
504 | 167 | br.lock_write() | 167 | with br.lock_write(): |
503 | 168 | try: | ||
505 | 169 | # XXX save should wipe if self._data is empty | 168 | # XXX save should wipe if self._data is empty |
506 | 170 | self._set_new_commit_data(self._filtered_data()) | 169 | self._set_new_commit_data(self._filtered_data()) |
507 | 171 | # clear old data | 170 | # clear old data |
508 | 172 | self._wipe_old_data() | 171 | self._wipe_old_data() |
509 | 173 | finally: | ||
510 | 174 | br.unlock() | ||
511 | 175 | 172 | ||
512 | 176 | def _wipe_old_data(self): | 173 | def _wipe_old_data(self): |
513 | 177 | """Wipe saved data in old format.""" | 174 | """Wipe saved data in old format.""" |
514 | @@ -180,13 +177,10 @@ | |||
515 | 180 | def wipe(self): | 177 | def wipe(self): |
516 | 181 | """Delete saved data from branch/tree config.""" | 178 | """Delete saved data from branch/tree config.""" |
517 | 182 | br = self._get_branch() | 179 | br = self._get_branch() |
520 | 183 | br.lock_write() | 180 | with br.lock_write(): |
519 | 184 | try: | ||
521 | 185 | self._set_new_commit_data({}) | 181 | self._set_new_commit_data({}) |
522 | 186 | # clear old data | 182 | # clear old data |
523 | 187 | self._wipe_old_data() | 183 | self._wipe_old_data() |
524 | 188 | finally: | ||
525 | 189 | br.unlock() | ||
526 | 190 | 184 | ||
527 | 191 | def _get_branch(self): | 185 | def _get_branch(self): |
528 | 192 | """Return branch object if either branch or tree was specified on init. | 186 | """Return branch object if either branch or tree was specified on init. |
529 | 193 | 187 | ||
530 | === modified file 'lib/diff.py' | |||
531 | --- lib/diff.py 2022-01-08 11:48:59 +0000 | |||
532 | +++ lib/diff.py 2022-07-06 15:37:54 +0000 | |||
533 | @@ -17,8 +17,18 @@ | |||
534 | 17 | # along with this program; if not, write to the Free Software | 17 | # along with this program; if not, write to the Free Software |
535 | 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
536 | 19 | 19 | ||
537 | 20 | from contextlib import ExitStack | ||
538 | 21 | import errno | ||
539 | 22 | import re | ||
540 | 23 | import time | ||
541 | 24 | import sys | ||
542 | 25 | import os | ||
543 | 26 | import glob | ||
544 | 27 | |||
545 | 20 | from PyQt5 import QtCore, QtGui, QtWidgets | 28 | from PyQt5 import QtCore, QtGui, QtWidgets |
546 | 21 | 29 | ||
547 | 30 | from breezy import trace, osutils, cmdline | ||
548 | 31 | |||
549 | 22 | from breezy.errors import NoSuchId, ExecutableMissing | 32 | from breezy.errors import NoSuchId, ExecutableMissing |
550 | 23 | from breezy.tree import FileTimestampUnavailable | 33 | from breezy.tree import FileTimestampUnavailable |
551 | 24 | from breezy.plugins.qbrz.lib.diff_arg import * # import DiffArgProvider classes | 34 | from breezy.plugins.qbrz.lib.diff_arg import * # import DiffArgProvider classes |
552 | @@ -30,22 +40,9 @@ | |||
553 | 30 | ) | 40 | ) |
554 | 31 | 41 | ||
555 | 32 | from breezy.lazy_import import lazy_import | 42 | from breezy.lazy_import import lazy_import |
556 | 33 | try: | ||
557 | 34 | QString = unicode | ||
558 | 35 | except NameError: | ||
559 | 36 | # Python 3 | ||
560 | 37 | QString = str | ||
561 | 38 | |||
562 | 39 | lazy_import(globals(), ''' | 43 | lazy_import(globals(), ''' |
563 | 40 | import errno | ||
564 | 41 | import re | ||
565 | 42 | import time | ||
566 | 43 | import sys | ||
567 | 44 | import os | ||
568 | 45 | import glob | ||
569 | 46 | from patiencediff import PatienceSequenceMatcher as SequenceMatcher | 44 | from patiencediff import PatienceSequenceMatcher as SequenceMatcher |
570 | 47 | from breezy.plugins.qbrz.lib.i18n import gettext, ngettext, N_ | 45 | from breezy.plugins.qbrz.lib.i18n import gettext, ngettext, N_ |
571 | 48 | from breezy import trace, osutils, cmdline | ||
572 | 49 | from breezy.workingtree import WorkingTree | 46 | from breezy.workingtree import WorkingTree |
573 | 50 | from breezy.trace import mutter | 47 | from breezy.trace import mutter |
574 | 51 | ''') | 48 | ''') |
575 | @@ -78,10 +75,9 @@ | |||
576 | 78 | parent_window.windows.append(window) | 75 | parent_window.windows.append(window) |
577 | 79 | elif context: | 76 | elif context: |
578 | 80 | ext_diff = str(ext_diff) # convert QString to str | 77 | ext_diff = str(ext_diff) # convert QString to str |
581 | 81 | cleanup = [] | 78 | with ExitStack() as es: |
580 | 82 | try: | ||
582 | 83 | args = arg_provider.get_diff_window_args( | 79 | args = arg_provider.get_diff_window_args( |
584 | 84 | QtWidgets.QApplication.processEvents, cleanup.append | 80 | QtWidgets.QApplication.processEvents, es |
585 | 85 | ) | 81 | ) |
586 | 86 | old_tree = args["old_tree"] | 82 | old_tree = args["old_tree"] |
587 | 87 | new_tree = args["new_tree"] | 83 | new_tree = args["new_tree"] |
588 | @@ -91,9 +87,6 @@ | |||
589 | 91 | context.diff_paths(specific_files) | 87 | context.diff_paths(specific_files) |
590 | 92 | else: | 88 | else: |
591 | 93 | context.diff_tree() | 89 | context.diff_tree() |
592 | 94 | finally: | ||
593 | 95 | while cleanup: | ||
594 | 96 | cleanup.pop()() | ||
595 | 97 | 90 | ||
596 | 98 | else: | 91 | else: |
597 | 99 | args=["diff", "--using", ext_diff] # NEVER USE --using=xxx, ALWAYS --using xxx | 92 | args=["diff", "--using", ext_diff] # NEVER USE --using=xxx, ALWAYS --using xxx |
598 | @@ -188,11 +181,10 @@ | |||
599 | 188 | """ | 181 | """ |
600 | 189 | RJLRJL: updated to call .iter_changes directly | 182 | RJLRJL: updated to call .iter_changes directly |
601 | 190 | """ | 183 | """ |
604 | 191 | try: | 184 | with ExitStack() as es: |
603 | 192 | cleanup = [] | ||
605 | 193 | if lock_trees: | 185 | if lock_trees: |
606 | 194 | for t in trees: | 186 | for t in trees: |
608 | 195 | cleanup.append(t.lock_read().unlock) | 187 | es.enter_context(t.lock_read()) |
609 | 196 | 188 | ||
610 | 197 | # changes = trees[1].iter_changes(trees[0], specific_files=specific_files, require_versioned=True) | 189 | # changes = trees[1].iter_changes(trees[0], specific_files=specific_files, require_versioned=True) |
611 | 198 | 190 | ||
612 | @@ -215,9 +207,6 @@ | |||
613 | 215 | if not di: | 207 | if not di: |
614 | 216 | continue | 208 | continue |
615 | 217 | yield di | 209 | yield di |
616 | 218 | finally: | ||
617 | 219 | while cleanup: | ||
618 | 220 | cleanup.pop()() | ||
619 | 221 | 210 | ||
620 | 222 | @classmethod | 211 | @classmethod |
621 | 223 | def create(cls, trees, file_id, paths, changed_content, versioned, | 212 | def create(cls, trees, file_id, paths, changed_content, versioned, |
622 | @@ -588,17 +577,13 @@ | |||
623 | 588 | NOTE: Directories cannot be specified. | 577 | NOTE: Directories cannot be specified. |
624 | 589 | Use diff_tree or diff_paths instead when specifing directory. | 578 | Use diff_tree or diff_paths instead when specifing directory. |
625 | 590 | """ | 579 | """ |
628 | 591 | cleanup = [] | 580 | with ExitStack() as es: |
627 | 592 | try: | ||
629 | 593 | if lock_trees: | 581 | if lock_trees: |
632 | 594 | cleanup.append(self._differ.new_tree.lock_read().unlock) | 582 | es.enter_context(self._differ.new_tree.lock_read()) |
633 | 595 | cleanup.append(self._differ.old_tree.lock_read().unlock) | 583 | es.enter_context(self._differ.old_tree.lock_read()) |
634 | 596 | for file_id in file_ids: | 584 | for file_id in file_ids: |
635 | 597 | self._differ.diff(file_id) | 585 | self._differ.diff(file_id) |
636 | 598 | time.sleep(interval * 0.001) | 586 | time.sleep(interval * 0.001) |
637 | 599 | finally: | ||
638 | 600 | while cleanup: | ||
639 | 601 | cleanup.pop()() | ||
640 | 602 | 587 | ||
641 | 603 | def diff_paths(self, paths, interval=50, lock_trees=True): | 588 | def diff_paths(self, paths, interval=50, lock_trees=True): |
642 | 604 | """ | 589 | """ |
643 | @@ -610,12 +595,11 @@ | |||
644 | 610 | valid_paths = [] | 595 | valid_paths = [] |
645 | 611 | ids = [] | 596 | ids = [] |
646 | 612 | dir_included = False | 597 | dir_included = False |
649 | 613 | cleanup = [] | 598 | with ExitStack() as es: |
648 | 614 | try: | ||
650 | 615 | # Sometimes, we must lock tree before calling tree.kind() | 599 | # Sometimes, we must lock tree before calling tree.kind() |
651 | 616 | if lock_trees: | 600 | if lock_trees: |
654 | 617 | cleanup.append(new_tree.lock_read().unlock) | 601 | es.enter_context(new_tree.lock_read()) |
655 | 618 | cleanup.append(old_tree.lock_read().unlock) | 602 | es.enter_context(old_tree.lock_read()) |
656 | 619 | for p in paths: | 603 | for p in paths: |
657 | 620 | id = new_tree.path2id(p) | 604 | id = new_tree.path2id(p) |
658 | 621 | if id: | 605 | if id: |
659 | @@ -630,9 +614,6 @@ | |||
660 | 630 | self.diff_tree(valid_paths, interval, False) | 614 | self.diff_tree(valid_paths, interval, False) |
661 | 631 | else: | 615 | else: |
662 | 632 | self.diff_ids(ids, interval, False) | 616 | self.diff_ids(ids, interval, False) |
663 | 633 | finally: | ||
664 | 634 | while cleanup: | ||
665 | 635 | cleanup.pop()() | ||
666 | 636 | 617 | ||
667 | 637 | def diff_tree(self, specific_files=None, interval=50, lock_trees=True): | 618 | def diff_tree(self, specific_files=None, interval=50, lock_trees=True): |
668 | 638 | """ | 619 | """ |
669 | 639 | 620 | ||
670 | === modified file 'lib/diff_arg.py' | |||
671 | --- lib/diff_arg.py 2017-09-11 06:53:22 +0000 | |||
672 | +++ lib/diff_arg.py 2022-07-06 15:37:54 +0000 | |||
673 | @@ -30,7 +30,7 @@ | |||
674 | 30 | """Contract class to pass arguments to either builtin diff window, or | 30 | """Contract class to pass arguments to either builtin diff window, or |
675 | 31 | external diffs""" | 31 | external diffs""" |
676 | 32 | 32 | ||
678 | 33 | def get_diff_window_args(self, processEvents, add_cleanup): | 33 | def get_diff_window_args(self, processEvents, es): |
679 | 34 | """Returns the arguments for the builtin diff window. | 34 | """Returns the arguments for the builtin diff window. |
680 | 35 | 35 | ||
681 | 36 | :return: {"old_tree": old_tree, | 36 | :return: {"old_tree": old_tree, |
682 | @@ -52,7 +52,7 @@ | |||
683 | 52 | 52 | ||
684 | 53 | class InternalDiffArgProvider(DiffArgProvider): | 53 | class InternalDiffArgProvider(DiffArgProvider): |
685 | 54 | """Use for passing arguments from internal source.""" | 54 | """Use for passing arguments from internal source.""" |
687 | 55 | 55 | ||
688 | 56 | def __init__(self, | 56 | def __init__(self, |
689 | 57 | old_revid, new_revid, | 57 | old_revid, new_revid, |
690 | 58 | old_branch, new_branch, | 58 | old_branch, new_branch, |
691 | @@ -67,7 +67,7 @@ | |||
692 | 67 | 67 | ||
693 | 68 | self.old_tree = old_tree | 68 | self.old_tree = old_tree |
694 | 69 | self.new_tree = new_tree | 69 | self.new_tree = new_tree |
696 | 70 | 70 | ||
697 | 71 | def need_to_load_paths(self): | 71 | def need_to_load_paths(self): |
698 | 72 | return self.specific_file_ids is not None \ | 72 | return self.specific_file_ids is not None \ |
699 | 73 | and self.specific_files is None | 73 | and self.specific_files is None |
700 | @@ -83,14 +83,11 @@ | |||
701 | 83 | self.new_branch.repository.revision_tree(self.new_revid) | 83 | self.new_branch.repository.revision_tree(self.new_revid) |
702 | 84 | 84 | ||
703 | 85 | if self.need_to_load_paths(): | 85 | if self.need_to_load_paths(): |
706 | 86 | self.new_tree.lock_read() | 86 | with self.new_tree.lock_read(): |
705 | 87 | try: | ||
707 | 88 | self.specific_files = [self.new_tree.id2path(id) \ | 87 | self.specific_files = [self.new_tree.id2path(id) \ |
708 | 89 | for id in self.specific_file_ids] | 88 | for id in self.specific_file_ids] |
709 | 90 | finally: | ||
710 | 91 | self.new_tree.unlock() | ||
711 | 92 | 89 | ||
713 | 93 | def get_diff_window_args(self, processEvents, add_cleanup): | 90 | def get_diff_window_args(self, processEvents, es): |
714 | 94 | self.load_old_tree() | 91 | self.load_old_tree() |
715 | 95 | processEvents() | 92 | processEvents() |
716 | 96 | self.load_new_tree_and_paths() | 93 | self.load_new_tree_and_paths() |
717 | @@ -107,11 +104,11 @@ | |||
718 | 107 | if revid.startswith(CURRENT_REVISION): | 104 | if revid.startswith(CURRENT_REVISION): |
719 | 108 | return '' | 105 | return '' |
720 | 109 | return 'revid:%s' % revid | 106 | return 'revid:%s' % revid |
722 | 110 | 107 | ||
723 | 111 | return "-r%s..%s" % ( | 108 | return "-r%s..%s" % ( |
724 | 112 | get_revspec_part(self.old_revid), | 109 | get_revspec_part(self.old_revid), |
725 | 113 | get_revspec_part(self.new_revid)) | 110 | get_revspec_part(self.new_revid)) |
727 | 114 | 111 | ||
728 | 115 | def get_ext_diff_args(self, processEvents): | 112 | def get_ext_diff_args(self, processEvents): |
729 | 116 | from breezy import urlutils | 113 | from breezy import urlutils |
730 | 117 | from breezy import errors | 114 | from breezy import errors |
731 | @@ -177,7 +174,7 @@ | |||
732 | 177 | else: | 174 | else: |
733 | 178 | InternalDiffArgProvider.load_old_tree(self) | 175 | InternalDiffArgProvider.load_old_tree(self) |
734 | 179 | 176 | ||
736 | 180 | def get_diff_window_args(self, processEvents, add_cleanup): | 177 | def get_diff_window_args(self, processEvents, es): |
737 | 181 | self.load_old_tree() | 178 | self.load_old_tree() |
738 | 182 | processEvents() | 179 | processEvents() |
739 | 183 | 180 | ||
740 | 184 | 181 | ||
741 | === modified file 'lib/diffview.py' | |||
742 | --- lib/diffview.py 2022-01-08 10:52:49 +0000 | |||
743 | +++ lib/diffview.py 2022-07-06 15:37:54 +0000 | |||
744 | @@ -295,7 +295,7 @@ | |||
745 | 295 | def adjust_range(self): | 295 | def adjust_range(self): |
746 | 296 | page_step = self.browsers[0].verticalScrollBar().pageStep() | 296 | page_step = self.browsers[0].verticalScrollBar().pageStep() |
747 | 297 | self.setPageStep(page_step) | 297 | self.setPageStep(page_step) |
749 | 298 | self.setRange(0, self.total_length - page_step + 4) | 298 | self.setRange(0, int(self.total_length - page_step + 4)) |
750 | 299 | self.setVisible(self.total_length > page_step) | 299 | self.setVisible(self.total_length > page_step) |
751 | 300 | 300 | ||
752 | 301 | def get_position_info(self, target): | 301 | def get_position_info(self, target): |
753 | 302 | 302 | ||
754 | === modified file 'lib/diffwindow.py' | |||
755 | --- lib/diffwindow.py 2022-01-08 11:48:59 +0000 | |||
756 | +++ lib/diffwindow.py 2022-07-06 15:37:54 +0000 | |||
757 | @@ -20,6 +20,7 @@ | |||
758 | 20 | # along with this program; if not, write to the Free Software | 20 | # along with this program; if not, write to the Free Software |
759 | 21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
760 | 22 | 22 | ||
761 | 23 | from contextlib import ExitStack | ||
762 | 23 | import errno | 24 | import errno |
763 | 24 | import re | 25 | import re |
764 | 25 | import time | 26 | import time |
765 | @@ -35,8 +36,6 @@ | |||
766 | 35 | from breezy.workingtree import WorkingTree | 36 | from breezy.workingtree import WorkingTree |
767 | 36 | from breezy.bzr.workingtree_4 import DirStateRevisionTree | 37 | from breezy.bzr.workingtree_4 import DirStateRevisionTree |
768 | 37 | from breezy import trace | 38 | from breezy import trace |
769 | 38 | # from breezy import cleanup | ||
770 | 39 | from breezy.plugins.qbrz.lib import cleanup | ||
771 | 40 | 39 | ||
772 | 41 | from breezy.plugins.qbrz.lib.diffview import ( | 40 | from breezy.plugins.qbrz.lib.diffview import ( |
773 | 42 | SidebySideDiffView, | 41 | SidebySideDiffView, |
774 | @@ -345,16 +344,13 @@ | |||
775 | 345 | throbber window, then loads the branches etc if they weren't specified | 344 | throbber window, then loads the branches etc if they weren't specified |
776 | 346 | in our constructor. | 345 | in our constructor. |
777 | 347 | """ | 346 | """ |
782 | 348 | op = cleanup.OperationWithCleanups(self._initial_load) | 347 | with ExitStack() as es: |
783 | 349 | self.throbber.show() | 348 | es.callback(self.throbber.hide) |
784 | 350 | op.add_cleanup(self.throbber.hide) | 349 | self.throbber.show() |
785 | 351 | op.run() | 350 | self._initial_load(es) |
786 | 352 | 351 | ||
792 | 353 | def _initial_load(self, op): | 352 | def _initial_load(self, es): |
793 | 354 | # RJL Breezy expects a context handler of some type | 353 | args = self.arg_provider.get_diff_window_args(self.processEvents, es) |
789 | 355 | exit_stack = contextlib.ExitStack() | ||
790 | 356 | args = self.arg_provider.get_diff_window_args(self.processEvents, exit_stack) | ||
791 | 357 | # args = self.arg_provider.get_diff_window_args(self.processEvents, op.add_cleanup) | ||
794 | 358 | 354 | ||
795 | 359 | self.trees = (args["old_tree"], args["new_tree"]) | 355 | self.trees = (args["old_tree"], args["new_tree"]) |
796 | 360 | self.branches = (args.get("old_branch", None), args.get("new_branch",None)) | 356 | self.branches = (args.get("old_branch", None), args.get("new_branch",None)) |
797 | 361 | 357 | ||
798 | === modified file 'lib/extra/isignored.py' | |||
799 | --- lib/extra/isignored.py 2019-10-27 14:48:19 +0000 | |||
800 | +++ lib/extra/isignored.py 2022-07-06 15:37:54 +0000 | |||
801 | @@ -33,7 +33,7 @@ | |||
802 | 33 | 33 | ||
803 | 34 | def run(self, filename): | 34 | def run(self, filename): |
804 | 35 | tree, relpath = workingtree.WorkingTree.open_containing(filename) | 35 | tree, relpath = workingtree.WorkingTree.open_containing(filename) |
806 | 36 | if tree.is_ignored(relpath) and not tree.path2id(relpath): | 36 | if tree.is_ignored(relpath) and not tree.is_versioned(relpath): |
807 | 37 | if not trace.is_quiet(): | 37 | if not trace.is_quiet(): |
808 | 38 | print('ignored', file=self.outf) | 38 | print('ignored', file=self.outf) |
809 | 39 | return 1 | 39 | return 1 |
810 | 40 | 40 | ||
811 | === modified file 'lib/extra/isversioned.py' | |||
812 | --- lib/extra/isversioned.py 2019-10-27 14:48:19 +0000 | |||
813 | +++ lib/extra/isversioned.py 2022-07-06 15:37:54 +0000 | |||
814 | @@ -33,7 +33,7 @@ | |||
815 | 33 | 33 | ||
816 | 34 | def run(self, filename): | 34 | def run(self, filename): |
817 | 35 | tree, relpath = workingtree.WorkingTree.open_containing(filename) | 35 | tree, relpath = workingtree.WorkingTree.open_containing(filename) |
819 | 36 | if tree.path2id(relpath): | 36 | if tree.is_versioned(relpath): |
820 | 37 | if not trace.is_quiet(): | 37 | if not trace.is_quiet(): |
821 | 38 | print('versioned', file=self.outf) | 38 | print('versioned', file=self.outf) |
822 | 39 | return 1 | 39 | return 1 |
823 | 40 | 40 | ||
824 | === modified file 'lib/lazycachedrevloader.py' | |||
825 | --- lib/lazycachedrevloader.py 2021-01-05 13:03:34 +0000 | |||
826 | +++ lib/lazycachedrevloader.py 2022-07-06 15:37:54 +0000 | |||
827 | @@ -37,13 +37,13 @@ | |||
828 | 37 | before_batch_load = None, | 37 | before_batch_load = None, |
829 | 38 | revisions_loaded = None, | 38 | revisions_loaded = None, |
830 | 39 | pass_prev_loaded_rev = False): | 39 | pass_prev_loaded_rev = False): |
832 | 40 | 40 | ||
833 | 41 | start_time = time.process_time() | 41 | start_time = time.process_time() |
834 | 42 | showed_throbber = False | 42 | showed_throbber = False |
835 | 43 | revids = [revid for revid in revids if not revid == "root:"] | 43 | revids = [revid for revid in revids if not revid == "root:"] |
836 | 44 | return_revisions = {} | 44 | return_revisions = {} |
837 | 45 | throbber = current_throbber() | 45 | throbber = current_throbber() |
839 | 46 | 46 | ||
840 | 47 | try: | 47 | try: |
841 | 48 | for revid in [revid for revid in revids | 48 | for revid in [revid for revid in revids |
842 | 49 | if revid in cached_revisions]: | 49 | if revid in cached_revisions]: |
843 | @@ -51,7 +51,7 @@ | |||
844 | 51 | if pass_prev_loaded_rev: | 51 | if pass_prev_loaded_rev: |
845 | 52 | if revisions_loaded is not None: | 52 | if revisions_loaded is not None: |
846 | 53 | revisions_loaded(return_revisions, False) | 53 | revisions_loaded(return_revisions, False) |
848 | 54 | 54 | ||
849 | 55 | revs_loaded = {} | 55 | revs_loaded = {} |
850 | 56 | revids = [revid for revid in revids if revid not in cached_revisions] | 56 | revids = [revid for revid in revids if revid not in cached_revisions] |
851 | 57 | if revids: | 57 | if revids: |
852 | @@ -59,24 +59,23 @@ | |||
853 | 59 | repo_revids=((repo, revids),) | 59 | repo_revids=((repo, revids),) |
854 | 60 | else: | 60 | else: |
855 | 61 | repo_revids = repo(revids) | 61 | repo_revids = repo(revids) |
857 | 62 | 62 | ||
858 | 63 | for repo, revids in repo_revids: | 63 | for repo, revids in repo_revids: |
859 | 64 | repo_is_local = isinstance(repo.controldir.transport, LocalTransport) | 64 | repo_is_local = isinstance(repo.controldir.transport, LocalTransport) |
860 | 65 | if repo_is_local: | 65 | if repo_is_local: |
861 | 66 | batch_size = local_batch_size | 66 | batch_size = local_batch_size |
862 | 67 | else: | 67 | else: |
863 | 68 | batch_size = remote_batch_size | 68 | batch_size = remote_batch_size |
865 | 69 | 69 | ||
866 | 70 | if revids: | 70 | if revids: |
869 | 71 | repo.lock_read() | 71 | with repo.lock_read(): |
868 | 72 | try: | ||
870 | 73 | if not repo_is_local: | 72 | if not repo_is_local: |
871 | 74 | update_ui() | 73 | update_ui() |
873 | 75 | 74 | ||
874 | 76 | for offset in range(0, len(revids), batch_size): | 75 | for offset in range(0, len(revids), batch_size): |
876 | 77 | 76 | ||
877 | 78 | running_time = time.process_time() - start_time | 77 | running_time = time.process_time() - start_time |
879 | 79 | 78 | ||
880 | 80 | if time_before_first_ui_update < running_time: | 79 | if time_before_first_ui_update < running_time: |
881 | 81 | if revisions_loaded is not None: | 80 | if revisions_loaded is not None: |
882 | 82 | revisions_loaded(revs_loaded, False) | 81 | revisions_loaded(revs_loaded, False) |
883 | @@ -86,28 +85,26 @@ | |||
884 | 86 | throbber.show() | 85 | throbber.show() |
885 | 87 | showed_throbber = True | 86 | showed_throbber = True |
886 | 88 | update_ui() | 87 | update_ui() |
888 | 89 | 88 | ||
889 | 90 | batch_revids = revids[offset:offset+batch_size] | 89 | batch_revids = revids[offset:offset+batch_size] |
891 | 91 | 90 | ||
892 | 92 | if before_batch_load is not None: | 91 | if before_batch_load is not None: |
893 | 93 | stop = before_batch_load(repo, batch_revids) | 92 | stop = before_batch_load(repo, batch_revids) |
894 | 94 | if stop: | 93 | if stop: |
895 | 95 | break | 94 | break |
897 | 96 | 95 | ||
898 | 97 | for rev in repo.get_revisions(batch_revids): | 96 | for rev in repo.get_revisions(batch_revids): |
899 | 98 | cached_revisions[rev.revision_id] = rev | 97 | cached_revisions[rev.revision_id] = rev |
900 | 99 | return_revisions[rev.revision_id] = rev | 98 | return_revisions[rev.revision_id] = rev |
901 | 100 | revs_loaded[rev.revision_id] = rev | 99 | revs_loaded[rev.revision_id] = rev |
902 | 101 | rev.repository = repo | 100 | rev.repository = repo |
906 | 102 | finally: | 101 | |
904 | 103 | repo.unlock() | ||
905 | 104 | |||
907 | 105 | if revisions_loaded is not None: | 102 | if revisions_loaded is not None: |
908 | 106 | revisions_loaded(revs_loaded, True) | 103 | revisions_loaded(revs_loaded, True) |
909 | 107 | finally: | 104 | finally: |
910 | 108 | if showed_throbber: | 105 | if showed_throbber: |
911 | 109 | throbber.hide() | 106 | throbber.hide() |
913 | 110 | 107 | ||
914 | 111 | return return_revisions | 108 | return return_revisions |
915 | 112 | 109 | ||
916 | 113 | def update_ui(): | 110 | def update_ui(): |
917 | 114 | 111 | ||
918 | === modified file 'lib/log.py' | |||
919 | --- lib/log.py 2022-01-08 11:48:59 +0000 | |||
920 | +++ lib/log.py 2022-07-06 15:37:54 +0000 | |||
921 | @@ -612,9 +612,8 @@ | |||
922 | 612 | for repo, repo_revids in repos_revids: | 612 | for repo, repo_revids in repos_revids: |
923 | 613 | repo_revids = [revid for revid in repo_revids if revid not in self.tree_cache] | 613 | repo_revids = [revid for revid in repo_revids if revid not in self.tree_cache] |
924 | 614 | if repo_revids: | 614 | if repo_revids: |
928 | 615 | repo.lock_read() | 615 | with repo.lock_read(): |
929 | 616 | self.processEvents() | 616 | self.processEvents() |
927 | 617 | try: | ||
930 | 618 | for revid in repo_revids: | 617 | for revid in repo_revids: |
931 | 619 | if (revid.startswith(CURRENT_REVISION) and gv_is_wtgv): | 618 | if (revid.startswith(CURRENT_REVISION) and gv_is_wtgv): |
932 | 620 | tree = gv.working_trees[revid] | 619 | tree = gv.working_trees[revid] |
933 | @@ -622,8 +621,6 @@ | |||
934 | 622 | tree = repo.revision_tree(revid) | 621 | tree = repo.revision_tree(revid) |
935 | 623 | self.tree_cache[revid] = tree | 622 | self.tree_cache[revid] = tree |
936 | 624 | self.processEvents() | 623 | self.processEvents() |
937 | 625 | finally: | ||
938 | 626 | repo.unlock() | ||
939 | 627 | self.processEvents() | 624 | self.processEvents() |
940 | 628 | 625 | ||
941 | 629 | delta = self.tree_cache[revids[0]].changes_from(self.tree_cache[revids[1]]) | 626 | delta = self.tree_cache[revids[0]].changes_from(self.tree_cache[revids[1]]) |
942 | @@ -830,13 +827,10 @@ | |||
943 | 830 | tree = branch.repository.revision_tree(top_revid) | 827 | tree = branch.repository.revision_tree(top_revid) |
944 | 831 | file_id = file_ids[0] | 828 | file_id = file_ids[0] |
945 | 832 | path = paths[0] | 829 | path = paths[0] |
948 | 833 | tree.lock_read() | 830 | with tree.lock_read(): |
947 | 834 | try: | ||
949 | 835 | kind = tree.kind(path) | 831 | kind = tree.kind(path) |
950 | 836 | if kind == 'file': | 832 | if kind == 'file': |
951 | 837 | file_content_bytes = tree.get_file_text(path) | 833 | file_content_bytes = tree.get_file_text(path) |
952 | 838 | finally: | ||
953 | 839 | tree.unlock() | ||
954 | 840 | if kind != 'file': | 834 | if kind != 'file': |
955 | 841 | QtWidgets.QMessageBox.information(self, gettext("Not a file"), | 835 | QtWidgets.QMessageBox.information(self, gettext("Not a file"), |
956 | 842 | gettext("Operation is supported for a single file only,\n" | 836 | gettext("Operation is supported for a single file only,\n" |
957 | @@ -844,11 +838,8 @@ | |||
958 | 844 | return | 838 | return |
959 | 845 | filename = QtWidgets.QFileDialog.getSaveFileName(self, gettext("Save file in this revision as..."))[0] | 839 | filename = QtWidgets.QFileDialog.getSaveFileName(self, gettext("Save file in this revision as..."))[0] |
960 | 846 | if filename: | 840 | if filename: |
963 | 847 | f = open(str(filename), 'wb') | 841 | with open(str(filename), 'wb') as f: |
962 | 848 | try: | ||
964 | 849 | f.write(file_content_bytes) | 842 | f.write(file_content_bytes) |
965 | 850 | finally: | ||
966 | 851 | f.close() | ||
967 | 852 | 843 | ||
968 | 853 | @ui_current_widget | 844 | @ui_current_widget |
969 | 854 | def revert_file(self): | 845 | def revert_file(self): |
970 | 855 | 846 | ||
971 | === modified file 'lib/loggraphviz.py' | |||
972 | --- lib/loggraphviz.py 2021-08-05 11:27:16 +0000 | |||
973 | +++ lib/loggraphviz.py 2022-07-06 15:37:54 +0000 | |||
974 | @@ -219,7 +219,6 @@ | |||
975 | 219 | finally: | 219 | finally: |
976 | 220 | self.unlock_branches() | 220 | self.unlock_branches() |
977 | 221 | 221 | ||
978 | 222 | |||
979 | 223 | def load_current_dir_repo(self): | 222 | def load_current_dir_repo(self): |
980 | 224 | # There are no local repositories. Try open the repository | 223 | # There are no local repositories. Try open the repository |
981 | 225 | # of the current directory, and try load revisions data from | 224 | # of the current directory, and try load revisions data from |
982 | @@ -1050,13 +1049,10 @@ | |||
983 | 1050 | return_revisions = {} | 1049 | return_revisions = {} |
984 | 1051 | for repo, revids in self.get_repo_revids(revids): | 1050 | for repo, revids in self.get_repo_revids(revids): |
985 | 1052 | if revids: | 1051 | if revids: |
988 | 1053 | repo.lock_read() | 1052 | with repo.lock_read(): |
987 | 1054 | try: | ||
989 | 1055 | self.update_ui() | 1053 | self.update_ui() |
990 | 1056 | for rev in repo.get_revisions(revids): | 1054 | for rev in repo.get_revisions(revids): |
991 | 1057 | return_revisions[rev.revision_id] = rev | 1055 | return_revisions[rev.revision_id] = rev |
992 | 1058 | finally: | ||
993 | 1059 | repo.unlock() | ||
994 | 1060 | return return_revisions | 1056 | return return_revisions |
995 | 1061 | 1057 | ||
996 | 1062 | 1058 | ||
997 | @@ -1443,8 +1439,7 @@ | |||
998 | 1443 | if tree is None: | 1439 | if tree is None: |
999 | 1444 | tree = bi.branch.basis_tree() | 1440 | tree = bi.branch.basis_tree() |
1000 | 1445 | 1441 | ||
1003 | 1446 | tree.lock_read() | 1442 | with tree.lock_read(): |
1002 | 1447 | try: | ||
1004 | 1448 | for file_id in self.file_ids: | 1443 | for file_id in self.file_ids: |
1005 | 1449 | if tree.kind(tree.id2path(file_id)) in ('directory', | 1444 | if tree.kind(tree.id2path(file_id)) in ('directory', |
1006 | 1450 | 'tree-reference'): | 1445 | 'tree-reference'): |
1007 | @@ -1452,8 +1447,6 @@ | |||
1008 | 1452 | break | 1447 | break |
1009 | 1453 | if self.has_dir: | 1448 | if self.has_dir: |
1010 | 1454 | break | 1449 | break |
1011 | 1455 | finally: | ||
1012 | 1456 | tree.unlock() | ||
1013 | 1457 | 1450 | ||
1014 | 1458 | if revids is None: | 1451 | if revids is None: |
1015 | 1459 | revids = [rev.revid for rev in self.graph_viz.revisions] | 1452 | revids = [rev.revid for rev in self.graph_viz.revisions] |
1016 | @@ -1485,8 +1478,7 @@ | |||
1017 | 1485 | self.filter_changed_callback(changed_revs, False) | 1478 | self.filter_changed_callback(changed_revs, False) |
1018 | 1486 | self.graph_viz.update_ui() | 1479 | self.graph_viz.update_ui() |
1019 | 1487 | 1480 | ||
1022 | 1488 | repo.lock_read() | 1481 | with repo.lock_read(): |
1021 | 1489 | try: | ||
1023 | 1490 | if not self.uses_inventory(): | 1482 | if not self.uses_inventory(): |
1024 | 1491 | text_keys = [(file_id, revid) | 1483 | text_keys = [(file_id, revid) |
1025 | 1492 | for revid in revids | 1484 | for revid in revids |
1026 | @@ -1508,8 +1500,6 @@ | |||
1027 | 1508 | self.graph_viz.update_ui() | 1500 | self.graph_viz.update_ui() |
1028 | 1509 | 1501 | ||
1029 | 1510 | check_text_keys(text_keys) | 1502 | check_text_keys(text_keys) |
1030 | 1511 | finally: | ||
1031 | 1512 | repo.unlock() | ||
1032 | 1513 | 1503 | ||
1033 | 1514 | def load_filter_file_id_chunk_finished(self): | 1504 | def load_filter_file_id_chunk_finished(self): |
1034 | 1515 | self.filter_changed_callback([], True) | 1505 | self.filter_changed_callback([], True) |
1035 | @@ -1555,8 +1545,7 @@ | |||
1036 | 1555 | 1545 | ||
1037 | 1556 | :return: True if a change is found. False otherwise | 1546 | :return: True if a change is found. False otherwise |
1038 | 1557 | """ | 1547 | """ |
1041 | 1558 | tree.lock_read() | 1548 | with tree.lock_read(): |
1040 | 1559 | try: | ||
1042 | 1560 | # Copied from mutabletree, cause we need file_ids too. | 1549 | # Copied from mutabletree, cause we need file_ids too. |
1043 | 1561 | # Check pending merges | 1550 | # Check pending merges |
1044 | 1562 | if len(tree.get_parent_ids()) > 1: | 1551 | if len(tree.get_parent_ids()) > 1: |
1045 | @@ -1579,8 +1568,6 @@ | |||
1046 | 1579 | except StopIteration: | 1568 | except StopIteration: |
1047 | 1580 | # No changes | 1569 | # No changes |
1048 | 1581 | return False | 1570 | return False |
1049 | 1582 | finally: | ||
1050 | 1583 | tree.unlock() | ||
1051 | 1584 | 1571 | ||
1052 | 1585 | def get_revision_visible(self, rev): | 1572 | def get_revision_visible(self, rev): |
1053 | 1586 | if rev.revid.startswith(CURRENT_REVISION): | 1573 | if rev.revid.startswith(CURRENT_REVISION): |
1054 | 1587 | 1574 | ||
1055 | === modified file 'lib/spellcheck_enchant.py' | |||
1056 | --- lib/spellcheck_enchant.py 2019-10-27 14:48:19 +0000 | |||
1057 | +++ lib/spellcheck_enchant.py 2022-07-06 15:37:54 +0000 | |||
1058 | @@ -30,7 +30,7 @@ | |||
1059 | 30 | text = self._text[offset:] | 30 | text = self._text[offset:] |
1060 | 31 | if not text: | 31 | if not text: |
1061 | 32 | raise StopIteration() | 32 | raise StopIteration() |
1063 | 33 | match = re.match('(\w+?)[A-Z]', text) | 33 | match = re.match(br'(\w+?)[A-Z]', text) |
1064 | 34 | if match is None: | 34 | if match is None: |
1065 | 35 | word = text | 35 | word = text |
1066 | 36 | else: | 36 | else: |
1067 | @@ -60,7 +60,7 @@ | |||
1068 | 60 | self.checker.set_text(text) | 60 | self.checker.set_text(text) |
1069 | 61 | for err in self.checker: | 61 | for err in self.checker: |
1070 | 62 | yield err.wordpos, len(err.word) | 62 | yield err.wordpos, len(err.word) |
1072 | 63 | 63 | ||
1073 | 64 | def suggest(self, text): | 64 | def suggest(self, text): |
1074 | 65 | return self.dict.suggest(text) | 65 | return self.dict.suggest(text) |
1075 | 66 | 66 | ||
1076 | 67 | 67 | ||
1077 | === modified file 'lib/subprocess.py' | |||
1078 | --- lib/subprocess.py 2022-04-14 11:45:16 +0000 | |||
1079 | +++ lib/subprocess.py 2022-07-06 15:37:54 +0000 | |||
1080 | @@ -847,12 +847,9 @@ | |||
1081 | 847 | if not os.path.isdir(qdir): | 847 | if not os.path.isdir(qdir): |
1082 | 848 | os.makedirs(qdir) | 848 | os.makedirs(qdir) |
1083 | 849 | fd, fname = tempfile.mkstemp(dir=qdir) | 849 | fd, fname = tempfile.mkstemp(dir=qdir) |
1086 | 850 | f = os.fdopen(fd, "wb") | 850 | with os.fdopen(fd, "wb") as f: |
1085 | 851 | try: | ||
1087 | 852 | # f.write(text.decode('utf8')) | 851 | # f.write(text.decode('utf8')) |
1088 | 853 | f.write(text) | 852 | f.write(text) |
1089 | 854 | finally: | ||
1090 | 855 | f.close() # it closes fd as well | ||
1091 | 856 | self._args_file = fname | 853 | self._args_file = fname |
1092 | 857 | return fname | 854 | return fname |
1093 | 858 | 855 | ||
1094 | @@ -1074,11 +1071,8 @@ | |||
1095 | 1074 | if s_cmd[0][0] == '@': | 1071 | if s_cmd[0][0] == '@': |
1096 | 1075 | fname = s_cmd[1:] | 1072 | fname = s_cmd[1:] |
1097 | 1076 | # Changed this: it's written in 'b' so must be read that way too | 1073 | # Changed this: it's written in 'b' so must be read that way too |
1100 | 1077 | f = open(fname, 'rb') | 1074 | with open(fname, 'rb') as f: |
1099 | 1078 | try: | ||
1101 | 1079 | s_cmd = f.read() | 1075 | s_cmd = f.read() |
1102 | 1080 | finally: | ||
1103 | 1081 | f.close() | ||
1104 | 1082 | # We stored a bencoded string like b'l6:ignore18:qbrz-setup-iss.loge', so...: | 1076 | # We stored a bencoded string like b'l6:ignore18:qbrz-setup-iss.loge', so...: |
1105 | 1083 | s_cmd = bencode.bdecode(s_cmd) | 1077 | s_cmd = bencode.bdecode(s_cmd) |
1106 | 1084 | # ...and again, sometimes we get a list like [b'ignore', b'qbrz-setup-iss.log'], so... | 1078 | # ...and again, sometimes we get a list like [b'ignore', b'qbrz-setup-iss.log'], so... |
1107 | 1085 | 1079 | ||
1108 | === modified file 'lib/tests/test_extdiff.py' | |||
1109 | --- lib/tests/test_extdiff.py 2020-07-05 15:21:39 +0000 | |||
1110 | +++ lib/tests/test_extdiff.py 2022-07-06 15:37:54 +0000 | |||
1111 | @@ -25,11 +25,11 @@ | |||
1112 | 25 | 25 | ||
1113 | 26 | def test_no_arguments(self): | 26 | def test_no_arguments(self): |
1114 | 27 | self.differ.set_command_string("test") | 27 | self.differ.set_command_string("test") |
1116 | 28 | self.assertEqual(self.differ.command_template, ["test", "@old_path", "@new_path"]) | 28 | self.assertEqual(self.differ.command_template, ["test", "{old_path}", "{new_path}"]) |
1117 | 29 | 29 | ||
1118 | 30 | def test_has_arguments(self): | 30 | def test_has_arguments(self): |
1121 | 31 | self.differ.set_command_string("test --old @old_path --new @new_path") | 31 | self.differ.set_command_string("test --old {old_path} --new {new_path}") |
1122 | 32 | self.assertEqual(self.differ.command_template, ["test", "--old", "@old_path", "--new", "@new_path"]) | 32 | self.assertEqual(self.differ.command_template, ["test", "--old", "{old_path}", "--new", "{new_path}"]) |
1123 | 33 | 33 | ||
1124 | 34 | class TestPrefix(QTestCase): | 34 | class TestPrefix(QTestCase): |
1125 | 35 | def setUp(self): | 35 | def setUp(self): |
1126 | @@ -221,7 +221,7 @@ | |||
1127 | 221 | def assertPopen(self, paths, old_contents): | 221 | def assertPopen(self, paths, old_contents): |
1128 | 222 | for args, path, old_content in zip(self.popen_mock.args, paths, old_contents): | 222 | for args, path, old_content in zip(self.popen_mock.args, paths, old_contents): |
1129 | 223 | # tool, old_path, new_path = args[0][0] | 223 | # tool, old_path, new_path = args[0][0] |
1131 | 224 | tool, _, _, old_path, new_path = args[0][0] | 224 | tool, old_path, new_path = args[0][0] |
1132 | 225 | self.assertEqual(tool, "diff.exe") | 225 | self.assertEqual(tool, "diff.exe") |
1133 | 226 | self.assertFileContent(old_path, old_content) | 226 | self.assertFileContent(old_path, old_content) |
1134 | 227 | self.assertEqual(new_path, self.tree.abspath(path)) | 227 | self.assertEqual(new_path, self.tree.abspath(path)) |
1135 | 228 | 228 | ||
1136 | === modified file 'lib/tests/test_guidebar.py' | |||
1137 | --- lib/tests/test_guidebar.py 2021-01-05 16:26:04 +0000 | |||
1138 | +++ lib/tests/test_guidebar.py 2022-07-06 15:37:54 +0000 | |||
1139 | @@ -24,7 +24,7 @@ | |||
1140 | 24 | def __init__(self, tree): | 24 | def __init__(self, tree): |
1141 | 25 | self.tree = tree | 25 | self.tree = tree |
1142 | 26 | 26 | ||
1144 | 27 | def get_diff_window_args(self, processEvents, add_cleanup): | 27 | def get_diff_window_args(self, processEvents, es): |
1145 | 28 | # This will be used by DiffWindow::_initial_load | 28 | # This will be used by DiffWindow::_initial_load |
1146 | 29 | return dict( | 29 | return dict( |
1147 | 30 | old_tree=self.tree.basis_tree(), | 30 | old_tree=self.tree.basis_tree(), |
1148 | 31 | 31 | ||
1149 | === modified file 'lib/treewidget.py' | |||
1150 | --- lib/treewidget.py 2022-01-08 11:48:59 +0000 | |||
1151 | +++ lib/treewidget.py 2022-07-06 15:37:54 +0000 | |||
1152 | @@ -485,16 +485,10 @@ | |||
1153 | 485 | 485 | ||
1154 | 486 | if isinstance(self.tree, WorkingTree): | 486 | if isinstance(self.tree, WorkingTree): |
1155 | 487 | # print(':::-> tree.lock_read (try) about to execute') | 487 | # print(':::-> tree.lock_read (try) about to execute') |
1162 | 488 | tree.lock_read() | 488 | with tree.lock_read(): |
1157 | 489 | try: | ||
1158 | 490 | # RJL Breezy release notes state that: | ||
1159 | 491 | # | ||
1160 | 492 | # The ``Tree.get_root_id`` method has been removed. Use``Tree.path2id('')`` instead. (Jelmer Vernooij) | ||
1161 | 493 | # | ||
1163 | 494 | root_id = self.tree.path2id('') | 489 | root_id = self.tree.path2id('') |
1164 | 495 | basis_tree = self.tree.basis_tree() | 490 | basis_tree = self.tree.basis_tree() |
1167 | 496 | basis_tree.lock_read() | 491 | with basis_tree.lock_read(): |
1166 | 497 | try: | ||
1168 | 498 | # print(':::->>second try block') | 492 | # print(':::->>second try block') |
1169 | 499 | for the_change in self.tree.iter_changes(basis_tree, want_unversioned=want_unversioned): | 493 | for the_change in self.tree.iter_changes(basis_tree, want_unversioned=want_unversioned): |
1170 | 500 | # iter_changes now seems to appear to return a TreeChange type See Jelmer's 7390. | 494 | # iter_changes now seems to appear to return a TreeChange type See Jelmer's 7390. |
1171 | @@ -641,12 +635,8 @@ | |||
1172 | 641 | dir_fileid = self.tree.path2id(dir_path) | 635 | dir_fileid = self.tree.path2id(dir_path) |
1173 | 642 | # print('\tname setting gave ', item_data, item_data.path, dir_path, name, dir_fileid) | 636 | # print('\tname setting gave ', item_data, item_data.path, dir_path, name, dir_fileid) |
1174 | 643 | item_data.item.name = get_name(dir_fileid, dir_path, item_data.path, item_data.change) | 637 | item_data.item.name = get_name(dir_fileid, dir_path, item_data.path, item_data.change) |
1175 | 644 | finally: | ||
1176 | 645 | basis_tree.unlock() | ||
1177 | 646 | # print('\n\t\t FIRST process_tree...', initial_checked_paths, load_dirs) | 638 | # print('\n\t\t FIRST process_tree...', initial_checked_paths, load_dirs) |
1178 | 647 | self.process_tree(self.working_tree_get_children, initial_checked_paths, load_dirs) | 639 | self.process_tree(self.working_tree_get_children, initial_checked_paths, load_dirs) |
1179 | 648 | finally: | ||
1180 | 649 | tree.unlock() | ||
1181 | 650 | else: | 640 | else: |
1182 | 651 | # print('\n\t\t SECOND process_tree...', initial_checked_paths, load_dirs) | 641 | # print('\n\t\t SECOND process_tree...', initial_checked_paths, load_dirs) |
1183 | 652 | self.process_tree(self.revision_tree_get_children, initial_checked_paths, load_dirs) | 642 | self.process_tree(self.revision_tree_get_children, initial_checked_paths, load_dirs) |
1184 | @@ -1579,11 +1569,8 @@ | |||
1185 | 1579 | self.change_load_filter = change_load_filter | 1569 | self.change_load_filter = change_load_filter |
1186 | 1580 | 1570 | ||
1187 | 1581 | if branch: | 1571 | if branch: |
1190 | 1582 | branch.lock_read() | 1572 | with branch.lock_read(): |
1189 | 1583 | try: | ||
1191 | 1584 | last_revno = branch.last_revision_info()[0] | 1573 | last_revno = branch.last_revision_info()[0] |
1192 | 1585 | finally: | ||
1193 | 1586 | branch.unlock() | ||
1194 | 1587 | self.revno_item_delegate.set_max_revno(last_revno) | 1574 | self.revno_item_delegate.set_max_revno(last_revno) |
1195 | 1588 | # update width uncoditionally because we may change the revno column | 1575 | # update width uncoditionally because we may change the revno column |
1196 | 1589 | self.set_header_width_settings() | 1576 | self.set_header_width_settings() |
1197 | @@ -1656,8 +1643,7 @@ | |||
1198 | 1656 | 1643 | ||
1199 | 1657 | def restore_state(self, state): | 1644 | def restore_state(self, state): |
1200 | 1658 | (checked, expanded, selected, v_scroll) = state | 1645 | (checked, expanded, selected, v_scroll) = state |
1203 | 1659 | self.tree.lock_read() | 1646 | with self.tree.lock_read(): |
1202 | 1660 | try: | ||
1204 | 1661 | if self.tree_model.checkable and checked is not None: | 1647 | if self.tree_model.checkable and checked is not None: |
1205 | 1662 | for (ref, state) in checked: | 1648 | for (ref, state) in checked: |
1206 | 1663 | if not state == QtCore.Qt.PartiallyChecked: | 1649 | if not state == QtCore.Qt.PartiallyChecked: |
1207 | @@ -1679,12 +1665,9 @@ | |||
1208 | 1679 | QtCore.QItemSelectionModel.SelectCurrent | | 1665 | QtCore.QItemSelectionModel.SelectCurrent | |
1209 | 1680 | QtCore.QItemSelectionModel.Rows) | 1666 | QtCore.QItemSelectionModel.Rows) |
1210 | 1681 | self.verticalScrollBar().setValue(v_scroll) | 1667 | self.verticalScrollBar().setValue(v_scroll) |
1211 | 1682 | finally: | ||
1212 | 1683 | self.tree.unlock() | ||
1213 | 1684 | 1668 | ||
1214 | 1685 | def refresh(self): | 1669 | def refresh(self): |
1217 | 1686 | self.tree.lock_read() | 1670 | with self.tree.lock_read(): |
1216 | 1687 | try: | ||
1218 | 1688 | state = self.get_state() | 1671 | state = self.get_state() |
1219 | 1689 | self.tree_model.set_tree(self.tree, self.branch, | 1672 | self.tree_model.set_tree(self.tree, self.branch, |
1220 | 1690 | self.changes_mode, self.want_unversioned, | 1673 | self.changes_mode, self.want_unversioned, |
1221 | @@ -1699,8 +1682,6 @@ | |||
1222 | 1699 | # after every time we do a layout changed. The issue is similar to | 1682 | # after every time we do a layout changed. The issue is similar to |
1223 | 1700 | # http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=236755 | 1683 | # http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=236755 |
1224 | 1701 | self.set_header_width_settings() | 1684 | self.set_header_width_settings() |
1225 | 1702 | finally: | ||
1226 | 1703 | self.tree.unlock() | ||
1227 | 1704 | 1685 | ||
1228 | 1705 | def mousePressEvent(self, event): | 1686 | def mousePressEvent(self, event): |
1229 | 1706 | index = self.indexAt(event.pos()) | 1687 | index = self.indexAt(event.pos()) |
1230 | @@ -1917,11 +1898,8 @@ | |||
1231 | 1917 | item = items[0] | 1898 | item = items[0] |
1232 | 1918 | 1899 | ||
1233 | 1919 | if isinstance(self.tree, WorkingTree): | 1900 | if isinstance(self.tree, WorkingTree): |
1236 | 1920 | self.tree.lock_read() | 1901 | with self.tree.lock_read(): |
1235 | 1921 | try: | ||
1237 | 1922 | abspath = self.tree.abspath(item.path) | 1902 | abspath = self.tree.abspath(item.path) |
1238 | 1923 | finally: | ||
1239 | 1924 | self.tree.unlock() | ||
1240 | 1925 | url = QtCore.QUrl.fromLocalFile(abspath) | 1903 | url = QtCore.QUrl.fromLocalFile(abspath) |
1241 | 1926 | QtGui.QDesktopServices.openUrl(url) | 1904 | QtGui.QDesktopServices.openUrl(url) |
1242 | 1927 | else: | 1905 | else: |
1243 | @@ -2020,11 +1998,8 @@ | |||
1244 | 2020 | QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) | 1998 | QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) |
1245 | 2021 | if res == QtWidgets.QMessageBox.Yes: | 1999 | if res == QtWidgets.QMessageBox.Yes: |
1246 | 2022 | try: | 2000 | try: |
1249 | 2023 | self.tree.lock_write() | 2001 | with self.tree.lock_write(): |
1248 | 2024 | try: | ||
1250 | 2025 | self.tree.revert(paths, self.tree.basis_tree()) | 2002 | self.tree.revert(paths, self.tree.basis_tree()) |
1251 | 2026 | finally: | ||
1252 | 2027 | self.tree.unlock() | ||
1253 | 2028 | except Exception: | 2003 | except Exception: |
1254 | 2029 | report_exception(type=SUB_LOAD_METHOD, window=self.window()) | 2004 | report_exception(type=SUB_LOAD_METHOD, window=self.window()) |
1255 | 2030 | # XXX - it would be good it we could just refresh the selected items | 2005 | # XXX - it would be good it we could just refresh the selected items |
1256 | 2031 | 2006 | ||
1257 | === modified file 'lib/widgets/shelve.py' | |||
1258 | --- lib/widgets/shelve.py 2021-01-06 09:29:35 +0000 | |||
1259 | +++ lib/widgets/shelve.py 2022-07-06 15:37:54 +0000 | |||
1260 | @@ -17,6 +17,8 @@ | |||
1261 | 17 | # along with this program; if not, write to the Free Software | 17 | # along with this program; if not, write to the Free Software |
1262 | 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
1263 | 19 | 19 | ||
1264 | 20 | from contextlib import ExitStack | ||
1265 | 21 | import os | ||
1266 | 20 | import sys, time | 22 | import sys, time |
1267 | 21 | from PyQt5 import QtCore, QtGui, QtWidgets | 23 | from PyQt5 import QtCore, QtGui, QtWidgets |
1268 | 22 | 24 | ||
1269 | @@ -56,8 +58,6 @@ | |||
1270 | 56 | from breezy.shelf import ShelfCreator | 58 | from breezy.shelf import ShelfCreator |
1271 | 57 | from breezy.shelf_ui import Shelver | 59 | from breezy.shelf_ui import Shelver |
1272 | 58 | from breezy.osutils import split_lines | 60 | from breezy.osutils import split_lines |
1273 | 59 | from cStringIO import StringIO | ||
1274 | 60 | import os | ||
1275 | 61 | ''') | 61 | ''') |
1276 | 62 | 62 | ||
1277 | 63 | 63 | ||
1278 | @@ -453,15 +453,14 @@ | |||
1279 | 453 | self.hunk_view.set_tab_width(pixels) | 453 | self.hunk_view.set_tab_width(pixels) |
1280 | 454 | 454 | ||
1281 | 455 | def refresh(self): | 455 | def refresh(self): |
1284 | 456 | cleanup = [] | 456 | with ExitStack() as es: |
1283 | 457 | try: | ||
1285 | 458 | old_rev = self.revision | 457 | old_rev = self.revision |
1286 | 459 | old_changes = self._get_change_dictionary() | 458 | old_changes = self._get_change_dictionary() |
1287 | 460 | self.clear(clear_message = False) | 459 | self.clear(clear_message = False) |
1288 | 461 | 460 | ||
1289 | 462 | shelver, creator = self._create_shelver_and_creator() | 461 | shelver, creator = self._create_shelver_and_creator() |
1292 | 463 | cleanup.append(shelver.finalize) | 462 | es.callback(shelver.finalize) |
1293 | 464 | cleanup.append(creator.finalize) | 463 | es.callback(creator.finalize) |
1294 | 465 | 464 | ||
1295 | 466 | file_list = shelver.file_list | 465 | file_list = shelver.file_list |
1296 | 467 | if file_list: | 466 | if file_list: |
1297 | @@ -489,10 +488,6 @@ | |||
1298 | 489 | item = self._create_item(change, shelver, self.trees, old_changes) | 488 | item = self._create_item(change, shelver, self.trees, old_changes) |
1299 | 490 | self.file_view.addTopLevelItem(item) | 489 | self.file_view.addTopLevelItem(item) |
1300 | 491 | 490 | ||
1301 | 492 | finally: | ||
1302 | 493 | for func in cleanup: | ||
1303 | 494 | func() | ||
1304 | 495 | |||
1305 | 496 | if self.select_all: | 491 | if self.select_all: |
1306 | 497 | self.check_all(True) | 492 | self.check_all(True) |
1307 | 498 | self.select_all = False | 493 | self.select_all = False |
1308 | @@ -625,16 +620,15 @@ | |||
1309 | 625 | self.loaded = False | 620 | self.loaded = False |
1310 | 626 | 621 | ||
1311 | 627 | def use_editor(self): | 622 | def use_editor(self): |
1312 | 628 | cleanup = [] | ||
1313 | 629 | items = self.file_view.selectedItems() | 623 | items = self.file_view.selectedItems() |
1314 | 630 | if len(items) != 1 or items[0].change.status != 'modify text': | 624 | if len(items) != 1 or items[0].change.status != 'modify text': |
1315 | 631 | return | 625 | return |
1316 | 632 | else: | 626 | else: |
1317 | 633 | change = items[0].change | 627 | change = items[0].change |
1319 | 634 | try: | 628 | with ExitStack() as es: |
1320 | 635 | target_tree, work_tree = self.trees | 629 | target_tree, work_tree = self.trees |
1323 | 636 | cleanup.append(work_tree.lock_read().unlock) | 630 | es.enter_context(work_tree.lock_read()) |
1324 | 637 | cleanup.append(target_tree.lock_read().unlock) | 631 | es.enter_context(target_tree.lock_read()) |
1325 | 638 | config = work_tree.branch.get_config() | 632 | config = work_tree.branch.get_config() |
1326 | 639 | change_editor = config.get_change_editor(target_tree, work_tree) | 633 | change_editor = config.get_change_editor(target_tree, work_tree) |
1327 | 640 | if change_editor is None: | 634 | if change_editor is None: |
1328 | @@ -643,16 +637,13 @@ | |||
1329 | 643 | self.editor_button.setEnabled(False) | 637 | self.editor_button.setEnabled(False) |
1330 | 644 | return | 638 | return |
1331 | 645 | 639 | ||
1333 | 646 | cleanup.append(change_editor.finish) | 640 | es.callback(change_editor.finish) |
1334 | 647 | lines = split_lines(change_editor.edit_file(change.file_id)) | 641 | lines = split_lines(change_editor.edit_file(change.file_id)) |
1335 | 648 | change_count = Shelver._count_changed_regions(change.work_lines, lines) | 642 | change_count = Shelver._count_changed_regions(change.work_lines, lines) |
1336 | 649 | if change_count > 0: | 643 | if change_count > 0: |
1337 | 650 | change.edited_lines = lines | 644 | change.edited_lines = lines |
1338 | 651 | self.update_item(items[0]) | 645 | self.update_item(items[0]) |
1339 | 652 | self.selected_file_changed() | 646 | self.selected_file_changed() |
1340 | 653 | finally: | ||
1341 | 654 | while cleanup: | ||
1342 | 655 | cleanup.pop()() | ||
1343 | 656 | 647 | ||
1344 | 657 | def _get_change_dictionary(self): | 648 | def _get_change_dictionary(self): |
1345 | 658 | change_dict = {} | 649 | change_dict = {} |
1346 | @@ -683,59 +674,56 @@ | |||
1347 | 683 | QtWidgets.QMessageBox.information(self, gettext('Shelve'), gettext('No changes selected.'), gettext('&OK')) | 674 | QtWidgets.QMessageBox.information(self, gettext('Shelve'), gettext('No changes selected.'), gettext('&OK')) |
1348 | 684 | return | 675 | return |
1349 | 685 | 676 | ||
1381 | 686 | cleanup = [] | 677 | with ExitStack() as es: |
1382 | 687 | try: | 678 | try: |
1383 | 688 | shelver, creator = self._create_shelver_and_creator(destroy=destroy) | 679 | shelver, creator = self._create_shelver_and_creator(destroy=destroy) |
1384 | 689 | cleanup.append(shelver.finalize) | 680 | es.callback(shelver.finalize) |
1385 | 690 | cleanup.append(creator.finalize) | 681 | es.callback(creator.finalize) |
1386 | 691 | trees = (shelver.target_tree, shelver.work_tree) | 682 | trees = (shelver.target_tree, shelver.work_tree) |
1387 | 692 | if len(trees[1].get_parent_ids()) > 1: | 683 | if len(trees[1].get_parent_ids()) > 1: |
1388 | 693 | raise WorkingTreeHasPendingMarge | 684 | raise WorkingTreeHasPendingMarge |
1389 | 694 | if self.revision != trees[0].get_revision_id(): | 685 | if self.revision != trees[0].get_revision_id(): |
1390 | 695 | raise WorkingTreeHasChanged | 686 | raise WorkingTreeHasChanged |
1391 | 696 | 687 | ||
1392 | 697 | changes = [] | 688 | changes = [] |
1393 | 698 | for ch in creator.iter_shelvable(): | 689 | for ch in creator.iter_shelvable(): |
1394 | 699 | change = Change(ch, shelver, trees) | 690 | change = Change(ch, shelver, trees) |
1395 | 700 | key = (change.file_id, change.status) | 691 | key = (change.file_id, change.status) |
1396 | 701 | org_change = change_dict.get(key) | 692 | org_change = change_dict.get(key) |
1397 | 702 | if org_change is None: | 693 | if org_change is None: |
1398 | 703 | continue | 694 | continue |
1399 | 704 | if not change.is_same_change(org_change): | 695 | if not change.is_same_change(org_change): |
1400 | 705 | raise WorkingTreeHasChanged | 696 | raise WorkingTreeHasChanged |
1401 | 706 | del(change_dict[key]) | 697 | del(change_dict[key]) |
1402 | 707 | changes.append(org_change) | 698 | changes.append(org_change) |
1403 | 708 | 699 | ||
1404 | 709 | if change_dict: | 700 | if change_dict: |
1405 | 710 | raise WorkingTreeHasChanged | 701 | raise WorkingTreeHasChanged |
1406 | 711 | 702 | ||
1407 | 712 | for change in changes: | 703 | for change in changes: |
1408 | 713 | if change.status == 'modify text': | 704 | if change.status == 'modify text': |
1409 | 714 | self.handle_modify_text(creator, change) | 705 | self.handle_modify_text(creator, change) |
1410 | 715 | elif change.status == 'modify binary': | 706 | elif change.status == 'modify binary': |
1411 | 716 | creator.shelve_content_change(change.data[1]) | 707 | creator.shelve_content_change(change.data[1]) |
1412 | 708 | else: | ||
1413 | 709 | creator.shelve_change(change.data) | ||
1414 | 710 | manager = shelver.work_tree.get_shelf_manager() | ||
1415 | 711 | message = str(self.message.toPlainText()).strip() or gettext('<no message>') | ||
1416 | 712 | if destroy: | ||
1417 | 713 | creator.transform() | ||
1418 | 714 | shelf_id = -1 | ||
1419 | 717 | else: | 715 | else: |
1441 | 718 | creator.shelve_change(change.data) | 716 | shelf_id = manager.shelve_changes(creator, message) |
1442 | 719 | manager = shelver.work_tree.get_shelf_manager() | 717 | |
1443 | 720 | message = str(self.message.toPlainText()).strip() or gettext('<no message>') | 718 | except WorkingTreeHasPendingMarge: |
1444 | 721 | if destroy: | 719 | QtWidgets.QMessageBox.warning(self, gettext('Shelve'), |
1445 | 722 | creator.transform() | 720 | gettext('Operation aborted because working tree has pending merges.'), gettext('&OK')) |
1446 | 723 | shelf_id = -1 | 721 | return |
1447 | 724 | else: | 722 | except WorkingTreeHasChanged: |
1448 | 725 | shelf_id = manager.shelve_changes(creator, message) | 723 | QtWidgets.QMessageBox.warning(self, gettext('Shelve'), |
1449 | 726 | 724 | gettext('Operation aborted because target files has been changed.'), gettext('&OK')) | |
1450 | 727 | except WorkingTreeHasPendingMarge: | 725 | return |
1451 | 728 | QtWidgets.QMessageBox.warning(self, gettext('Shelve'), | 726 | |
1431 | 729 | gettext('Operation aborted because working tree has pending merges.'), gettext('&OK')) | ||
1432 | 730 | return | ||
1433 | 731 | except WorkingTreeHasChanged: | ||
1434 | 732 | QtWidgets.QMessageBox.warning(self, gettext('Shelve'), | ||
1435 | 733 | gettext('Operation aborted because target files has been changed.'), gettext('&OK')) | ||
1436 | 734 | return | ||
1437 | 735 | |||
1438 | 736 | finally: | ||
1439 | 737 | while cleanup: | ||
1440 | 738 | cleanup.pop()() | ||
1452 | 739 | self.shelfCreated.emit(shelf_id) | 727 | self.shelfCreated.emit(shelf_id) |
1453 | 740 | self.clear() | 728 | self.clear() |
1454 | 741 | 729 | ||
1455 | @@ -888,12 +876,12 @@ | |||
1456 | 888 | continue | 876 | continue |
1457 | 889 | if bottom < y1: | 877 | if bottom < y1: |
1458 | 890 | break | 878 | break |
1460 | 891 | painter.fillRect(6, y1, 13, 13, QtCore.Qt.white) | 879 | painter.fillRect(6, int(y1), 13, 13, QtCore.Qt.white) |
1461 | 892 | 880 | ||
1463 | 893 | painter.drawRect(6, y1, 13, 13) | 881 | painter.drawRect(6, int(y1), 13, 13) |
1464 | 894 | if hunk.selected: | 882 | if hunk.selected: |
1467 | 895 | painter.drawLine(9, y1 + 7, 12, y1 + 10) | 883 | painter.drawLine(9, int(y1) + 7, 12, int(y1) + 10) |
1468 | 896 | painter.drawLine(16, y1 + 3, 12, y1 + 10) | 884 | painter.drawLine(16, int(y1) + 3, 12, int(y1) + 10) |
1469 | 897 | 885 | ||
1470 | 898 | del painter | 886 | del painter |
1471 | 899 | 887 | ||
1472 | @@ -942,7 +930,7 @@ | |||
1473 | 942 | self.monospacedInactiveFormat.setForeground(QtGui.QColor(128, 128, 128)) | 930 | self.monospacedInactiveFormat.setForeground(QtGui.QColor(128, 128, 128)) |
1474 | 943 | 931 | ||
1475 | 944 | titleFont = QtGui.QFont(monospacedFont) | 932 | titleFont = QtGui.QFont(monospacedFont) |
1477 | 945 | titleFont.setPointSize(titleFont.pointSize() * 140 / 100) | 933 | titleFont.setPointSize(titleFont.pointSize() * 140 // 100) |
1478 | 946 | titleFont.setBold(True) | 934 | titleFont.setBold(True) |
1479 | 947 | titleFont.setItalic(True) | 935 | titleFont.setItalic(True) |
1480 | 948 | 936 | ||
1481 | @@ -1062,17 +1050,17 @@ | |||
1482 | 1062 | continue | 1050 | continue |
1483 | 1063 | if not self.complete: | 1051 | if not self.complete: |
1484 | 1064 | # Fill header rect. | 1052 | # Fill header rect. |
1486 | 1065 | painter.fillRect(left, y1, width, 20, self.header_color) | 1053 | painter.fillRect(left, int(y1), width, 20, self.header_color) |
1487 | 1066 | # Overlay focus rect. | 1054 | # Overlay focus rect. |
1488 | 1067 | if i == self._focused_index: | 1055 | if i == self._focused_index: |
1489 | 1068 | if self.hasFocus(): | 1056 | if self.hasFocus(): |
1490 | 1069 | color = self.focus_color | 1057 | color = self.focus_color |
1491 | 1070 | else: | 1058 | else: |
1492 | 1071 | color = self.focus_color_inactive | 1059 | color = self.focus_color_inactive |
1494 | 1072 | painter.fillRect(left, y1, width, y2 - y1, color) | 1060 | painter.fillRect(left, int(y1), width, int(y2 - y1), color) |
1495 | 1073 | # Draw border. | 1061 | # Draw border. |
1498 | 1074 | painter.drawLine(left, y1, right, y1) | 1062 | painter.drawLine(left, int(y1), right, int(y1)) |
1499 | 1075 | painter.drawLine(left, y2, right, y2) | 1063 | painter.drawLine(left, int(y2), right, int(y2)) |
1500 | 1076 | 1064 | ||
1501 | 1077 | def move_next(self): | 1065 | def move_next(self): |
1502 | 1078 | index = int(self._focused_index + 1) | 1066 | index = int(self._focused_index + 1) |
1503 | @@ -1127,8 +1115,8 @@ | |||
1504 | 1127 | MARGIN = 24 | 1115 | MARGIN = 24 |
1505 | 1128 | height = self.viewport().height() | 1116 | height = self.viewport().height() |
1506 | 1129 | cur_pos = sbar.value() | 1117 | cur_pos = sbar.value() |
1509 | 1130 | max_pos = self.hunk_list[index][1] - MARGIN | 1118 | max_pos = int(self.hunk_list[index][1] - MARGIN) |
1510 | 1131 | min_pos = self.hunk_list[index][2] - height + MARGIN | 1119 | min_pos = int(self.hunk_list[index][2] - height + MARGIN) |
1511 | 1132 | if max_pos <= min_pos or max_pos < cur_pos: | 1120 | if max_pos <= min_pos or max_pos < cur_pos: |
1512 | 1133 | sbar.setValue(max_pos) | 1121 | sbar.setValue(max_pos) |
1513 | 1134 | elif cur_pos < min_pos: | 1122 | elif cur_pos < min_pos: |
1514 | 1135 | 1123 | ||
1515 | === modified file 'lib/widgets/shelvelist.py' | |||
1516 | --- lib/widgets/shelvelist.py 2021-01-06 09:29:35 +0000 | |||
1517 | +++ lib/widgets/shelvelist.py 2022-07-06 15:37:54 +0000 | |||
1518 | @@ -17,6 +17,8 @@ | |||
1519 | 17 | # along with this program; if not, write to the Free Software | 17 | # along with this program; if not, write to the Free Software |
1520 | 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
1521 | 19 | 19 | ||
1522 | 20 | from contextlib import ExitStack | ||
1523 | 21 | |||
1524 | 20 | import sys, time | 22 | import sys, time |
1525 | 21 | from PyQt5 import QtCore, QtGui, QtWidgets | 23 | from PyQt5 import QtCore, QtGui, QtWidgets |
1526 | 22 | from PyQt5.QtGui import QKeySequence | 24 | from PyQt5.QtGui import QKeySequence |
1527 | @@ -55,7 +57,6 @@ | |||
1528 | 55 | from breezy.plugins.qbrz.lib.widgets.texteditaccessory import setup_guidebar_for_find | 57 | from breezy.plugins.qbrz.lib.widgets.texteditaccessory import setup_guidebar_for_find |
1529 | 56 | from breezy.lazy_import import lazy_import | 58 | from breezy.lazy_import import lazy_import |
1530 | 57 | lazy_import(globals(), ''' | 59 | lazy_import(globals(), ''' |
1531 | 58 | from breezy import transform | ||
1532 | 59 | from breezy.workingtree import WorkingTree | 60 | from breezy.workingtree import WorkingTree |
1533 | 60 | from breezy.plugins.qbrz.lib.encoding_selector import EncodingMenuSelector | 61 | from breezy.plugins.qbrz.lib.encoding_selector import EncodingMenuSelector |
1534 | 61 | from breezy.plugins.qbrz.lib.diff import DiffItem | 62 | from breezy.plugins.qbrz.lib.diff import DiffItem |
1535 | @@ -274,8 +275,7 @@ | |||
1536 | 274 | self.loaded = False | 275 | self.loaded = False |
1537 | 275 | self.clear() | 276 | self.clear() |
1538 | 276 | tree = WorkingTree.open_containing(self.directory)[0] | 277 | tree = WorkingTree.open_containing(self.directory)[0] |
1541 | 277 | tree.lock_read() | 278 | with tree.lock_read(): |
1540 | 278 | try: | ||
1542 | 279 | manager = tree.get_shelf_manager() | 279 | manager = tree.get_shelf_manager() |
1543 | 280 | shelves = manager.active_shelves() | 280 | shelves = manager.active_shelves() |
1544 | 281 | for shelf_id in reversed(shelves): | 281 | for shelf_id in reversed(shelves): |
1545 | @@ -298,8 +298,6 @@ | |||
1546 | 298 | self.tabwidth_selector.setTabWidth(tabwidth) | 298 | self.tabwidth_selector.setTabWidth(tabwidth) |
1547 | 299 | self._on_tabwidth_changed(tabwidth) | 299 | self._on_tabwidth_changed(tabwidth) |
1548 | 300 | 300 | ||
1549 | 301 | finally: | ||
1550 | 302 | tree.unlock() | ||
1551 | 303 | self.update() | 301 | self.update() |
1552 | 304 | self.loaded = True | 302 | self.loaded = True |
1553 | 305 | 303 | ||
1554 | @@ -312,18 +310,17 @@ | |||
1555 | 312 | self.manager = None | 310 | self.manager = None |
1556 | 313 | 311 | ||
1557 | 314 | def show_changes(self, shelf_id): | 312 | def show_changes(self, shelf_id): |
1558 | 315 | cleanup = [] | ||
1559 | 316 | shelf_file = self.manager.read_shelf(shelf_id) | 313 | shelf_file = self.manager.read_shelf(shelf_id) |
1562 | 317 | cleanup.append(shelf_file.close) | 314 | with ExitStack() as es: |
1563 | 318 | try: | 315 | es.callback(shelf_file.close) |
1564 | 319 | records = Unshelver.iter_records(shelf_file) | 316 | records = Unshelver.iter_records(shelf_file) |
1565 | 320 | revid = Unshelver.parse_metadata(records)[b'revision_id'] | 317 | revid = Unshelver.parse_metadata(records)[b'revision_id'] |
1566 | 321 | try: | 318 | try: |
1567 | 322 | base_tree = self.tree.revision_tree(revid) | 319 | base_tree = self.tree.revision_tree(revid) |
1568 | 323 | except NoSuchRevisionInTree: | 320 | except NoSuchRevisionInTree: |
1569 | 324 | base_tree = self.tree.branch.repository.revision_tree(revid) | 321 | base_tree = self.tree.branch.repository.revision_tree(revid) |
1572 | 325 | preview = transform.TransformPreview(base_tree) | 322 | preview = base_tree.preview_transform() |
1573 | 326 | cleanup.append(preview.finalize) | 323 | es.callback(preview.finalize) |
1574 | 327 | preview.deserialize(records) | 324 | preview.deserialize(records) |
1575 | 328 | 325 | ||
1576 | 329 | tabwidth = get_tab_width_pixels(self.tree.branch) | 326 | tabwidth = get_tab_width_pixels(self.tree.branch) |
1577 | @@ -332,10 +329,6 @@ | |||
1578 | 332 | 329 | ||
1579 | 333 | self.load_diff(preview.get_preview_tree(), base_tree) | 330 | self.load_diff(preview.get_preview_tree(), base_tree) |
1580 | 334 | 331 | ||
1581 | 335 | finally: | ||
1582 | 336 | for func in cleanup: | ||
1583 | 337 | func() | ||
1584 | 338 | |||
1585 | 339 | def load_diff(self, tree, base_tree): | 332 | def load_diff(self, tree, base_tree): |
1586 | 340 | self.file_view.clear() | 333 | self.file_view.clear() |
1587 | 341 | 334 |