~sinzui/gdp/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# Copyright (C) 2009-2013 - Curtis Hovey <sinzui.is at verizon.net>
# This software is licensed under the GNU General Public License version 2
# (see the file COPYING).
"""Bazaar integration."""

from __future__ import (
    absolute_import,
    print_function,
    unicode_literals,
)


__all__ = [
    'BzrProject',
]


import os

from gettext import gettext as _

from gdp import (
    Command,
    ControllerMixin,
)


bzr_branch_root = Command(
    ['bzr', 'info'], pattern=r'(?:root|repository branch): ([\S]*)')
bzr_push_branch = Command(['bzr', 'info'], pattern=r'push branch: ([\S]*)')
bzr_parent_branch = Command(['bzr', 'info'], pattern=r'parent branch: ([\S]*)')


bzr_changes = Command(['bzr', 'st', '-S', '-r'])
bzr_diff = Command(['bzr', 'diff', '-r'])
bzr_qadd = Command(['bzr', 'qadd'], spawn=True)
bzr_qannotate = Command(['bzr', 'qannotate'], spawn=True)
bzr_qbind = Command(['bzr', 'qbind'], spawn=True)
bzr_qbranch = Command(['bzr', 'qbranch'], spawn=True)
bzr_qbrowse = Command(['bzr', 'qbrowse'], spawn=True)
bzr_qcommit = Command(['bzr', 'qcommit'], spawn=True)
bzr_qconfig = Command(['bzr', 'qconfig'], spawn=True)
bzr_qconflicts = Command(['bzr', 'qconflicts'], spawn=True)
bzr_qdiff = Command(['bzr', 'qdiff', '-r'], spawn=True)
bzr_qignore = Command(['bzr', 'qignore'], spawn=True)
bzr_qinfo = Command(['bzr', 'qinfo'], spawn=True)
bzr_qinit = Command(['bzr', 'qinit'], spawn=True)
bzr_qlog = Command(['bzr', 'qlog'], spawn=True)
bzr_qmerge = Command(['bzr', 'qmerge'], spawn=True)
bzr_qmissing = Command(
    ['bzr', 'qrun', '--ui-mode', 'missing', ':parent'], spawn=True)
bzr_qpull = Command(['bzr', 'qpull'], spawn=True)
bzr_qpush = Command(['bzr', 'qpush'], spawn=True)
bzr_qrevert = Command(['bzr', 'qrevert'], spawn=True)
bzr_qsend = Command(['bzr', 'qsend'], spawn=True)
bzr_qstatus = Command(['bzr', 'qrun', '-e', '--ui-mode', 'status'], spawn=True)
bzr_qtag = Command(['bzr', 'qtag'], spawn=True)
bzr_qtags = Command(['bzr', 'qrun', '-e', '--ui-mode', 'tags'], spawn=True)


class BzrProject(ControllerMixin):
    """View and manage a bazaar branch."""

    def __init__(self, window, working_tree=None):
        self.window = window
        self.working_tree = working_tree
        self.working_tree_file_path = None

    def deactivate(self):
        """Clean up resources before deactivation."""
        self.working_tree = None

    def set_working_tree(self):
        """Return the working tree for the working directory or document"""
        doc = self.active_document
        if doc is None:
            self.working_tree = None
            return
        file_path = doc.get_uri_for_display()
        if (self.working_tree is not None
                and self.working_tree_file_path == file_path):
            return
        if file_path is None or '/' not in file_path:
            cwd = os.getcwd()
        else:
            if file_path.startswith('file://'):
                file_path = file_path[7:]
            cwd = os.path.dirname(file_path)
        self.working_tree = None
        code, groups = bzr_branch_root(cwd=cwd)
        if groups:
            path = groups[0]
            if path == '.':
                path = cwd
            self.working_tree = path
            self.working_tree_file_path = file_path

    def open_changed_files(self, other_branch):
        """Open files in the bzr branch."""
        code, changes = bzr_changes(other_branch, cwd=self.working_tree)
        if code > 0:
            self.show_info_dialog(
                _('This branch does not have a %s location.' % other_branch))
            return
        for change in changes.splitlines():
            if change[0:2] not in ('+N', ' M', 'R ') or change.endswith('/'):
                continue
            tree_file_path = change[4:]
            if ' => ' in tree_file_path:
                ignore, tree_file_path = tree_file_path.split(' => ')
            uri = 'file://%s' % os.path.join(self.working_tree, tree_file_path)
            self.open_doc(uri)

    def open_uncommitted_files(self, action):
        """Open modified and added files in the bzr branch."""
        self.open_changed_files(self.working_tree)

    def open_changed_files_to_push(self, action):
        """Open the changed files in the branch that not been pushed."""
        self.open_changed_files(':push')

    def open_changed_files_from_parent(self, action):
        """Open the changed files that diverged from the parent branch."""
        self.open_changed_files(':parent')

    @property
    def diff_file_path(self):
        """The path of the diff file."""
        return os.path.join(self.working_tree, '_diff.diff')

    def _write_diff(self, report):
        with open(self.diff_file_path, 'w+t') as diff_file:
            diff_file.write(report)

    def _diff_tree(self, another_tree):
        """Diff the working tree against an anoter tree."""
        try:
            code, report = bzr_diff(another_tree, cwd=self.working_tree)
            if code == 0:
                self._write_diff(report)
            bzr_qdiff(another_tree, cwd=self.working_tree)
        except:
            # The :parent and :push locations can be invalid, but that
            # is not an error in the application
            pass

    def diff_uncommited_changes(self, action):
        """Create a diff of uncommitted changes."""
        self._diff_tree(self.working_tree)

    def diff_changes_from_parent(self, action):
        """Create a diff of changes from the parent tree."""
        self._diff_tree(':parent')

    def diff_changes_to_push(self, action):
        """Create a diff of changes to the push tree."""
        self._diff_tree(':push')

    def commit_changes(self, action):
        """Commit the changes in the working tree."""
        bzr_qcommit(cwd=self.working_tree)

    def show_info(self, action):
        """Show info about the working tree."""
        bzr_qinfo(cwd=self.working_tree)

    def show_status(self, action):
        """Show the status of the working tree."""
        bzr_qstatus(cwd=self.working_tree)

    def show_log(self, action):
        """Show the revision log for working tree."""
        bzr_qlog(cwd=self.working_tree)

    def show_conflicts(self, action):
        """Show the merge, revert, or pull conflicts in the working tree."""
        bzr_qconflicts(cwd=self.working_tree)

    def show_missing(self, action):
        """Show unmerged/unpulled revisions between two branches."""
        bzr_qmissing(cwd=self.working_tree)

    def show_tags(self, action):
        """Show the tags in the branch."""
        bzr_qtags(cwd=self.working_tree)

    def tag_revision(self, action):
        """Tag a revision in the branch."""
        bzr_qtag(cwd=self.working_tree)

    def show_annotations(self, action):
        """Show the annotated revisions of the file."""
        document = self.window.get_active_document()
        file_path = document.get_uri_for_display()
        if file_path is None:
            return
        bzr_qannotate(file_path, cwd=self.working_tree)

    def visualise_branch(self, action):
        """Visualise the tree."""
        bzr_qbrowse(cwd=self.working_tree)

    def add_files(self, action):
        """Add files to the branch."""
        bzr_qadd(cwd=self.working_tree)

    def ignore_files(self, action):
        """Ignore files in the working tree."""
        bzr_qignore(cwd=self.working_tree)

    def revert_changes(self, action):
        """Revert changes in the working tree."""
        bzr_qrevert(cwd=self.working_tree)

    def merge_changes(self, action):
        """Merge changes from another branch into the working tree."""
        bzr_qmerge(cwd=self.working_tree)

    def pull_changes(self, action):
        """Pull changes into the working tree."""
        bzr_qpull(cwd=self.working_tree)

    def push_changes(self, action):
        """Push the changes in the working tree."""
        bzr_qpush(cwd=self.working_tree)

    def send_merge(self, action):
        """Mail or create a merge-directive for submitting changes."""
        bzr_qsend(cwd=self.working_tree)

    def initialise_branch(self, action):
        """Make a directory into a versioned branch."""
        bzr_qinit(cwd=self.working_tree)

    def branch_branch(self, action):
        """Create a new branch that is a copy of an existing branch."""
        bzr_qbranch(cwd=self.working_tree)

    def checkout_branch(self, action):
        """Create a new checkout of an existing branch."""
        bzr_qbind(cwd=self.working_tree)

    def preferences(self, action):
        """Bazaar preferences."""
        bzr_qconfig(cwd=self.working_tree)