Merge lp:~jelmer/qbrz/context-managers into lp:qbrz

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
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
=== modified file 'extras/build_pot.py'
--- extras/build_pot.py 2020-07-15 09:34:25 +0000
+++ extras/build_pot.py 2022-07-06 15:37:54 +0000
@@ -63,18 +63,12 @@
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.")
6464
65 def _force_LF(self, src, dst=None):65 def _force_LF(self, src, dst=None):
66 f = open(src, 'rU')66 with open(src, 'rU') as f:
67 try:
68 content = f.read()67 content = f.read()
69 finally:
70 f.close()
71 if dst is None:68 if dst is None:
72 dst = src69 dst = src
73 f = open(dst, 'wb')70 with open(dst, 'wb') as f:
74 try:
75 f.write(content)71 f.write(content)
76 finally:
77 f.close()
7872
79 def run(self):73 def run(self):
80 """Run xgettext for project sources"""74 """Run xgettext for project sources"""
8175
=== modified file 'extras/import_po.py'
--- extras/import_po.py 2019-10-27 14:48:19 +0000
+++ extras/import_po.py 2022-07-06 15:37:54 +0000
@@ -80,11 +80,8 @@
80 for n, fn in entries:80 for n, fn in entries:
81 log.info(' %s -> %s' % (n, fn))81 log.info(' %s -> %s' % (n, fn))
82 ft = t.extractfile(n)82 ft = t.extractfile(n)
83 fd = open(fn, 'wb')83 with open(fn, 'wb') as fd:
84 try:
85 fd.write(ft.read())84 fd.write(ft.read())
86 finally:
87 fd.close()
88 if pot_file:85 if pot_file:
89 if find_executable('msginit') is None:86 if find_executable('msginit') is None:
90 log.warn("GNU gettext msginit utility not found!")87 log.warn("GNU gettext msginit utility not found!")
9188
=== modified file 'lib/annotate.py'
--- lib/annotate.py 2022-01-07 14:04:10 +0000
+++ lib/annotate.py 2022-07-06 15:37:54 +0000
@@ -410,12 +410,9 @@
410 QtCore.QCoreApplication.processEvents()410 QtCore.QCoreApplication.processEvents()
411 self.encoding = get_set_encoding(self.encoding, self.branch)411 self.encoding = get_set_encoding(self.encoding, self.branch)
412 self.encoding_selector.encoding = self.encoding412 self.encoding_selector.encoding = self.encoding
413 self.branch.lock_read()413 with self.branch.lock_read():
414 try:
415 self.set_annotate_title()414 self.set_annotate_title()
416 self.annotate(self.annotate_tree, self.fileId, self.path)415 self.annotate(self.annotate_tree, self.fileId, self.path)
417 finally:
418 self.branch.unlock()
419 finally:416 finally:
420 self.throbber.hide()417 self.throbber.hide()
421 QtCore.QTimer.singleShot(1, self._activate_line)418 QtCore.QTimer.singleShot(1, self._activate_line)
@@ -634,8 +631,7 @@
634 def set_annotate_revision(self):631 def set_annotate_revision(self):
635 self.throbber.show()632 self.throbber.show()
636 try:633 try:
637 self.branch.lock_read()634 with self.branch.lock_read():
638 try:
639 revid = self.log_list.currentIndex().data(logmodel.RevIdRole)635 revid = self.log_list.currentIndex().data(logmodel.RevIdRole)
640 if revid.startswith(CURRENT_REVISION):636 if revid.startswith(CURRENT_REVISION):
641 rev = cached_revisions[revid]637 rev = cached_revisions[revid]
@@ -646,8 +642,6 @@
646 self.set_annotate_title()642 self.set_annotate_title()
647 self.processEvents()643 self.processEvents()
648 self.annotate(self.annotate_tree, self.fileId, self.path)644 self.annotate(self.annotate_tree, self.fileId, self.path)
649 finally:
650 self.branch.unlock()
651 finally:645 finally:
652 self.throbber.hide()646 self.throbber.hide()
653647
@@ -657,11 +651,8 @@
657 get_set_encoding(encoding, self.branch)651 get_set_encoding(encoding, self.branch)
658 self.throbber.show()652 self.throbber.show()
659 try:653 try:
660 self.branch.lock_read()654 with self.branch.lock_read():
661 try:
662 self.annotate(self.annotate_tree, self.fileId, self.path)655 self.annotate(self.annotate_tree, self.fileId, self.path)
663 finally:
664 self.branch.unlock()
665 finally:656 finally:
666 self.throbber.hide()657 self.throbber.hide()
667658
668659
=== modified file 'lib/browse.py'
--- lib/browse.py 2021-01-08 13:56:34 +0000
+++ lib/browse.py 2022-07-06 15:37:54 +0000
@@ -158,49 +158,45 @@
158 self.diffbuttons,158 self.diffbuttons,
159 self.refresh_button)159 self.refresh_button)
160 state = self.file_tree.get_state()160 state = self.file_tree.get_state()
161 if text=="wt:":161 if text == "wt:":
162 self.tree = self.workingtree162 self.tree = self.workingtree
163 self.tree.lock_read()163 with self.tree.lock_read():
164 try:164 try:
165 self.file_tree.set_tree(self.workingtree, self.branch)165 self.file_tree.set_tree(self.workingtree, self.branch)
166 self.file_tree.restore_state(state)166 self.file_tree.restore_state(state)
167 finally:
168 self.tree.unlock()
169 for button in buttons:167 for button in buttons:
170 button.setEnabled(True)168 button.setEnabled(True)
171 else:169 else:
172 branch = self.branch170 branch = self.branch
173 branch.lock_read()171 with branch.lock_read():
174 self.processEvents()
175
176 for button in buttons:
177 button.setEnabled(False)
178 fmodel = self.file_tree.tree_filter_model
179 fmodel.setFilter(fmodel.UNCHANGED, True)
180 self.filter_menu.set_filters(fmodel.filters)
181
182 try:
183 if revision_id is None:
184 text = revspec.spec or ''
185 if revspec.in_branch == revspec.in_history:
186 args = [branch]
187 else:
188 args = [branch, False]
189
190 revision_id = revspec.in_branch(*args).rev_id
191
192 self.revision_id = revision_id
193 self.tree = branch.repository.revision_tree(revision_id)
194 self.processEvents()172 self.processEvents()
195 self.file_tree.set_tree(self.tree, self.branch)173
196 self.file_tree.restore_state(state)174 for button in buttons:
197 if self.revno_map is None:175 button.setEnabled(False)
176 fmodel = self.file_tree.tree_filter_model
177 fmodel.setFilter(fmodel.UNCHANGED, True)
178 self.filter_menu.set_filters(fmodel.filters)
179
180 try:
181 if revision_id is None:
182 text = revspec.spec or ''
183 if revspec.in_branch == revspec.in_history:
184 args = [branch]
185 else:
186 args = [branch, False]
187
188 revision_id = revspec.in_branch(*args).rev_id
189
190 self.revision_id = revision_id
191 self.tree = branch.repository.revision_tree(revision_id)
198 self.processEvents()192 self.processEvents()
199 # XXX make this operation lazy? how?193 self.file_tree.set_tree(self.tree, self.branch)
200 self.revno_map = self.branch.get_revision_id_to_revno_map()194 self.file_tree.restore_state(state)
201 self.file_tree.tree_model.set_revno_map(self.revno_map)195 if self.revno_map is None:
202 finally:196 self.processEvents()
203 branch.unlock()197 # XXX make this operation lazy? how?
198 self.revno_map = self.branch.get_revision_id_to_revno_map()
199 self.file_tree.tree_model.set_revno_map(self.revno_map)
204 self.revision_edit.setText(text)200 self.revision_edit.setText(text)
205 finally:201 finally:
206 self.throbber.hide()202 self.throbber.hide()
207203
=== modified file 'lib/cat.py'
--- lib/cat.py 2021-01-08 08:16:13 +0000
+++ lib/cat.py 2022-07-06 15:37:54 +0000
@@ -142,8 +142,7 @@
142 "%r is not present in revision %s" % (142 "%r is not present in revision %s" % (
143 self.filename, self.tree.get_revision_id()))143 self.filename, self.tree.get_revision_id()))
144144
145 self.tree.lock_read()145 with self.tree.lock_read():
146 try:
147 kind = self.tree.kind(self.filename)146 kind = self.tree.kind(self.filename)
148 if kind == 'file':147 if kind == 'file':
149 text = self.tree.get_file_text(self.filename)148 text = self.tree.get_file_text(self.filename)
@@ -151,8 +150,6 @@
151 text = self.tree.get_symlink_target(self.filename)150 text = self.tree.get_symlink_target(self.filename)
152 else:151 else:
153 text = ''152 text = ''
154 finally:
155 self.tree.unlock()
156 self.processEvents()153 self.processEvents()
157154
158 self.text = text155 self.text = text
@@ -304,11 +301,8 @@
304 kind = osutils.file_kind(self.filename)301 kind = osutils.file_kind(self.filename)
305 text = ''302 text = ''
306 if kind == 'file':303 if kind == 'file':
307 f = open(self.filename, 'rb')304 with open(self.filename, 'rb') as f:
308 try:
309 text = f.read()305 text = f.read()
310 finally:
311 f.close()
312 elif kind == 'symlink':306 elif kind == 'symlink':
313 text = os.readlink(self.filename)307 text = os.readlink(self.filename)
314 self.text = text308 self.text = text
@@ -337,13 +331,8 @@
337 os.makedirs(qdir)331 os.makedirs(qdir)
338 basename = os.path.basename(relpath)332 basename = os.path.basename(relpath)
339 fname = os.path.join(qdir, basename)333 fname = os.path.join(qdir, basename)
340 f = open(fname, 'wb')334 with open(fname, 'wb') as f, tree.lock_read():
341 tree.lock_read()
342 try:
343 f.write(tree.get_file_text(relpath))335 f.write(tree.get_file_text(relpath))
344 finally:
345 tree.unlock()
346 f.close()
347 # open it336 # open it
348 url = QtCore.QUrl.fromLocalFile(fname)337 url = QtCore.QUrl.fromLocalFile(fname)
349 result = QtGui.QDesktopServices.openUrl(url)338 result = QtGui.QDesktopServices.openUrl(url)
350339
=== removed file 'lib/cleanup.py'
--- lib/cleanup.py 2020-07-14 15:58:13 +0000
+++ lib/cleanup.py 1970-01-01 00:00:00 +0000
@@ -1,184 +0,0 @@
1# Copyright (C) 2009, 2010 Canonical Ltd
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17"""Helpers for managing cleanup functions and the errors they might raise.
18
19The usual way to run cleanup code in Python is::
20
21 try:
22 do_something()
23 finally:
24 cleanup_something()
25
26However if both `do_something` and `cleanup_something` raise an exception
27Python will forget the original exception and propagate the one from
28cleanup_something. Unfortunately, this is almost always much less useful than
29the original exception.
30
31If you want to be certain that the first, and only the first, error is raised,
32then use::
33
34 operation = OperationWithCleanups(do_something)
35 operation.add_cleanup(cleanup_something)
36 operation.run_simple()
37
38This is more inconvenient (because you need to make every try block a
39function), but will ensure that the first error encountered is the one raised,
40while also ensuring all cleanups are run. See OperationWithCleanups for more
41details.
42"""
43
44from __future__ import absolute_import
45
46from collections import deque
47# import sys
48# from . import (
49# debug,
50# trace,
51# )
52
53from breezy import (
54 debug,
55 trace,
56 )
57
58
59def _log_cleanup_error(exc):
60 trace.mutter('Cleanup failed:')
61 trace.log_exception_quietly()
62 if 'cleanup' in debug.debug_flags:
63 trace.warning('brz: warning: Cleanup failed: %s', exc)
64
65
66def _run_cleanup(func, *args, **kwargs):
67 """Run func(*args, **kwargs), logging but not propagating any error it
68 raises.
69
70 :returns: True if func raised no errors, else False.
71 """
72 try:
73 func(*args, **kwargs)
74 except KeyboardInterrupt:
75 raise
76 except Exception as exc:
77 _log_cleanup_error(exc)
78 return False
79 return True
80
81
82def _run_cleanups(funcs):
83 """Run a series of cleanup functions."""
84 for func, args, kwargs in funcs:
85 _run_cleanup(func, *args, **kwargs)
86
87
88class ObjectWithCleanups(object):
89 """A mixin for objects that hold a cleanup list.
90
91 Subclass or client code can call add_cleanup and then later `cleanup_now`.
92 """
93 def __init__(self):
94 self.cleanups = deque()
95
96 def add_cleanup(self, cleanup_func, *args, **kwargs):
97 """Add a cleanup to run.
98
99 Cleanups may be added at any time.
100 Cleanups will be executed in LIFO order.
101 """
102 self.cleanups.appendleft((cleanup_func, args, kwargs))
103
104 def cleanup_now(self):
105 _run_cleanups(self.cleanups)
106 self.cleanups.clear()
107
108
109class OperationWithCleanups(ObjectWithCleanups):
110 """A way to run some code with a dynamic cleanup list.
111
112 This provides a way to add cleanups while the function-with-cleanups is
113 running.
114
115 Typical use::
116
117 operation = OperationWithCleanups(some_func)
118 operation.run(args...)
119
120 where `some_func` is::
121
122 def some_func(operation, args, ...):
123 do_something()
124 operation.add_cleanup(something)
125 # etc
126
127 Note that the first argument passed to `some_func` will be the
128 OperationWithCleanups object. To invoke `some_func` without that, use
129 `run_simple` instead of `run`.
130 """
131
132 def __init__(self, func):
133 super(OperationWithCleanups, self).__init__()
134 self.func = func
135
136 def run(self, *args, **kwargs):
137 return _do_with_cleanups(self.cleanups, self.func, self, *args, **kwargs)
138
139 def run_simple(self, *args, **kwargs):
140 return _do_with_cleanups(self.cleanups, self.func, *args, **kwargs)
141
142
143def _do_with_cleanups(cleanup_funcs, func, *args, **kwargs):
144 """Run `func`, then call all the cleanup_funcs.
145
146 All the cleanup_funcs are guaranteed to be run. The first exception raised
147 by func or any of the cleanup_funcs is the one that will be propagted by
148 this function (subsequent errors are caught and logged).
149
150 Conceptually similar to::
151
152 try:
153 return func(*args, **kwargs)
154 finally:
155 for cleanup, cargs, ckwargs in cleanup_funcs:
156 cleanup(*cargs, **ckwargs)
157
158 It avoids several problems with using try/finally directly:
159 * an exception from func will not be obscured by a subsequent exception
160 from a cleanup.
161 * an exception from a cleanup will not prevent other cleanups from
162 running (but the first exception encountered is still the one
163 propagated).
164
165 Unike `_run_cleanup`, `_do_with_cleanups` can propagate an exception from a
166 cleanup, but only if there is no exception from func.
167 """
168 try:
169 result = func(*args, **kwargs)
170 except:
171 # We have an exception from func already, so suppress cleanup errors.
172 _run_cleanups(cleanup_funcs)
173 raise
174 # No exception from func, so allow first cleanup error to propgate.
175 pending_cleanups = iter(cleanup_funcs)
176 try:
177 for cleanup, c_args, c_kwargs in pending_cleanups:
178 cleanup(*c_args, **c_kwargs)
179 except:
180 # Still run the remaining cleanups but suppress any further errors.
181 _run_cleanups(pending_cleanups)
182 raise
183 # No error, so we can return the result
184 return result
1850
=== modified file 'lib/commands.py'
--- lib/commands.py 2021-08-05 11:12:43 +0000
+++ lib/commands.py 2022-07-06 15:37:54 +0000
@@ -367,11 +367,8 @@
367 if message is not None and file:367 if message is not None and file:
368 raise errors.BzrCommandError("please specify either --message or --file")368 raise errors.BzrCommandError("please specify either --message or --file")
369 if file:369 if file:
370 f = open(file)370 with open(file) as f:
371 try:
372 message = f.read().decode(file_encoding or osutils.get_user_encoding())371 message = f.read().decode(file_encoding or osutils.get_user_encoding())
373 finally:
374 f.close()
375 tree, selected_list = WorkingTree.open_containing_paths(selected_list)372 tree, selected_list = WorkingTree.open_containing_paths(selected_list)
376 if selected_list == ['']:373 if selected_list == ['']:
377 selected_list = None374 selected_list = None
@@ -403,18 +400,11 @@
403 takes_options.append('change')400 takes_options.append('change')
404 aliases = ['qdi']401 aliases = ['qdi']
405402
406 def get_diff_window_args(self, processEvents, add_cleanup):403 def get_diff_window_args(self, processEvents, es):
407 # RJL if you get a ``AttributeError: 'function' object has no attribute 'enter_context'``
408 # error, or something similar, use something like:
409 #
410 # exit_stack = contextlib.ExitStack()
411 #
412 # and pass that as add_cleanup
413 #
414 args = {}404 args = {}
415 (args["old_tree"], args["new_tree"],405 (args["old_tree"], args["new_tree"],
416 args["old_branch"], args["new_branch"],406 args["old_branch"], args["new_branch"],
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)
418 args["ignore_whitespace"] = self.ignore_whitespace408 args["ignore_whitespace"] = self.ignore_whitespace
419 return args409 return args
420410
@@ -716,7 +706,7 @@
716 del kw['encoding']706 del kw['encoding']
717 return breezy.builtins.cmd_merge.run(self, *args, **kw)707 return breezy.builtins.cmd_merge.run(self, *args, **kw)
718708
719 def get_diff_window_args(self, processEvents, add_cleanup):709 def get_diff_window_args(self, processEvents, es):
720 tree_merger = self.merger.make_merger()710 tree_merger = self.merger.make_merger()
721 self.tt = tree_merger.make_preview_transform()711 self.tt = tree_merger.make_preview_transform()
722 result_tree = self.tt.get_preview_tree()712 result_tree = self.tt.get_preview_tree()
723713
=== modified file 'lib/commit.py'
--- lib/commit.py 2022-01-07 15:10:55 +0000
+++ lib/commit.py 2022-07-06 15:37:54 +0000
@@ -465,8 +465,7 @@
465 self.throbber.show()465 self.throbber.show()
466 self.refresh_button.setDisabled(True)466 self.refresh_button.setDisabled(True)
467 try:467 try:
468 self.tree.lock_read()468 with self.tree.lock_read():
469 try:
470 if self.pending_merges_list:469 if self.pending_merges_list:
471 self.pending_merges_list.load_tree(self.tree)470 self.pending_merges_list.load_tree(self.tree)
472 # Force the loading of the revisions, before we start471 # Force the loading of the revisions, before we start
@@ -488,7 +487,7 @@
488 # if there are any paths from the command line that487 # if there are any paths from the command line that
489 # are not versioned, we want_unversioned.488 # are not versioned, we want_unversioned.
490 for path in self.initial_selected_list:489 for path in self.initial_selected_list:
491 if not self.tree.path2id(path):490 if not self.tree.is_versioned(path):
492 want_unversioned = True491 want_unversioned = True
493 break492 break
494493
@@ -504,8 +503,6 @@
504 self.is_loading = False503 self.is_loading = False
505 self.processEvents()504 self.processEvents()
506 self.update_compleater_words()505 self.update_compleater_words()
507 finally:
508 self.tree.unlock()
509 finally:506 finally:
510 self.throbber.hide()507 self.throbber.hide()
511 self.refresh_button.setDisabled(False)508 self.refresh_button.setDisabled(False)
512509
=== modified file 'lib/commit_data.py'
--- lib/commit_data.py 2019-10-27 14:48:19 +0000
+++ lib/commit_data.py 2022-07-06 15:37:54 +0000
@@ -164,14 +164,11 @@
164 def save(self):164 def save(self):
165 """Save data to the branch/tree."""165 """Save data to the branch/tree."""
166 br = self._get_branch()166 br = self._get_branch()
167 br.lock_write()167 with br.lock_write():
168 try:
169 # XXX save should wipe if self._data is empty168 # XXX save should wipe if self._data is empty
170 self._set_new_commit_data(self._filtered_data())169 self._set_new_commit_data(self._filtered_data())
171 # clear old data170 # clear old data
172 self._wipe_old_data()171 self._wipe_old_data()
173 finally:
174 br.unlock()
175172
176 def _wipe_old_data(self):173 def _wipe_old_data(self):
177 """Wipe saved data in old format."""174 """Wipe saved data in old format."""
@@ -180,13 +177,10 @@
180 def wipe(self):177 def wipe(self):
181 """Delete saved data from branch/tree config."""178 """Delete saved data from branch/tree config."""
182 br = self._get_branch()179 br = self._get_branch()
183 br.lock_write()180 with br.lock_write():
184 try:
185 self._set_new_commit_data({})181 self._set_new_commit_data({})
186 # clear old data182 # clear old data
187 self._wipe_old_data()183 self._wipe_old_data()
188 finally:
189 br.unlock()
190184
191 def _get_branch(self):185 def _get_branch(self):
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.
193187
=== modified file 'lib/diff.py'
--- lib/diff.py 2022-01-08 11:48:59 +0000
+++ lib/diff.py 2022-07-06 15:37:54 +0000
@@ -17,8 +17,18 @@
17# along with this program; if not, write to the Free Software17# along with this program; if not, write to the Free Software
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.
1919
20from contextlib import ExitStack
21import errno
22import re
23import time
24import sys
25import os
26import glob
27
20from PyQt5 import QtCore, QtGui, QtWidgets28from PyQt5 import QtCore, QtGui, QtWidgets
2129
30from breezy import trace, osutils, cmdline
31
22from breezy.errors import NoSuchId, ExecutableMissing32from breezy.errors import NoSuchId, ExecutableMissing
23from breezy.tree import FileTimestampUnavailable33from breezy.tree import FileTimestampUnavailable
24from breezy.plugins.qbrz.lib.diff_arg import * # import DiffArgProvider classes34from breezy.plugins.qbrz.lib.diff_arg import * # import DiffArgProvider classes
@@ -30,22 +40,9 @@
30 )40 )
3141
32from breezy.lazy_import import lazy_import42from breezy.lazy_import import lazy_import
33try:
34 QString = unicode
35except NameError:
36 # Python 3
37 QString = str
38
39lazy_import(globals(), '''43lazy_import(globals(), '''
40import errno
41import re
42import time
43import sys
44import os
45import glob
46from patiencediff import PatienceSequenceMatcher as SequenceMatcher44from patiencediff import PatienceSequenceMatcher as SequenceMatcher
47from breezy.plugins.qbrz.lib.i18n import gettext, ngettext, N_45from breezy.plugins.qbrz.lib.i18n import gettext, ngettext, N_
48from breezy import trace, osutils, cmdline
49from breezy.workingtree import WorkingTree46from breezy.workingtree import WorkingTree
50from breezy.trace import mutter47from breezy.trace import mutter
51''')48''')
@@ -78,10 +75,9 @@
78 parent_window.windows.append(window)75 parent_window.windows.append(window)
79 elif context:76 elif context:
80 ext_diff = str(ext_diff) # convert QString to str77 ext_diff = str(ext_diff) # convert QString to str
81 cleanup = []78 with ExitStack() as es:
82 try:
83 args = arg_provider.get_diff_window_args(79 args = arg_provider.get_diff_window_args(
84 QtWidgets.QApplication.processEvents, cleanup.append80 QtWidgets.QApplication.processEvents, es
85 )81 )
86 old_tree = args["old_tree"]82 old_tree = args["old_tree"]
87 new_tree = args["new_tree"]83 new_tree = args["new_tree"]
@@ -91,9 +87,6 @@
91 context.diff_paths(specific_files)87 context.diff_paths(specific_files)
92 else:88 else:
93 context.diff_tree()89 context.diff_tree()
94 finally:
95 while cleanup:
96 cleanup.pop()()
9790
98 else:91 else:
99 args=["diff", "--using", ext_diff] # NEVER USE --using=xxx, ALWAYS --using xxx92 args=["diff", "--using", ext_diff] # NEVER USE --using=xxx, ALWAYS --using xxx
@@ -188,11 +181,10 @@
188 """181 """
189 RJLRJL: updated to call .iter_changes directly182 RJLRJL: updated to call .iter_changes directly
190 """183 """
191 try:184 with ExitStack() as es:
192 cleanup = []
193 if lock_trees:185 if lock_trees:
194 for t in trees:186 for t in trees:
195 cleanup.append(t.lock_read().unlock)187 es.enter_context(t.lock_read())
196188
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)
198190
@@ -215,9 +207,6 @@
215 if not di:207 if not di:
216 continue208 continue
217 yield di209 yield di
218 finally:
219 while cleanup:
220 cleanup.pop()()
221210
222 @classmethod211 @classmethod
223 def create(cls, trees, file_id, paths, changed_content, versioned,212 def create(cls, trees, file_id, paths, changed_content, versioned,
@@ -588,17 +577,13 @@
588 NOTE: Directories cannot be specified.577 NOTE: Directories cannot be specified.
589 Use diff_tree or diff_paths instead when specifing directory.578 Use diff_tree or diff_paths instead when specifing directory.
590 """579 """
591 cleanup = []580 with ExitStack() as es:
592 try:
593 if lock_trees:581 if lock_trees:
594 cleanup.append(self._differ.new_tree.lock_read().unlock)582 es.enter_context(self._differ.new_tree.lock_read())
595 cleanup.append(self._differ.old_tree.lock_read().unlock)583 es.enter_context(self._differ.old_tree.lock_read())
596 for file_id in file_ids:584 for file_id in file_ids:
597 self._differ.diff(file_id)585 self._differ.diff(file_id)
598 time.sleep(interval * 0.001)586 time.sleep(interval * 0.001)
599 finally:
600 while cleanup:
601 cleanup.pop()()
602587
603 def diff_paths(self, paths, interval=50, lock_trees=True):588 def diff_paths(self, paths, interval=50, lock_trees=True):
604 """589 """
@@ -610,12 +595,11 @@
610 valid_paths = []595 valid_paths = []
611 ids = []596 ids = []
612 dir_included = False597 dir_included = False
613 cleanup = []598 with ExitStack() as es:
614 try:
615 # Sometimes, we must lock tree before calling tree.kind()599 # Sometimes, we must lock tree before calling tree.kind()
616 if lock_trees:600 if lock_trees:
617 cleanup.append(new_tree.lock_read().unlock)601 es.enter_context(new_tree.lock_read())
618 cleanup.append(old_tree.lock_read().unlock)602 es.enter_context(old_tree.lock_read())
619 for p in paths:603 for p in paths:
620 id = new_tree.path2id(p)604 id = new_tree.path2id(p)
621 if id:605 if id:
@@ -630,9 +614,6 @@
630 self.diff_tree(valid_paths, interval, False)614 self.diff_tree(valid_paths, interval, False)
631 else:615 else:
632 self.diff_ids(ids, interval, False)616 self.diff_ids(ids, interval, False)
633 finally:
634 while cleanup:
635 cleanup.pop()()
636617
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):
638 """619 """
639620
=== modified file 'lib/diff_arg.py'
--- lib/diff_arg.py 2017-09-11 06:53:22 +0000
+++ lib/diff_arg.py 2022-07-06 15:37:54 +0000
@@ -30,7 +30,7 @@
30 """Contract class to pass arguments to either builtin diff window, or30 """Contract class to pass arguments to either builtin diff window, or
31 external diffs"""31 external diffs"""
3232
33 def get_diff_window_args(self, processEvents, add_cleanup):33 def get_diff_window_args(self, processEvents, es):
34 """Returns the arguments for the builtin diff window.34 """Returns the arguments for the builtin diff window.
3535
36 :return: {"old_tree": old_tree,36 :return: {"old_tree": old_tree,
@@ -52,7 +52,7 @@
5252
53class InternalDiffArgProvider(DiffArgProvider):53class InternalDiffArgProvider(DiffArgProvider):
54 """Use for passing arguments from internal source."""54 """Use for passing arguments from internal source."""
55 55
56 def __init__(self,56 def __init__(self,
57 old_revid, new_revid,57 old_revid, new_revid,
58 old_branch, new_branch,58 old_branch, new_branch,
@@ -67,7 +67,7 @@
6767
68 self.old_tree = old_tree68 self.old_tree = old_tree
69 self.new_tree = new_tree69 self.new_tree = new_tree
70 70
71 def need_to_load_paths(self):71 def need_to_load_paths(self):
72 return self.specific_file_ids is not None \72 return self.specific_file_ids is not None \
73 and self.specific_files is None73 and self.specific_files is None
@@ -83,14 +83,11 @@
83 self.new_branch.repository.revision_tree(self.new_revid)83 self.new_branch.repository.revision_tree(self.new_revid)
8484
85 if self.need_to_load_paths():85 if self.need_to_load_paths():
86 self.new_tree.lock_read()86 with self.new_tree.lock_read():
87 try:
88 self.specific_files = [self.new_tree.id2path(id) \87 self.specific_files = [self.new_tree.id2path(id) \
89 for id in self.specific_file_ids]88 for id in self.specific_file_ids]
90 finally:
91 self.new_tree.unlock()
9289
93 def get_diff_window_args(self, processEvents, add_cleanup):90 def get_diff_window_args(self, processEvents, es):
94 self.load_old_tree()91 self.load_old_tree()
95 processEvents()92 processEvents()
96 self.load_new_tree_and_paths()93 self.load_new_tree_and_paths()
@@ -107,11 +104,11 @@
107 if revid.startswith(CURRENT_REVISION):104 if revid.startswith(CURRENT_REVISION):
108 return ''105 return ''
109 return 'revid:%s' % revid106 return 'revid:%s' % revid
110 107
111 return "-r%s..%s" % (108 return "-r%s..%s" % (
112 get_revspec_part(self.old_revid),109 get_revspec_part(self.old_revid),
113 get_revspec_part(self.new_revid))110 get_revspec_part(self.new_revid))
114 111
115 def get_ext_diff_args(self, processEvents):112 def get_ext_diff_args(self, processEvents):
116 from breezy import urlutils113 from breezy import urlutils
117 from breezy import errors114 from breezy import errors
@@ -177,7 +174,7 @@
177 else:174 else:
178 InternalDiffArgProvider.load_old_tree(self)175 InternalDiffArgProvider.load_old_tree(self)
179176
180 def get_diff_window_args(self, processEvents, add_cleanup):177 def get_diff_window_args(self, processEvents, es):
181 self.load_old_tree()178 self.load_old_tree()
182 processEvents()179 processEvents()
183180
184181
=== modified file 'lib/diffview.py'
--- lib/diffview.py 2022-01-08 10:52:49 +0000
+++ lib/diffview.py 2022-07-06 15:37:54 +0000
@@ -295,7 +295,7 @@
295 def adjust_range(self):295 def adjust_range(self):
296 page_step = self.browsers[0].verticalScrollBar().pageStep()296 page_step = self.browsers[0].verticalScrollBar().pageStep()
297 self.setPageStep(page_step)297 self.setPageStep(page_step)
298 self.setRange(0, self.total_length - page_step + 4)298 self.setRange(0, int(self.total_length - page_step + 4))
299 self.setVisible(self.total_length > page_step)299 self.setVisible(self.total_length > page_step)
300300
301 def get_position_info(self, target):301 def get_position_info(self, target):
302302
=== modified file 'lib/diffwindow.py'
--- lib/diffwindow.py 2022-01-08 11:48:59 +0000
+++ lib/diffwindow.py 2022-07-06 15:37:54 +0000
@@ -20,6 +20,7 @@
20# along with this program; if not, write to the Free Software20# along with this program; if not, write to the Free Software
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.
2222
23from contextlib import ExitStack
23import errno24import errno
24import re25import re
25import time26import time
@@ -35,8 +36,6 @@
35from breezy.workingtree import WorkingTree36from breezy.workingtree import WorkingTree
36from breezy.bzr.workingtree_4 import DirStateRevisionTree37from breezy.bzr.workingtree_4 import DirStateRevisionTree
37from breezy import trace38from breezy import trace
38# from breezy import cleanup
39from breezy.plugins.qbrz.lib import cleanup
4039
41from breezy.plugins.qbrz.lib.diffview import (40from breezy.plugins.qbrz.lib.diffview import (
42 SidebySideDiffView,41 SidebySideDiffView,
@@ -345,16 +344,13 @@
345 throbber window, then loads the branches etc if they weren't specified344 throbber window, then loads the branches etc if they weren't specified
346 in our constructor.345 in our constructor.
347 """346 """
348 op = cleanup.OperationWithCleanups(self._initial_load)347 with ExitStack() as es:
349 self.throbber.show()348 es.callback(self.throbber.hide)
350 op.add_cleanup(self.throbber.hide)349 self.throbber.show()
351 op.run()350 self._initial_load(es)
352351
353 def _initial_load(self, op):352 def _initial_load(self, es):
354 # RJL Breezy expects a context handler of some type353 args = self.arg_provider.get_diff_window_args(self.processEvents, es)
355 exit_stack = contextlib.ExitStack()
356 args = self.arg_provider.get_diff_window_args(self.processEvents, exit_stack)
357 # args = self.arg_provider.get_diff_window_args(self.processEvents, op.add_cleanup)
358354
359 self.trees = (args["old_tree"], args["new_tree"])355 self.trees = (args["old_tree"], args["new_tree"])
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))
361357
=== modified file 'lib/extra/isignored.py'
--- lib/extra/isignored.py 2019-10-27 14:48:19 +0000
+++ lib/extra/isignored.py 2022-07-06 15:37:54 +0000
@@ -33,7 +33,7 @@
3333
34 def run(self, filename):34 def run(self, filename):
35 tree, relpath = workingtree.WorkingTree.open_containing(filename)35 tree, relpath = workingtree.WorkingTree.open_containing(filename)
36 if tree.is_ignored(relpath) and not tree.path2id(relpath):36 if tree.is_ignored(relpath) and not tree.is_versioned(relpath):
37 if not trace.is_quiet():37 if not trace.is_quiet():
38 print('ignored', file=self.outf)38 print('ignored', file=self.outf)
39 return 139 return 1
4040
=== modified file 'lib/extra/isversioned.py'
--- lib/extra/isversioned.py 2019-10-27 14:48:19 +0000
+++ lib/extra/isversioned.py 2022-07-06 15:37:54 +0000
@@ -33,7 +33,7 @@
3333
34 def run(self, filename):34 def run(self, filename):
35 tree, relpath = workingtree.WorkingTree.open_containing(filename)35 tree, relpath = workingtree.WorkingTree.open_containing(filename)
36 if tree.path2id(relpath):36 if tree.is_versioned(relpath):
37 if not trace.is_quiet():37 if not trace.is_quiet():
38 print('versioned', file=self.outf)38 print('versioned', file=self.outf)
39 return 139 return 1
4040
=== modified file 'lib/lazycachedrevloader.py'
--- lib/lazycachedrevloader.py 2021-01-05 13:03:34 +0000
+++ lib/lazycachedrevloader.py 2022-07-06 15:37:54 +0000
@@ -37,13 +37,13 @@
37 before_batch_load = None,37 before_batch_load = None,
38 revisions_loaded = None,38 revisions_loaded = None,
39 pass_prev_loaded_rev = False):39 pass_prev_loaded_rev = False):
40 40
41 start_time = time.process_time()41 start_time = time.process_time()
42 showed_throbber = False42 showed_throbber = False
43 revids = [revid for revid in revids if not revid == "root:"]43 revids = [revid for revid in revids if not revid == "root:"]
44 return_revisions = {}44 return_revisions = {}
45 throbber = current_throbber()45 throbber = current_throbber()
46 46
47 try:47 try:
48 for revid in [revid for revid in revids48 for revid in [revid for revid in revids
49 if revid in cached_revisions]:49 if revid in cached_revisions]:
@@ -51,7 +51,7 @@
51 if pass_prev_loaded_rev:51 if pass_prev_loaded_rev:
52 if revisions_loaded is not None:52 if revisions_loaded is not None:
53 revisions_loaded(return_revisions, False)53 revisions_loaded(return_revisions, False)
54 54
55 revs_loaded = {}55 revs_loaded = {}
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]
57 if revids:57 if revids:
@@ -59,24 +59,23 @@
59 repo_revids=((repo, revids),)59 repo_revids=((repo, revids),)
60 else:60 else:
61 repo_revids = repo(revids)61 repo_revids = repo(revids)
62 62
63 for repo, revids in repo_revids:63 for repo, revids in repo_revids:
64 repo_is_local = isinstance(repo.controldir.transport, LocalTransport)64 repo_is_local = isinstance(repo.controldir.transport, LocalTransport)
65 if repo_is_local:65 if repo_is_local:
66 batch_size = local_batch_size66 batch_size = local_batch_size
67 else:67 else:
68 batch_size = remote_batch_size68 batch_size = remote_batch_size
69 69
70 if revids:70 if revids:
71 repo.lock_read()71 with repo.lock_read():
72 try:
73 if not repo_is_local:72 if not repo_is_local:
74 update_ui()73 update_ui()
75 74
76 for offset in range(0, len(revids), batch_size):75 for offset in range(0, len(revids), batch_size):
77 76
78 running_time = time.process_time() - start_time77 running_time = time.process_time() - start_time
79 78
80 if time_before_first_ui_update < running_time:79 if time_before_first_ui_update < running_time:
81 if revisions_loaded is not None:80 if revisions_loaded is not None:
82 revisions_loaded(revs_loaded, False)81 revisions_loaded(revs_loaded, False)
@@ -86,28 +85,26 @@
86 throbber.show()85 throbber.show()
87 showed_throbber = True86 showed_throbber = True
88 update_ui()87 update_ui()
89 88
90 batch_revids = revids[offset:offset+batch_size]89 batch_revids = revids[offset:offset+batch_size]
91 90
92 if before_batch_load is not None:91 if before_batch_load is not None:
93 stop = before_batch_load(repo, batch_revids)92 stop = before_batch_load(repo, batch_revids)
94 if stop:93 if stop:
95 break94 break
96 95
97 for rev in repo.get_revisions(batch_revids):96 for rev in repo.get_revisions(batch_revids):
98 cached_revisions[rev.revision_id] = rev97 cached_revisions[rev.revision_id] = rev
99 return_revisions[rev.revision_id] = rev98 return_revisions[rev.revision_id] = rev
100 revs_loaded[rev.revision_id] = rev99 revs_loaded[rev.revision_id] = rev
101 rev.repository = repo100 rev.repository = repo
102 finally:101
103 repo.unlock()
104
105 if revisions_loaded is not None:102 if revisions_loaded is not None:
106 revisions_loaded(revs_loaded, True)103 revisions_loaded(revs_loaded, True)
107 finally:104 finally:
108 if showed_throbber:105 if showed_throbber:
109 throbber.hide()106 throbber.hide()
110 107
111 return return_revisions108 return return_revisions
112109
113def update_ui():110def update_ui():
114111
=== modified file 'lib/log.py'
--- lib/log.py 2022-01-08 11:48:59 +0000
+++ lib/log.py 2022-07-06 15:37:54 +0000
@@ -612,9 +612,8 @@
612 for repo, repo_revids in repos_revids:612 for repo, repo_revids in repos_revids:
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]
614 if repo_revids:614 if repo_revids:
615 repo.lock_read()615 with repo.lock_read():
616 self.processEvents()616 self.processEvents()
617 try:
618 for revid in repo_revids:617 for revid in repo_revids:
619 if (revid.startswith(CURRENT_REVISION) and gv_is_wtgv):618 if (revid.startswith(CURRENT_REVISION) and gv_is_wtgv):
620 tree = gv.working_trees[revid]619 tree = gv.working_trees[revid]
@@ -622,8 +621,6 @@
622 tree = repo.revision_tree(revid)621 tree = repo.revision_tree(revid)
623 self.tree_cache[revid] = tree622 self.tree_cache[revid] = tree
624 self.processEvents()623 self.processEvents()
625 finally:
626 repo.unlock()
627 self.processEvents()624 self.processEvents()
628625
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]])
@@ -830,13 +827,10 @@
830 tree = branch.repository.revision_tree(top_revid)827 tree = branch.repository.revision_tree(top_revid)
831 file_id = file_ids[0]828 file_id = file_ids[0]
832 path = paths[0]829 path = paths[0]
833 tree.lock_read()830 with tree.lock_read():
834 try:
835 kind = tree.kind(path)831 kind = tree.kind(path)
836 if kind == 'file':832 if kind == 'file':
837 file_content_bytes = tree.get_file_text(path)833 file_content_bytes = tree.get_file_text(path)
838 finally:
839 tree.unlock()
840 if kind != 'file':834 if kind != 'file':
841 QtWidgets.QMessageBox.information(self, gettext("Not a file"),835 QtWidgets.QMessageBox.information(self, gettext("Not a file"),
842 gettext("Operation is supported for a single file only,\n"836 gettext("Operation is supported for a single file only,\n"
@@ -844,11 +838,8 @@
844 return838 return
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]
846 if filename:840 if filename:
847 f = open(str(filename), 'wb')841 with open(str(filename), 'wb') as f:
848 try:
849 f.write(file_content_bytes)842 f.write(file_content_bytes)
850 finally:
851 f.close()
852843
853 @ui_current_widget844 @ui_current_widget
854 def revert_file(self):845 def revert_file(self):
855846
=== modified file 'lib/loggraphviz.py'
--- lib/loggraphviz.py 2021-08-05 11:27:16 +0000
+++ lib/loggraphviz.py 2022-07-06 15:37:54 +0000
@@ -219,7 +219,6 @@
219 finally:219 finally:
220 self.unlock_branches()220 self.unlock_branches()
221221
222
223 def load_current_dir_repo(self):222 def load_current_dir_repo(self):
224 # There are no local repositories. Try open the repository223 # There are no local repositories. Try open the repository
225 # of the current directory, and try load revisions data from224 # of the current directory, and try load revisions data from
@@ -1050,13 +1049,10 @@
1050 return_revisions = {}1049 return_revisions = {}
1051 for repo, revids in self.get_repo_revids(revids):1050 for repo, revids in self.get_repo_revids(revids):
1052 if revids:1051 if revids:
1053 repo.lock_read()1052 with repo.lock_read():
1054 try:
1055 self.update_ui()1053 self.update_ui()
1056 for rev in repo.get_revisions(revids):1054 for rev in repo.get_revisions(revids):
1057 return_revisions[rev.revision_id] = rev1055 return_revisions[rev.revision_id] = rev
1058 finally:
1059 repo.unlock()
1060 return return_revisions1056 return return_revisions
10611057
10621058
@@ -1443,8 +1439,7 @@
1443 if tree is None:1439 if tree is None:
1444 tree = bi.branch.basis_tree()1440 tree = bi.branch.basis_tree()
14451441
1446 tree.lock_read()1442 with tree.lock_read():
1447 try:
1448 for file_id in self.file_ids:1443 for file_id in self.file_ids:
1449 if tree.kind(tree.id2path(file_id)) in ('directory',1444 if tree.kind(tree.id2path(file_id)) in ('directory',
1450 'tree-reference'):1445 'tree-reference'):
@@ -1452,8 +1447,6 @@
1452 break1447 break
1453 if self.has_dir:1448 if self.has_dir:
1454 break1449 break
1455 finally:
1456 tree.unlock()
14571450
1458 if revids is None:1451 if revids is None:
1459 revids = [rev.revid for rev in self.graph_viz.revisions]1452 revids = [rev.revid for rev in self.graph_viz.revisions]
@@ -1485,8 +1478,7 @@
1485 self.filter_changed_callback(changed_revs, False)1478 self.filter_changed_callback(changed_revs, False)
1486 self.graph_viz.update_ui()1479 self.graph_viz.update_ui()
14871480
1488 repo.lock_read()1481 with repo.lock_read():
1489 try:
1490 if not self.uses_inventory():1482 if not self.uses_inventory():
1491 text_keys = [(file_id, revid)1483 text_keys = [(file_id, revid)
1492 for revid in revids1484 for revid in revids
@@ -1508,8 +1500,6 @@
1508 self.graph_viz.update_ui()1500 self.graph_viz.update_ui()
15091501
1510 check_text_keys(text_keys)1502 check_text_keys(text_keys)
1511 finally:
1512 repo.unlock()
15131503
1514 def load_filter_file_id_chunk_finished(self):1504 def load_filter_file_id_chunk_finished(self):
1515 self.filter_changed_callback([], True)1505 self.filter_changed_callback([], True)
@@ -1555,8 +1545,7 @@
15551545
1556 :return: True if a change is found. False otherwise1546 :return: True if a change is found. False otherwise
1557 """1547 """
1558 tree.lock_read()1548 with tree.lock_read():
1559 try:
1560 # Copied from mutabletree, cause we need file_ids too.1549 # Copied from mutabletree, cause we need file_ids too.
1561 # Check pending merges1550 # Check pending merges
1562 if len(tree.get_parent_ids()) > 1:1551 if len(tree.get_parent_ids()) > 1:
@@ -1579,8 +1568,6 @@
1579 except StopIteration:1568 except StopIteration:
1580 # No changes1569 # No changes
1581 return False1570 return False
1582 finally:
1583 tree.unlock()
15841571
1585 def get_revision_visible(self, rev):1572 def get_revision_visible(self, rev):
1586 if rev.revid.startswith(CURRENT_REVISION):1573 if rev.revid.startswith(CURRENT_REVISION):
15871574
=== modified file 'lib/spellcheck_enchant.py'
--- lib/spellcheck_enchant.py 2019-10-27 14:48:19 +0000
+++ lib/spellcheck_enchant.py 2022-07-06 15:37:54 +0000
@@ -30,7 +30,7 @@
30 text = self._text[offset:]30 text = self._text[offset:]
31 if not text:31 if not text:
32 raise StopIteration()32 raise StopIteration()
33 match = re.match('(\w+?)[A-Z]', text)33 match = re.match(br'(\w+?)[A-Z]', text)
34 if match is None:34 if match is None:
35 word = text35 word = text
36 else:36 else:
@@ -60,7 +60,7 @@
60 self.checker.set_text(text)60 self.checker.set_text(text)
61 for err in self.checker:61 for err in self.checker:
62 yield err.wordpos, len(err.word)62 yield err.wordpos, len(err.word)
63 63
64 def suggest(self, text):64 def suggest(self, text):
65 return self.dict.suggest(text)65 return self.dict.suggest(text)
6666
6767
=== modified file 'lib/subprocess.py'
--- lib/subprocess.py 2022-04-14 11:45:16 +0000
+++ lib/subprocess.py 2022-07-06 15:37:54 +0000
@@ -847,12 +847,9 @@
847 if not os.path.isdir(qdir):847 if not os.path.isdir(qdir):
848 os.makedirs(qdir)848 os.makedirs(qdir)
849 fd, fname = tempfile.mkstemp(dir=qdir)849 fd, fname = tempfile.mkstemp(dir=qdir)
850 f = os.fdopen(fd, "wb")850 with os.fdopen(fd, "wb") as f:
851 try:
852 # f.write(text.decode('utf8'))851 # f.write(text.decode('utf8'))
853 f.write(text)852 f.write(text)
854 finally:
855 f.close() # it closes fd as well
856 self._args_file = fname853 self._args_file = fname
857 return fname854 return fname
858855
@@ -1074,11 +1071,8 @@
1074 if s_cmd[0][0] == '@':1071 if s_cmd[0][0] == '@':
1075 fname = s_cmd[1:]1072 fname = s_cmd[1:]
1076 # Changed this: it's written in 'b' so must be read that way too1073 # Changed this: it's written in 'b' so must be read that way too
1077 f = open(fname, 'rb')1074 with open(fname, 'rb') as f:
1078 try:
1079 s_cmd = f.read()1075 s_cmd = f.read()
1080 finally:
1081 f.close()
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...:
1083 s_cmd = bencode.bdecode(s_cmd)1077 s_cmd = bencode.bdecode(s_cmd)
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...
10851079
=== modified file 'lib/tests/test_extdiff.py'
--- lib/tests/test_extdiff.py 2020-07-05 15:21:39 +0000
+++ lib/tests/test_extdiff.py 2022-07-06 15:37:54 +0000
@@ -25,11 +25,11 @@
2525
26 def test_no_arguments(self):26 def test_no_arguments(self):
27 self.differ.set_command_string("test")27 self.differ.set_command_string("test")
28 self.assertEqual(self.differ.command_template, ["test", "@old_path", "@new_path"])28 self.assertEqual(self.differ.command_template, ["test", "{old_path}", "{new_path}"])
2929
30 def test_has_arguments(self):30 def test_has_arguments(self):
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}")
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}"])
3333
34class TestPrefix(QTestCase):34class TestPrefix(QTestCase):
35 def setUp(self):35 def setUp(self):
@@ -221,7 +221,7 @@
221 def assertPopen(self, paths, old_contents):221 def assertPopen(self, paths, old_contents):
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):
223 # tool, old_path, new_path = args[0][0]223 # tool, old_path, new_path = args[0][0]
224 tool, _, _, old_path, new_path = args[0][0]224 tool, old_path, new_path = args[0][0]
225 self.assertEqual(tool, "diff.exe")225 self.assertEqual(tool, "diff.exe")
226 self.assertFileContent(old_path, old_content)226 self.assertFileContent(old_path, old_content)
227 self.assertEqual(new_path, self.tree.abspath(path))227 self.assertEqual(new_path, self.tree.abspath(path))
228228
=== modified file 'lib/tests/test_guidebar.py'
--- lib/tests/test_guidebar.py 2021-01-05 16:26:04 +0000
+++ lib/tests/test_guidebar.py 2022-07-06 15:37:54 +0000
@@ -24,7 +24,7 @@
24 def __init__(self, tree):24 def __init__(self, tree):
25 self.tree = tree25 self.tree = tree
2626
27 def get_diff_window_args(self, processEvents, add_cleanup):27 def get_diff_window_args(self, processEvents, es):
28 # This will be used by DiffWindow::_initial_load28 # This will be used by DiffWindow::_initial_load
29 return dict(29 return dict(
30 old_tree=self.tree.basis_tree(),30 old_tree=self.tree.basis_tree(),
3131
=== modified file 'lib/treewidget.py'
--- lib/treewidget.py 2022-01-08 11:48:59 +0000
+++ lib/treewidget.py 2022-07-06 15:37:54 +0000
@@ -485,16 +485,10 @@
485485
486 if isinstance(self.tree, WorkingTree):486 if isinstance(self.tree, WorkingTree):
487 # print(':::-> tree.lock_read (try) about to execute')487 # print(':::-> tree.lock_read (try) about to execute')
488 tree.lock_read()488 with tree.lock_read():
489 try:
490 # RJL Breezy release notes state that:
491 #
492 # The ``Tree.get_root_id`` method has been removed. Use``Tree.path2id('')`` instead. (Jelmer Vernooń≥)
493 #
494 root_id = self.tree.path2id('')489 root_id = self.tree.path2id('')
495 basis_tree = self.tree.basis_tree()490 basis_tree = self.tree.basis_tree()
496 basis_tree.lock_read()491 with basis_tree.lock_read():
497 try:
498 # print(':::->>second try block')492 # print(':::->>second try block')
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):
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.
@@ -641,12 +635,8 @@
641 dir_fileid = self.tree.path2id(dir_path)635 dir_fileid = self.tree.path2id(dir_path)
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)
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)
644 finally:
645 basis_tree.unlock()
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)
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)
648 finally:
649 tree.unlock()
650 else:640 else:
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)
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)
@@ -1579,11 +1569,8 @@
1579 self.change_load_filter = change_load_filter1569 self.change_load_filter = change_load_filter
15801570
1581 if branch:1571 if branch:
1582 branch.lock_read()1572 with branch.lock_read():
1583 try:
1584 last_revno = branch.last_revision_info()[0]1573 last_revno = branch.last_revision_info()[0]
1585 finally:
1586 branch.unlock()
1587 self.revno_item_delegate.set_max_revno(last_revno)1574 self.revno_item_delegate.set_max_revno(last_revno)
1588 # update width uncoditionally because we may change the revno column1575 # update width uncoditionally because we may change the revno column
1589 self.set_header_width_settings()1576 self.set_header_width_settings()
@@ -1656,8 +1643,7 @@
16561643
1657 def restore_state(self, state):1644 def restore_state(self, state):
1658 (checked, expanded, selected, v_scroll) = state1645 (checked, expanded, selected, v_scroll) = state
1659 self.tree.lock_read()1646 with self.tree.lock_read():
1660 try:
1661 if self.tree_model.checkable and checked is not None:1647 if self.tree_model.checkable and checked is not None:
1662 for (ref, state) in checked:1648 for (ref, state) in checked:
1663 if not state == QtCore.Qt.PartiallyChecked:1649 if not state == QtCore.Qt.PartiallyChecked:
@@ -1679,12 +1665,9 @@
1679 QtCore.QItemSelectionModel.SelectCurrent |1665 QtCore.QItemSelectionModel.SelectCurrent |
1680 QtCore.QItemSelectionModel.Rows)1666 QtCore.QItemSelectionModel.Rows)
1681 self.verticalScrollBar().setValue(v_scroll)1667 self.verticalScrollBar().setValue(v_scroll)
1682 finally:
1683 self.tree.unlock()
16841668
1685 def refresh(self):1669 def refresh(self):
1686 self.tree.lock_read()1670 with self.tree.lock_read():
1687 try:
1688 state = self.get_state()1671 state = self.get_state()
1689 self.tree_model.set_tree(self.tree, self.branch,1672 self.tree_model.set_tree(self.tree, self.branch,
1690 self.changes_mode, self.want_unversioned,1673 self.changes_mode, self.want_unversioned,
@@ -1699,8 +1682,6 @@
1699 # after every time we do a layout changed. The issue is similar to1682 # after every time we do a layout changed. The issue is similar to
1700 # http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=2367551683 # http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=236755
1701 self.set_header_width_settings()1684 self.set_header_width_settings()
1702 finally:
1703 self.tree.unlock()
17041685
1705 def mousePressEvent(self, event):1686 def mousePressEvent(self, event):
1706 index = self.indexAt(event.pos())1687 index = self.indexAt(event.pos())
@@ -1917,11 +1898,8 @@
1917 item = items[0]1898 item = items[0]
19181899
1919 if isinstance(self.tree, WorkingTree):1900 if isinstance(self.tree, WorkingTree):
1920 self.tree.lock_read()1901 with self.tree.lock_read():
1921 try:
1922 abspath = self.tree.abspath(item.path)1902 abspath = self.tree.abspath(item.path)
1923 finally:
1924 self.tree.unlock()
1925 url = QtCore.QUrl.fromLocalFile(abspath)1903 url = QtCore.QUrl.fromLocalFile(abspath)
1926 QtGui.QDesktopServices.openUrl(url)1904 QtGui.QDesktopServices.openUrl(url)
1927 else:1905 else:
@@ -2020,11 +1998,8 @@
2020 QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)1998 QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
2021 if res == QtWidgets.QMessageBox.Yes:1999 if res == QtWidgets.QMessageBox.Yes:
2022 try:2000 try:
2023 self.tree.lock_write()2001 with self.tree.lock_write():
2024 try:
2025 self.tree.revert(paths, self.tree.basis_tree())2002 self.tree.revert(paths, self.tree.basis_tree())
2026 finally:
2027 self.tree.unlock()
2028 except Exception:2003 except Exception:
2029 report_exception(type=SUB_LOAD_METHOD, window=self.window())2004 report_exception(type=SUB_LOAD_METHOD, window=self.window())
2030 # XXX - it would be good it we could just refresh the selected items2005 # XXX - it would be good it we could just refresh the selected items
20312006
=== modified file 'lib/widgets/shelve.py'
--- lib/widgets/shelve.py 2021-01-06 09:29:35 +0000
+++ lib/widgets/shelve.py 2022-07-06 15:37:54 +0000
@@ -17,6 +17,8 @@
17# along with this program; if not, write to the Free Software17# along with this program; if not, write to the Free Software
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.
1919
20from contextlib import ExitStack
21import os
20import sys, time22import sys, time
21from PyQt5 import QtCore, QtGui, QtWidgets23from PyQt5 import QtCore, QtGui, QtWidgets
2224
@@ -56,8 +58,6 @@
56from breezy.shelf import ShelfCreator58from breezy.shelf import ShelfCreator
57from breezy.shelf_ui import Shelver59from breezy.shelf_ui import Shelver
58from breezy.osutils import split_lines60from breezy.osutils import split_lines
59from cStringIO import StringIO
60import os
61''')61''')
6262
6363
@@ -453,15 +453,14 @@
453 self.hunk_view.set_tab_width(pixels)453 self.hunk_view.set_tab_width(pixels)
454454
455 def refresh(self):455 def refresh(self):
456 cleanup = []456 with ExitStack() as es:
457 try:
458 old_rev = self.revision457 old_rev = self.revision
459 old_changes = self._get_change_dictionary()458 old_changes = self._get_change_dictionary()
460 self.clear(clear_message = False)459 self.clear(clear_message = False)
461460
462 shelver, creator = self._create_shelver_and_creator()461 shelver, creator = self._create_shelver_and_creator()
463 cleanup.append(shelver.finalize)462 es.callback(shelver.finalize)
464 cleanup.append(creator.finalize)463 es.callback(creator.finalize)
465464
466 file_list = shelver.file_list465 file_list = shelver.file_list
467 if file_list:466 if file_list:
@@ -489,10 +488,6 @@
489 item = self._create_item(change, shelver, self.trees, old_changes)488 item = self._create_item(change, shelver, self.trees, old_changes)
490 self.file_view.addTopLevelItem(item)489 self.file_view.addTopLevelItem(item)
491490
492 finally:
493 for func in cleanup:
494 func()
495
496 if self.select_all:491 if self.select_all:
497 self.check_all(True)492 self.check_all(True)
498 self.select_all = False493 self.select_all = False
@@ -625,16 +620,15 @@
625 self.loaded = False620 self.loaded = False
626621
627 def use_editor(self):622 def use_editor(self):
628 cleanup = []
629 items = self.file_view.selectedItems()623 items = self.file_view.selectedItems()
630 if len(items) != 1 or items[0].change.status != 'modify text':624 if len(items) != 1 or items[0].change.status != 'modify text':
631 return625 return
632 else:626 else:
633 change = items[0].change627 change = items[0].change
634 try:628 with ExitStack() as es:
635 target_tree, work_tree = self.trees629 target_tree, work_tree = self.trees
636 cleanup.append(work_tree.lock_read().unlock)630 es.enter_context(work_tree.lock_read())
637 cleanup.append(target_tree.lock_read().unlock)631 es.enter_context(target_tree.lock_read())
638 config = work_tree.branch.get_config()632 config = work_tree.branch.get_config()
639 change_editor = config.get_change_editor(target_tree, work_tree)633 change_editor = config.get_change_editor(target_tree, work_tree)
640 if change_editor is None:634 if change_editor is None:
@@ -643,16 +637,13 @@
643 self.editor_button.setEnabled(False)637 self.editor_button.setEnabled(False)
644 return638 return
645639
646 cleanup.append(change_editor.finish)640 es.callback(change_editor.finish)
647 lines = split_lines(change_editor.edit_file(change.file_id))641 lines = split_lines(change_editor.edit_file(change.file_id))
648 change_count = Shelver._count_changed_regions(change.work_lines, lines)642 change_count = Shelver._count_changed_regions(change.work_lines, lines)
649 if change_count > 0:643 if change_count > 0:
650 change.edited_lines = lines644 change.edited_lines = lines
651 self.update_item(items[0])645 self.update_item(items[0])
652 self.selected_file_changed()646 self.selected_file_changed()
653 finally:
654 while cleanup:
655 cleanup.pop()()
656647
657 def _get_change_dictionary(self):648 def _get_change_dictionary(self):
658 change_dict = {}649 change_dict = {}
@@ -683,59 +674,56 @@
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'))
684 return675 return
685676
686 cleanup = []677 with ExitStack() as es:
687 try:678 try:
688 shelver, creator = self._create_shelver_and_creator(destroy=destroy)679 shelver, creator = self._create_shelver_and_creator(destroy=destroy)
689 cleanup.append(shelver.finalize)680 es.callback(shelver.finalize)
690 cleanup.append(creator.finalize)681 es.callback(creator.finalize)
691 trees = (shelver.target_tree, shelver.work_tree)682 trees = (shelver.target_tree, shelver.work_tree)
692 if len(trees[1].get_parent_ids()) > 1:683 if len(trees[1].get_parent_ids()) > 1:
693 raise WorkingTreeHasPendingMarge684 raise WorkingTreeHasPendingMarge
694 if self.revision != trees[0].get_revision_id():685 if self.revision != trees[0].get_revision_id():
695 raise WorkingTreeHasChanged686 raise WorkingTreeHasChanged
696687
697 changes = []688 changes = []
698 for ch in creator.iter_shelvable():689 for ch in creator.iter_shelvable():
699 change = Change(ch, shelver, trees)690 change = Change(ch, shelver, trees)
700 key = (change.file_id, change.status)691 key = (change.file_id, change.status)
701 org_change = change_dict.get(key)692 org_change = change_dict.get(key)
702 if org_change is None:693 if org_change is None:
703 continue694 continue
704 if not change.is_same_change(org_change):695 if not change.is_same_change(org_change):
705 raise WorkingTreeHasChanged696 raise WorkingTreeHasChanged
706 del(change_dict[key])697 del(change_dict[key])
707 changes.append(org_change)698 changes.append(org_change)
708699
709 if change_dict:700 if change_dict:
710 raise WorkingTreeHasChanged701 raise WorkingTreeHasChanged
711702
712 for change in changes:703 for change in changes:
713 if change.status == 'modify text':704 if change.status == 'modify text':
714 self.handle_modify_text(creator, change)705 self.handle_modify_text(creator, change)
715 elif change.status == 'modify binary':706 elif change.status == 'modify binary':
716 creator.shelve_content_change(change.data[1])707 creator.shelve_content_change(change.data[1])
708 else:
709 creator.shelve_change(change.data)
710 manager = shelver.work_tree.get_shelf_manager()
711 message = str(self.message.toPlainText()).strip() or gettext('<no message>')
712 if destroy:
713 creator.transform()
714 shelf_id = -1
717 else:715 else:
718 creator.shelve_change(change.data)716 shelf_id = manager.shelve_changes(creator, message)
719 manager = shelver.work_tree.get_shelf_manager()717
720 message = str(self.message.toPlainText()).strip() or gettext('<no message>')718 except WorkingTreeHasPendingMarge:
721 if destroy:719 QtWidgets.QMessageBox.warning(self, gettext('Shelve'),
722 creator.transform()720 gettext('Operation aborted because working tree has pending merges.'), gettext('&OK'))
723 shelf_id = -1721 return
724 else:722 except WorkingTreeHasChanged:
725 shelf_id = manager.shelve_changes(creator, message)723 QtWidgets.QMessageBox.warning(self, gettext('Shelve'),
726724 gettext('Operation aborted because target files has been changed.'), gettext('&OK'))
727 except WorkingTreeHasPendingMarge:725 return
728 QtWidgets.QMessageBox.warning(self, gettext('Shelve'),726
729 gettext('Operation aborted because working tree has pending merges.'), gettext('&OK'))
730 return
731 except WorkingTreeHasChanged:
732 QtWidgets.QMessageBox.warning(self, gettext('Shelve'),
733 gettext('Operation aborted because target files has been changed.'), gettext('&OK'))
734 return
735
736 finally:
737 while cleanup:
738 cleanup.pop()()
739 self.shelfCreated.emit(shelf_id)727 self.shelfCreated.emit(shelf_id)
740 self.clear()728 self.clear()
741729
@@ -888,12 +876,12 @@
888 continue876 continue
889 if bottom < y1:877 if bottom < y1:
890 break878 break
891 painter.fillRect(6, y1, 13, 13, QtCore.Qt.white)879 painter.fillRect(6, int(y1), 13, 13, QtCore.Qt.white)
892880
893 painter.drawRect(6, y1, 13, 13)881 painter.drawRect(6, int(y1), 13, 13)
894 if hunk.selected:882 if hunk.selected:
895 painter.drawLine(9, y1 + 7, 12, y1 + 10)883 painter.drawLine(9, int(y1) + 7, 12, int(y1) + 10)
896 painter.drawLine(16, y1 + 3, 12, y1 + 10)884 painter.drawLine(16, int(y1) + 3, 12, int(y1) + 10)
897885
898 del painter886 del painter
899887
@@ -942,7 +930,7 @@
942 self.monospacedInactiveFormat.setForeground(QtGui.QColor(128, 128, 128))930 self.monospacedInactiveFormat.setForeground(QtGui.QColor(128, 128, 128))
943931
944 titleFont = QtGui.QFont(monospacedFont)932 titleFont = QtGui.QFont(monospacedFont)
945 titleFont.setPointSize(titleFont.pointSize() * 140 / 100)933 titleFont.setPointSize(titleFont.pointSize() * 140 // 100)
946 titleFont.setBold(True)934 titleFont.setBold(True)
947 titleFont.setItalic(True)935 titleFont.setItalic(True)
948936
@@ -1062,17 +1050,17 @@
1062 continue1050 continue
1063 if not self.complete:1051 if not self.complete:
1064 # Fill header rect.1052 # Fill header rect.
1065 painter.fillRect(left, y1, width, 20, self.header_color)1053 painter.fillRect(left, int(y1), width, 20, self.header_color)
1066 # Overlay focus rect.1054 # Overlay focus rect.
1067 if i == self._focused_index:1055 if i == self._focused_index:
1068 if self.hasFocus():1056 if self.hasFocus():
1069 color = self.focus_color1057 color = self.focus_color
1070 else:1058 else:
1071 color = self.focus_color_inactive1059 color = self.focus_color_inactive
1072 painter.fillRect(left, y1, width, y2 - y1, color)1060 painter.fillRect(left, int(y1), width, int(y2 - y1), color)
1073 # Draw border.1061 # Draw border.
1074 painter.drawLine(left, y1, right, y1)1062 painter.drawLine(left, int(y1), right, int(y1))
1075 painter.drawLine(left, y2, right, y2)1063 painter.drawLine(left, int(y2), right, int(y2))
10761064
1077 def move_next(self):1065 def move_next(self):
1078 index = int(self._focused_index + 1)1066 index = int(self._focused_index + 1)
@@ -1127,8 +1115,8 @@
1127 MARGIN = 241115 MARGIN = 24
1128 height = self.viewport().height()1116 height = self.viewport().height()
1129 cur_pos = sbar.value()1117 cur_pos = sbar.value()
1130 max_pos = self.hunk_list[index][1] - MARGIN1118 max_pos = int(self.hunk_list[index][1] - MARGIN)
1131 min_pos = self.hunk_list[index][2] - height + MARGIN1119 min_pos = int(self.hunk_list[index][2] - height + MARGIN)
1132 if max_pos <= min_pos or max_pos < cur_pos:1120 if max_pos <= min_pos or max_pos < cur_pos:
1133 sbar.setValue(max_pos)1121 sbar.setValue(max_pos)
1134 elif cur_pos < min_pos:1122 elif cur_pos < min_pos:
11351123
=== modified file 'lib/widgets/shelvelist.py'
--- lib/widgets/shelvelist.py 2021-01-06 09:29:35 +0000
+++ lib/widgets/shelvelist.py 2022-07-06 15:37:54 +0000
@@ -17,6 +17,8 @@
17# along with this program; if not, write to the Free Software17# along with this program; if not, write to the Free Software
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.
1919
20from contextlib import ExitStack
21
20import sys, time22import sys, time
21from PyQt5 import QtCore, QtGui, QtWidgets23from PyQt5 import QtCore, QtGui, QtWidgets
22from PyQt5.QtGui import QKeySequence24from PyQt5.QtGui import QKeySequence
@@ -55,7 +57,6 @@
55from breezy.plugins.qbrz.lib.widgets.texteditaccessory import setup_guidebar_for_find57from breezy.plugins.qbrz.lib.widgets.texteditaccessory import setup_guidebar_for_find
56from breezy.lazy_import import lazy_import58from breezy.lazy_import import lazy_import
57lazy_import(globals(), '''59lazy_import(globals(), '''
58from breezy import transform
59from breezy.workingtree import WorkingTree60from breezy.workingtree import WorkingTree
60from breezy.plugins.qbrz.lib.encoding_selector import EncodingMenuSelector61from breezy.plugins.qbrz.lib.encoding_selector import EncodingMenuSelector
61from breezy.plugins.qbrz.lib.diff import DiffItem62from breezy.plugins.qbrz.lib.diff import DiffItem
@@ -274,8 +275,7 @@
274 self.loaded = False275 self.loaded = False
275 self.clear()276 self.clear()
276 tree = WorkingTree.open_containing(self.directory)[0]277 tree = WorkingTree.open_containing(self.directory)[0]
277 tree.lock_read()278 with tree.lock_read():
278 try:
279 manager = tree.get_shelf_manager()279 manager = tree.get_shelf_manager()
280 shelves = manager.active_shelves()280 shelves = manager.active_shelves()
281 for shelf_id in reversed(shelves):281 for shelf_id in reversed(shelves):
@@ -298,8 +298,6 @@
298 self.tabwidth_selector.setTabWidth(tabwidth)298 self.tabwidth_selector.setTabWidth(tabwidth)
299 self._on_tabwidth_changed(tabwidth)299 self._on_tabwidth_changed(tabwidth)
300300
301 finally:
302 tree.unlock()
303 self.update()301 self.update()
304 self.loaded = True302 self.loaded = True
305303
@@ -312,18 +310,17 @@
312 self.manager = None310 self.manager = None
313311
314 def show_changes(self, shelf_id):312 def show_changes(self, shelf_id):
315 cleanup = []
316 shelf_file = self.manager.read_shelf(shelf_id)313 shelf_file = self.manager.read_shelf(shelf_id)
317 cleanup.append(shelf_file.close)314 with ExitStack() as es:
318 try:315 es.callback(shelf_file.close)
319 records = Unshelver.iter_records(shelf_file)316 records = Unshelver.iter_records(shelf_file)
320 revid = Unshelver.parse_metadata(records)[b'revision_id']317 revid = Unshelver.parse_metadata(records)[b'revision_id']
321 try:318 try:
322 base_tree = self.tree.revision_tree(revid)319 base_tree = self.tree.revision_tree(revid)
323 except NoSuchRevisionInTree:320 except NoSuchRevisionInTree:
324 base_tree = self.tree.branch.repository.revision_tree(revid)321 base_tree = self.tree.branch.repository.revision_tree(revid)
325 preview = transform.TransformPreview(base_tree)322 preview = base_tree.preview_transform()
326 cleanup.append(preview.finalize)323 es.callback(preview.finalize)
327 preview.deserialize(records)324 preview.deserialize(records)
328325
329 tabwidth = get_tab_width_pixels(self.tree.branch)326 tabwidth = get_tab_width_pixels(self.tree.branch)
@@ -332,10 +329,6 @@
332329
333 self.load_diff(preview.get_preview_tree(), base_tree)330 self.load_diff(preview.get_preview_tree(), base_tree)
334331
335 finally:
336 for func in cleanup:
337 func()
338
339 def load_diff(self, tree, base_tree):332 def load_diff(self, tree, base_tree):
340 self.file_view.clear()333 self.file_view.clear()
341334

Subscribers

People subscribed via source and target branches

to all changes: