[Pkg-bazaar-commits] ./bzr-gtk/unstable r492: Allow saving from patch window, refactoring, testing.

Aaron Bentley aaron at aaronbentley.com
Fri Apr 10 07:50:32 UTC 2009


------------------------------------------------------------
revno: 492
committer: Aaron Bentley <aaron at aaronbentley.com>
branch nick: bzr-gtk
timestamp: Wed 2008-05-21 22:33:40 -0400
message:
  Allow saving from patch window, refactoring, testing.
modified:
  __init__.py
  diff.py
  tests/test_diff.py
    ------------------------------------------------------------
    revno: 487.2.1
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: save-patch
    timestamp: Thu 2008-05-08 20:16:51 +1200
    message:
      Refactor merge directive window into MergeController
    modified:
      __init__.py
      diff.py
    ------------------------------------------------------------
    revno: 487.2.2
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: save-patch
    timestamp: Thu 2008-05-08 20:45:15 +1200
    message:
      Unify MergeDirectiveWindow and DiffWindow
    modified:
      __init__.py
      diff.py
    ------------------------------------------------------------
    revno: 487.2.3
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: save-patch
    timestamp: Thu 2008-05-08 21:56:34 +1200
    message:
      Much refactoring
    modified:
      diff.py
    ------------------------------------------------------------
    revno: 487.2.4
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: save-patch
    timestamp: Fri 2008-05-09 11:23:47 +1200
    message:
      Add tests for DiffController
    modified:
      tests/test_diff.py
    ------------------------------------------------------------
    revno: 487.2.5
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: save-patch
    timestamp: Fri 2008-05-09 15:34:41 +1200
    message:
      Test successful merge
    modified:
      diff.py
      tests/test_diff.py
    ------------------------------------------------------------
    revno: 487.2.6
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: save-patch
    timestamp: Fri 2008-05-09 15:41:19 +1200
    message:
      Ensure MergeController sets pending merges and updates files
    modified:
      tests/test_diff.py
    ------------------------------------------------------------
    revno: 487.2.7
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: save-patch
    timestamp: Sat 2008-05-10 15:23:00 +1200
    message:
      Add more merge tests
    modified:
      diff.py
      tests/test_diff.py
    ------------------------------------------------------------
    revno: 487.2.8
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: save-patch
    timestamp: Mon 2008-05-12 16:21:45 -0400
    message:
      Update error handling to use window
    modified:
      diff.py
      tests/test_diff.py
-------------- next part --------------
=== modified file '__init__.py'
--- a/__init__.py	2008-05-22 02:22:38 +0000
+++ b/__init__.py	2008-05-22 02:33:40 +0000
@@ -705,8 +705,8 @@
 
     def run(self, path):
         try:
-            from bzrlib.plugins.gtk.diff import (DiffWindow,
-                                                 MergeDirectiveWindow)
+            from bzrlib.plugins.gtk.diff import (DiffController,
+                                                 MergeDirectiveController)
             if path == '-':
                 lines = sys.stdin.readlines()
             else:
@@ -715,11 +715,10 @@
             try:
                 directive = merge_directive.MergeDirective.from_lines(lines)
             except errors.NotAMergeDirective:
-                window = DiffWindow()
-                window.set_diff_text(path, lines)
+                controller = DiffController(path, lines)
             else:
-                window = MergeDirectiveWindow(directive, path)
-                window.set_diff_text(path, directive.patch.splitlines(True))
+                controller = MergeDirectiveController(path, directive)
+            window = controller.window
             window.show()
             gtk = self.open_display()
             window.connect("destroy", gtk.main_quit)

=== modified file 'diff.py'
--- a/diff.py	2008-05-05 18:16:46 +0000
+++ b/diff.py	2008-05-22 02:33:40 +0000
@@ -328,16 +328,16 @@
         """
         # The diffs of the  selected file: a scrollable source or
         # text view
+
+    def set_diff_text_sections(self, sections):
         self.diff_view = DiffFileView()
         self.diff_view.show()
         self.pack2(self.diff_view)
-        self.model.append(None, [ "Complete Diff", "" ])
-        self.diff_view._diffs[None] = ''.join(lines)
-        for patch in parse_patches(lines):
-            oldname = patch.oldname.split('\t')[0]
-            newname = patch.newname.split('\t')[0]
+        for oldname, newname, patch in sections:
+            self.diff_view._diffs[newname] = str(patch)
+            if newname is None:
+                newname = ''
             self.model.append(None, [oldname, newname])
-            self.diff_view._diffs[newname] = str(patch)
         self.diff_view.show_diff(None)
 
     def set_diff(self, rev_tree, parent_tree):
@@ -413,7 +413,7 @@
     differences between two revisions on a branch.
     """
 
-    def __init__(self, parent=None):
+    def __init__(self, parent=None, operations=None):
         Window.__init__(self, parent)
         self.set_border_width(0)
         self.set_title("bzrk diff")
@@ -424,36 +424,79 @@
         width = int(monitor.width * 0.66)
         height = int(monitor.height * 0.66)
         self.set_default_size(width, height)
-
-        self.construct()
-
-    def construct(self):
+        self.construct(operations)
+
+    def construct(self, operations):
         """Construct the window contents."""
         self.vbox = gtk.VBox()
         self.add(self.vbox)
         self.vbox.show()
-        hbox = self._get_button_bar()
+        hbox = self._get_button_bar(operations)
         if hbox is not None:
             self.vbox.pack_start(hbox, expand=False, fill=True)
         self.diff = DiffWidget()
         self.vbox.add(self.diff)
         self.diff.show_all()
 
-    def _get_button_bar(self):
+    def _get_button_bar(self, operations):
         """Return a button bar to use.
 
         :return: None, meaning that no button bar will be used.
         """
-        return None
-
-    def set_diff_text(self, description, lines):
-        """Set the diff from a text.
-
-        The diff must be in unified diff format, and will be parsed to
-        determine filenames.
-        """
-        self.diff.set_diff_text(lines)
-        self.set_title(description + " - bzrk diff")
+        if operations is None:
+            return None
+        hbox = gtk.HButtonBox()
+        hbox.set_layout(gtk.BUTTONBOX_START)
+        for title, method in operations:
+            merge_button = gtk.Button(title)
+            merge_button.show()
+            merge_button.set_relief(gtk.RELIEF_NONE)
+            merge_button.connect("clicked", method)
+            hbox.pack_start(merge_button, expand=False, fill=True)
+        hbox.show()
+        return hbox
+
+    def _get_merge_target(self):
+        d = gtk.FileChooserDialog('Merge branch', self,
+                                  gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                                  buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
+                                           gtk.STOCK_CANCEL,
+                                           gtk.RESPONSE_CANCEL,))
+        try:
+            result = d.run()
+            if result != gtk.RESPONSE_OK:
+                raise SelectCancelled()
+            return d.get_current_folder_uri()
+        finally:
+            d.destroy()
+
+    def _merge_successful(self):
+        # No conflicts found.
+        info_dialog(_i18n('Merge successful'),
+                    _i18n('All changes applied successfully.'))
+
+    def _conflicts(self):
+        warning_dialog(_i18n('Conflicts encountered'),
+                       _i18n('Please resolve the conflicts manually'
+                             ' before committing.'))
+
+    def _handle_error(self, e):
+        error_dialog('Error', str(e))
+
+    def _get_save_path(self, basename):
+        d = gtk.FileChooserDialog('Save As', self,
+                                  gtk.FILE_CHOOSER_ACTION_SAVE,
+                                  buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
+                                           gtk.STOCK_CANCEL,
+                                           gtk.RESPONSE_CANCEL,))
+        d.set_current_name(basename)
+        try:
+            result = d.run()
+            if result != gtk.RESPONSE_OK:
+                raise SelectCancelled()
+            return urlutils.local_path_from_url(d.get_uri())
+        finally:
+            d.destroy()
 
     def set_diff(self, description, rev_tree, parent_tree):
         """Set the differences showed by this window.
@@ -468,38 +511,64 @@
         self.diff.set_file(file_path)
 
 
-class MergeDirectiveWindow(DiffWindow):
-
-    def __init__(self, directive, path):
-        DiffWindow.__init__(self, None)
-        self._merge_target = None
+class DiffController(object):
+
+    def __init__(self, path, patch, window=None):
+        self.path = path
+        self.patch = patch
+        if window is None:
+            window = DiffWindow(operations=self._provide_operations())
+            self.initialize_window(window)
+        self.window = window
+
+    def initialize_window(self, window):
+        window.diff.set_diff_text_sections(self.get_diff_sections())
+        window.set_title(self.path + " - diff")
+
+    def get_diff_sections(self):
+        yield "Complete Diff", None, ''.join(self.patch)
+        for patch in parse_patches(self.patch):
+            oldname = patch.oldname.split('\t')[0]
+            newname = patch.newname.split('\t')[0]
+            yield oldname, newname, str(patch)
+
+    def perform_save(self, window):
+        try:
+            save_path = self.window._get_save_path(osutils.basename(self.path))
+        except SelectCancelled:
+            return
+        source = open(self.path, 'rb')
+        try:
+            target = open(save_path, 'wb')
+            try:
+                osutils.pumpfile(source, target)
+            finally:
+                target.close()
+        finally:
+            source.close()
+
+    def _provide_operations(self):
+        return [('Save', self.perform_save)]
+
+
+class MergeDirectiveController(DiffController):
+
+    def __init__(self, path, directive, window=None):
+        DiffController.__init__(self, path, directive.patch.splitlines(True),
+                                window)
         self.directive = directive
-        self.path = path
-
-    def _get_button_bar(self):
-        """The button bar has only the Merge button"""
-        merge_button = gtk.Button('Merge')
-        merge_button.show()
-        merge_button.set_relief(gtk.RELIEF_NONE)
-        merge_button.connect("clicked", self.perform_merge)
-
-        save_button = gtk.Button('Save')
-        save_button.show()
-        save_button.set_relief(gtk.RELIEF_NONE)
-        save_button.connect("clicked", self.perform_save)
-
-        hbox = gtk.HButtonBox()
-        hbox.set_layout(gtk.BUTTONBOX_START)
-        hbox.pack_start(merge_button, expand=False, fill=True)
-        hbox.pack_start(save_button, expand=False, fill=True)
-        hbox.show()
-        return hbox
+        self.merge_target = None
+
+    def _provide_operations(self):
+        return [('Merge', self.perform_merge), ('Save', self.perform_save)]
 
     def perform_merge(self, window):
-        try:
-            tree = self._get_merge_target()
-        except SelectCancelled:
-            return
+        if self.merge_target is None:
+            try:
+                self.merge_target = self.window._get_merge_target()
+            except SelectCancelled:
+                return
+        tree = workingtree.WorkingTree.open(self.merge_target)
         tree.lock_write()
         try:
             try:
@@ -510,64 +579,16 @@
                 conflict_count = merger.do_merge()
                 merger.set_pending()
                 if conflict_count == 0:
-                    # No conflicts found.
-                    info_dialog(_i18n('Merge successful'),
-                                _i18n('All changes applied successfully.'))
+                    self.window._merge_successful()
                 else:
+                    self.window._conflicts()
                     # There are conflicts to be resolved.
-                    warning_dialog(_i18n('Conflicts encountered'),
-                                   _i18n('Please resolve the conflicts manually'
-                                         ' before committing.'))
-                self.destroy()
+                self.window.destroy()
             except Exception, e:
-                error_dialog('Error', str(e))
+                self.window._handle_error(e)
         finally:
             tree.unlock()
 
-    def _get_merge_target(self):
-        if self._merge_target is not None:
-            return self._merge_target
-        d = gtk.FileChooserDialog('Merge branch', self,
-                                  gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
-                                  buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
-                                           gtk.STOCK_CANCEL,
-                                           gtk.RESPONSE_CANCEL,))
-        try:
-            result = d.run()
-            if result != gtk.RESPONSE_OK:
-                raise SelectCancelled()
-            uri = d.get_current_folder_uri()
-        finally:
-            d.destroy()
-        return workingtree.WorkingTree.open(uri)
-
-    def perform_save(self, window):
-        d = gtk.FileChooserDialog('Save As', self,
-                                  gtk.FILE_CHOOSER_ACTION_SAVE,
-                                  buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
-                                           gtk.STOCK_CANCEL,
-                                           gtk.RESPONSE_CANCEL,))
-        d.set_current_name(osutils.basename(self.path))
-        try:
-            try:
-                result = d.run()
-                if result != gtk.RESPONSE_OK:
-                    raise SelectCancelled()
-                uri = d.get_uri()
-            finally:
-                d.destroy()
-        except SelectCancelled:
-            return
-        source = open(self.path, 'rb')
-        try:
-            target = open(urlutils.local_path_from_url(uri), 'wb')
-            try:
-                target.write(source.read())
-            finally:
-                target.close()
-        finally:
-            source.close()
-
 
 def iter_changes_to_status(source, target):
     """Determine the differences between trees.

=== modified file 'tests/test_diff.py'
--- a/tests/test_diff.py	2008-03-11 13:18:28 +0000
+++ b/tests/test_diff.py	2008-05-12 20:21:45 +0000
@@ -18,10 +18,33 @@
 from cStringIO import StringIO
 import os
 
-from bzrlib import tests
-
-from bzrlib.plugins.gtk.diff import DiffView, iter_changes_to_status
-
+from bzrlib import errors, tests
+from bzrlib.merge_directive import MergeDirective
+
+from bzrlib.plugins.gtk.diff import (
+    DiffController,
+    DiffView,
+    iter_changes_to_status,
+    MergeDirectiveController,
+    )
+eg_diff = """\
+=== modified file 'tests/test_diff.py'
+--- tests/test_diff.py	2008-03-11 13:18:28 +0000
++++ tests/test_diff.py	2008-05-08 22:44:02 +0000
+@@ -20,7 +20,11 @@
+ 
+ from bzrlib import tests
+ 
+-from bzrlib.plugins.gtk.diff import DiffView, iter_changes_to_status
++from bzrlib.plugins.gtk.diff import (
++    DiffController,
++    DiffView,
++    iter_changes_to_status,
++    )
+ 
+ 
+ class TestDiffViewSimple(tests.TestCase):
+"""
 
 class TestDiffViewSimple(tests.TestCase):
 
@@ -69,6 +92,122 @@
             )
 
 
+class MockDiffWidget(object):
+
+    def set_diff_text_sections(self, sections):
+        self.sections = list(sections)
+
+
+class MockWindow(object):
+    def __init__(self):
+        self.diff = MockDiffWidget()
+        self.merge_successful = False
+
+    def set_title(self, title):
+        self.title = title
+
+    def _get_save_path(self, basename):
+        return 'save-path'
+
+    def _get_merge_target(self):
+        return 'this'
+
+    def destroy(self):
+        pass
+
+    def _merge_successful(self):
+        self.merge_successful = True
+
+    def _conflicts(self):
+        self.conflicts = True
+
+    def _handle_error(self, e):
+        self.handled_error = e
+
+
+class TestDiffController(tests.TestCaseWithTransport):
+
+    def get_controller(self):
+        window = MockWindow()
+        return DiffController('load-path', eg_diff.splitlines(True), window)
+
+    def test_get_diff_sections(self):
+        controller = self.get_controller()
+        controller = DiffController('.', eg_diff.splitlines(True),
+                                    controller.window)
+        sections = list(controller.get_diff_sections())
+        self.assertEqual('Complete Diff', sections[0][0])
+        self.assertIs(None, sections[0][1])
+        self.assertEqual(eg_diff, sections[0][2])
+
+        self.assertEqual('tests/test_diff.py', sections[1][0])
+        self.assertEqual('tests/test_diff.py', sections[1][1])
+        self.assertEqual(''.join(eg_diff.splitlines(True)[1:]),
+                         sections[1][2])
+
+    def test_initialize_window(self):
+        controller = self.get_controller()
+        controller.initialize_window(controller.window)
+        self.assertEqual(2, len(controller.window.diff.sections))
+        self.assertEqual('load-path - diff', controller.window.title)
+
+    def test_perform_save(self):
+        self.build_tree_contents([('load-path', 'foo')])
+        controller = self.get_controller()
+        controller.perform_save(None)
+        self.assertFileEqual('foo', 'save-path')
+
+
+class TestMergeDirectiveController(tests.TestCaseWithTransport):
+
+    def make_this_other_directive(self):
+        this = self.make_branch_and_tree('this')
+        this.commit('first commit')
+        other = this.bzrdir.sprout('other').open_workingtree()
+        self.build_tree_contents([('other/foo', 'bar')])
+        other.add('foo')
+        other.commit('second commit')
+        other.lock_write()
+        try:
+            directive = MergeDirective.from_objects(other.branch.repository,
+                                                    other.last_revision(), 0,
+                                                    0, 'this')
+        finally:
+            other.unlock()
+        return this, other, directive
+
+    def make_merged_window(self, directive):
+        window = MockWindow()
+        controller = MergeDirectiveController('directive', directive, window)
+        controller.perform_merge(window)
+        return window
+
+    def test_perform_merge_success(self):
+        this, other, directive = self.make_this_other_directive()
+        window = self.make_merged_window(directive)
+        self.assertTrue(window.merge_successful)
+        self.assertEqual(other.last_revision(), this.get_parent_ids()[1])
+        self.assertFileEqual('bar', 'this/foo')
+
+    def test_perform_merge_conflicts(self):
+        this, other, directive = self.make_this_other_directive()
+        self.build_tree_contents([('this/foo', 'bar')])
+        this.add('foo')
+        this.commit('message')
+        window = self.make_merged_window(directive)
+        self.assertFalse(window.merge_successful)
+        self.assertTrue(window.conflicts)
+        self.assertEqual(other.last_revision(), this.get_parent_ids()[1])
+        self.assertFileEqual('bar', 'this/foo')
+
+    def test_perform_merge_uncommitted_changes(self):
+        this, other, directive = self.make_this_other_directive()
+        self.build_tree_contents([('this/foo', 'bar')])
+        this.add('foo')
+        window = self.make_merged_window(directive)
+        self.assertIsInstance(window.handled_error, errors.UncommittedChanges)
+
+
 class Test_IterChangesToStatus(tests.TestCaseWithTransport):
 
     def assertStatusEqual(self, expected, tree):



More information about the Pkg-bazaar-commits mailing list