/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to commit.py

  • Committer: Vincent Ladeuil
  • Date: 2009-05-28 15:14:14 UTC
  • mto: This revision was merged to the branch mainline in revision 640.
  • Revision ID: v.ladeuil+lp@free.fr-20090528151414-q5rlh8kaicx2hgqo
Implement commit message saving without modifying bzrlib.

* tests/test_commit.py:
(TestSavedCommitMessages.setUp): Install the post_uncommit hook
for all relevant tests.
(TestUncommitHook.setUp): Use explicit rev-ids to ease debugging.

* commit.py: 
Fix imports. Integrate SavedCommitMessagesManager so that we don't
need to modify bzrlib anymore.
(CommitDialog.__init__, CommitDialog._fill_in_files,
CommitDialog._construct_global_message, CommitDialog._do_cancel,
CommitDialog._do_commit): Stop testing can_save_commit_messages,
SavedCommitMessagesManager is always available now.
(SavedCommitMessagesManager): Borrowed from Anne Mohsen's patch.
(save_commit_messages): Implement the post_uncommit hook.

* __init__.py:
Install a lazy hook.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
import gobject
28
28
import pango
29
29
 
30
 
from bzrlib import errors, osutils
31
 
from bzrlib.trace import mutter
 
30
from bzrlib import (
 
31
    branch,
 
32
    errors,
 
33
    osutils,
 
34
    trace,
 
35
    )
32
36
from bzrlib.util import bencode
33
 
try:
34
 
    from bzrlib.uncommit import SavedCommitMessagesManager
35
 
except ImportError: # old bzrlib
36
 
    can_save_commit_messages = False
37
 
else:
38
 
    can_save_commit_messages = True
39
37
 
40
38
from bzrlib.plugins.gtk import _i18n
41
39
from bzrlib.plugins.gtk.dialog import question_dialog
128
126
        self._enable_per_file_commits = True
129
127
        self._commit_all_changes = True
130
128
        self.committed_revision_id = None # Nothing has been committed yet
131
 
        if can_save_commit_messages:
132
 
            self._saved_commit_messages_manager = SavedCommitMessagesManager(self._wt, self._wt.branch)
 
129
        self._saved_commit_messages_manager = SavedCommitMessagesManager(self._wt, self._wt.branch)
133
130
 
134
131
        self.setup_params()
135
132
        self.construct()
204
201
        self._basis_tree.lock_read()
205
202
        try:
206
203
            from diff import iter_changes_to_status
207
 
            if can_save_commit_messages:
208
 
                saved_file_messages = self._saved_commit_messages_manager.get()[1]
209
 
            else:
210
 
                saved_file_messages = {}
 
204
            saved_file_messages = self._saved_commit_messages_manager.get()[1]
211
205
            for (file_id, real_path, change_type, display_path
212
206
                ) in iter_changes_to_status(self._basis_tree, self._wt):
213
207
                if self._selected and real_path != self._selected:
256
250
                proxy_obj = bus.get_object('org.freedesktop.NetworkManager',
257
251
                                           '/org/freedesktop/NetworkManager')
258
252
            except dbus.DBusException:
259
 
                mutter("networkmanager not available.")
 
253
                trace.mutter("networkmanager not available.")
260
254
                self._check_local.show()
261
255
                return
262
256
            
268
262
            except dbus.DBusException, e:
269
263
                # Silently drop errors. While DBus may be
270
264
                # available, NetworkManager doesn't necessarily have to be
271
 
                mutter("unable to get networkmanager state: %r" % e)
 
265
                trace.mutter("unable to get networkmanager state: %r" % e)
272
266
        self._check_local.show()
273
267
 
274
268
    def _fill_in_per_file_info(self):
567
561
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
568
562
 
569
563
        self._global_message_text_view = gtk.TextView()
570
 
        if can_save_commit_messages:
571
 
            self._set_global_commit_message(self._saved_commit_messages_manager.get()[0])
 
564
        self._set_global_commit_message(self._saved_commit_messages_manager.get()[0])
572
565
        self._global_message_text_view.modify_font(pango.FontDescription("Monospace"))
573
566
        scroller.add(self._global_message_text_view)
574
567
        scroller.set_shadow_type(gtk.SHADOW_IN)
686
679
 
687
680
    def _do_cancel(self):
688
681
        """If requested, saves commit messages when cancelling gcommit; they are re-used by a next gcommit"""
689
 
        if can_save_commit_messages:
690
 
            mgr = SavedCommitMessagesManager()
691
 
            self._saved_commit_messages_manager = mgr
692
 
            mgr.insert(self._get_global_commit_message(),
693
 
                       self._get_specific_files()[1])
694
 
            if mgr.is_not_empty(): # maybe worth saving
695
 
                response = self._question_dialog(
696
 
                    _i18n('Commit cancelled'),
697
 
                    _i18n('Do you want to save your commit messages ?'),
698
 
                    parent=self)
699
 
                if response == gtk.RESPONSE_NO:
700
 
                     # save nothing and destroy old comments if any
701
 
                    mgr = SavedCommitMessagesManager()
702
 
            mgr.save(self._wt, self._wt.branch)
 
682
        mgr = SavedCommitMessagesManager()
 
683
        self._saved_commit_messages_manager = mgr
 
684
        mgr.insert(self._get_global_commit_message(),
 
685
                   self._get_specific_files()[1])
 
686
        if mgr.is_not_empty(): # maybe worth saving
 
687
            response = self._question_dialog(
 
688
                _i18n('Commit cancelled'),
 
689
                _i18n('Do you want to save your commit messages ?'),
 
690
                parent=self)
 
691
            if response == gtk.RESPONSE_NO:
 
692
                 # save nothing and destroy old comments if any
 
693
                mgr = SavedCommitMessagesManager()
 
694
        mgr.save(self._wt, self._wt.branch)
703
695
        self.response(gtk.RESPONSE_CANCEL) # close window
704
696
 
705
697
    @show_bzr_error
767
759
                               revprops=revprops)
768
760
        self.committed_revision_id = rev_id
769
761
        # destroy old comments if any
770
 
        if can_save_commit_messages:
771
 
            SavedCommitMessagesManager().save(self._wt, self._wt.branch)
 
762
        SavedCommitMessagesManager().save(self._wt, self._wt.branch)
772
763
        self.response(gtk.RESPONSE_OK)
773
764
 
774
765
    def _get_global_commit_message(self):
802
793
                                       show_offset=False)
803
794
        rev_dict['revision_id'] = rev.revision_id
804
795
        return rev_dict
 
796
 
 
797
 
 
798
class SavedCommitMessagesManager:
 
799
    """Saves global commit message and utf-8 file_id->message dictionary
 
800
    of per-file commit messages on disk. Re-reads them later for re-using."""
 
801
    def __init__(self, tree=None, branch=None):
 
802
        """If branch is None, builds empty messages, otherwise reads them
 
803
        from branch's disk storage. 'tree' argument is for the future."""
 
804
        if branch is None:
 
805
            self.global_message = u''
 
806
            self.file_messages = {}
 
807
        else:
 
808
            config = branch.get_config()._get_branch_data_config()
 
809
            self.global_message = config.get_user_option('gtk_global_commit_message')
 
810
            if self.global_message is None:
 
811
                self.global_message = u''
 
812
            file_messages = config.get_user_option('gtk_file_commit_messages')
 
813
            if file_messages: # unicode and B-encoded:
 
814
                self.file_messages = bencode.bdecode(file_messages.encode('UTF-8'))
 
815
            else:
 
816
                self.file_messages = {}
 
817
    def get(self):
 
818
        return self.global_message, self.file_messages
 
819
    def is_not_empty(self):
 
820
        return bool(self.global_message or self.file_messages)
 
821
    def insert(self, global_message, file_info):
 
822
        """Formats per-file commit messages (list of dictionaries, one per file)
 
823
        into one utf-8 file_id->message dictionary and merges this with
 
824
        previously existing dictionary. Merges global commit message too."""
 
825
        file_messages = {}
 
826
        for fi in file_info:
 
827
            file_message = fi['message']
 
828
            if file_message:
 
829
                file_messages[fi['file_id']] = file_message # utf-8 strings
 
830
        for k,v in file_messages.iteritems():
 
831
            try:
 
832
                self.file_messages[k] = v + '\n******\n' + self.file_messages[k]
 
833
            except KeyError:
 
834
                self.file_messages[k] = v
 
835
        if self.global_message:
 
836
            self.global_message = global_message + '\n******\n' + self.global_message
 
837
        else:
 
838
            self.global_message = global_message
 
839
    def save(self, tree, branch):
 
840
        # We store in branch's config, which can be a problem if two gcommit
 
841
        # are done in two checkouts of one single branch (comments overwrite
 
842
        # each other). Ideally should be in working tree. But uncommit does
 
843
        # not always have a working tree, though it always has a branch.
 
844
        # 'tree' argument is for the future
 
845
        config = branch.get_config()
 
846
        # should it be named "gtk_" or some more neutral name ("gui_" ?) to
 
847
        # be compatible with qbzr in the future?
 
848
        config.set_user_option('gtk_global_commit_message', self.global_message)
 
849
        # bencode() does not know unicode objects but set_user_option() requires one:
 
850
        config.set_user_option('gtk_file_commit_messages',
 
851
                                bencode.bencode(self.file_messages).decode('UTF-8'))
 
852
 
 
853
 
 
854
def save_commit_messages(local, master, old_revno, old_revid,
 
855
                         new_revno, new_revid):
 
856
    b = local
 
857
    if b is None:
 
858
        b = master
 
859
    mgr = SavedCommitMessagesManager(None, b)
 
860
    revid_iterator = b.repository.iter_reverse_revision_history(old_revid)
 
861
    cur_revno = old_revno
 
862
    new_revision_id = old_revid
 
863
    graph = b.repository.get_graph()
 
864
    for rev_id in revid_iterator:
 
865
        if cur_revno == new_revno:
 
866
            break
 
867
        cur_revno -= 1
 
868
        rev = b.repository.get_revision(rev_id)
 
869
        file_info = rev.properties.get('file-info', None)
 
870
        if file_info is None:
 
871
            file_info = {}
 
872
        else:
 
873
            file_info = bencode.bdecode(file_info.encode('UTF-8'))
 
874
        global_message = osutils.safe_unicode(rev.message)
 
875
        # Concatenate comment of the uncommitted revision
 
876
        mgr.insert(global_message, file_info)
 
877
 
 
878
        parents = graph.get_parent_map([rev_id]).get(rev_id, None)
 
879
        if not parents:
 
880
            continue
 
881
    mgr.save(None, b)