1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic)
2
# <szilveszter.farkas@gmail.com>
3
# Copyright (C) 2007 by Jelmer Vernooij <jelmer@samba.org>
1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
5
3
# This program is free software; you can redistribute it and/or modify
6
4
# it under the terms of the GNU General Public License as published by
7
5
# the Free Software Foundation; either version 2 of the License, or
8
6
# (at your option) any later version.
10
8
# This program is distributed in the hope that it will be useful,
11
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
11
# GNU General Public License for more details.
15
13
# You should have received a copy of the GNU General Public License
16
14
# along with this program; if not, write to the Free Software
17
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
from gi.repository import Gtk
21
from errors import show_bzr_error
27
from bzrlib.controldir import ControlDir
28
from bzrlib.push import PushResult
29
from bzrlib.transport import get_transport
31
from bzrlib.plugins.gtk.dialog import (
34
from bzrlib.plugins.gtk.history import UrlHistory
35
from bzrlib.plugins.gtk.i18n import _i18n
36
from bzrlib.plugins.gtk.ui import ProgressPanel
39
class PushDialog(Gtk.Dialog):
40
"""New implementation of the Push dialog."""
42
def __init__(self, repository=None, revid=None, branch=None, parent=None):
43
"""Initialize the Push dialog. """
44
super(PushDialog, self).__init__(
45
title="Push", parent=parent, flags=0, border_width=6,
46
buttons=(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE))
47
if repository is None:
48
repository = branch.repository
52
self.repository = repository
54
revid = branch.last_revision()
58
self._label_location = Gtk.Label(label=_i18n("Location:"))
59
self._combo = Gtk.ComboBox.new_with_entry()
60
self._button_push = Gtk.Button(_i18n("_Push"), use_underline=True)
61
self._hbox_location = Gtk.Box(Gtk.Orientation.HORIZONTAL, 6)
62
self._push_message = Gtk.Label(xalign=0)
63
self._progress_widget = ProgressPanel()
66
ui.ui_factory.set_progress_bar_widget(self._progress_widget)
67
self.connect('close', self._on_close_clicked)
68
self._button_push.connect('clicked', self._on_push_clicked)
71
content_area = self.get_content_area()
72
content_area.set_spacing(6)
75
self._hbox_location.pack_start(self._label_location, False, False, 0)
76
self._hbox_location.pack_start(self._combo, False, False, 0)
77
content_area.pack_start(self._hbox_location, True, True, 0)
78
content_area.pack_start(self._progress_widget, True, True, 0)
79
content_area.pack_start(self._push_message, True, True, 0)
80
self.get_action_area().pack_end(self._button_push, True, True, 0)
83
content_area.show_all()
84
self._progress_widget.hide()
85
self._push_message.hide()
87
# Build location history
88
self._history = UrlHistory(self.branch.get_config(), 'push_history')
91
def _build_history(self):
92
"""Build up the location history. """
93
self._combo_model = Gtk.ListStore(str)
94
for item in self._history.get_entries():
95
self._combo_model.append([item])
96
self._combo.set_model(self._combo_model)
97
self._combo.set_entry_text_column(0)
99
if self.branch is not None:
100
location = self.branch.get_push_location()
101
if location is not None:
102
self._combo.get_child().set_text(location)
104
def _on_close_clicked(self, widget):
105
"""Close dialog handler."""
106
ui.ui_factory.set_progress_bar_widget(None)
109
def _on_push_clicked(self, widget):
110
"""Push button clicked handler. """
111
self._push_message.hide()
112
self._progress_widget.tick()
113
location = self._combo.get_child().get_text()
116
message = do_push(self.branch, location, overwrite=False)
117
except errors.DivergedBranches:
118
response = question_dialog(
119
_i18n('Branches have been diverged'),
120
_i18n('You cannot push if branches have diverged.\n'
122
if response == Gtk.ResponseType.YES:
123
message = do_push(self.branch, location, overwrite=True)
126
self._history.add_entry(location)
127
if (self.branch is not None
128
and self.branch.get_push_location() is None):
129
self.branch.set_push_location(location)
131
self._progress_widget.finished()
132
self._push_message.props.label = message
133
self._push_message.show()
136
def do_push(br_from, location, overwrite):
137
"""Update a mirror of a branch.
139
:param br_from: the source branch
140
:param location: the location of the branch that you'd like to update
141
:param overwrite: overwrite target location if it diverged
142
:return: number of revisions pushed
145
to_transport = get_transport(location)
147
dir_to = ControlDir.open_from_transport(to_transport)
148
except errors.NotBranchError:
153
br_to = br_from.create_clone_on_transport(
154
to_transport, revision_id=revision_id)
155
except errors.NoSuchFile:
156
response = question_dialog(
157
_i18n('Non existing parent directory'),
158
_i18n("The parent directory (%s)\ndoesn't exist. Create?") %
160
if response == Gtk.ResponseType.OK:
161
br_to = br_from.create_clone_on_transport(
162
to_transport, revision_id=revision_id, create_prefix=True)
164
return _i18n("Push aborted.")
165
push_result = create_push_result(br_from, br_to)
167
push_result = dir_to.push_branch(br_from, revision_id, overwrite)
168
message = create_push_message(br_from, push_result)
172
def create_push_message(br_from, push_result):
173
"""Return a mesage explaining what happened during the push."""
175
rev_count = br_from.revno() - push_result.old_revno
176
messages.append(_i18n("%d revision(s) pushed.") % rev_count)
177
if push_result.stacked_on is not None:
178
messages.append(_i18n("Stacked on %s.") % push_result.stacked_on)
179
if push_result.workingtree_updated is False:
180
messages.append(_i18n(
181
"\nThe working tree was not updated:"
182
"\nSee 'bzr help working-trees' for more information."))
183
return '\n'.join(messages)
186
def create_push_result(br_from, br_to):
187
"""Return a PushResult like one created by ControlDir.push_branch()."""
188
push_result = PushResult()
189
push_result.source_branch = br_from
190
push_result.target_branch = br_to
191
push_result.branch_push_result = None
192
push_result.master_branch = None
193
push_result.old_revno = 0
194
push_result.old_revid = br_to.last_revision()
195
push_result.workingtree_updated = None # Not applicable to this case.
197
push_result.stacked_on = br_to.get_stacked_on_url()
198
except (errors.UnstackableBranchFormat,
199
errors.UnstackableRepositoryFormat,
201
push_result.stacked_on = None
31
import olive.backend.commit as commit
32
import olive.backend.errors as errors
33
import olive.backend.info as info
35
from dialog import OliveDialog
38
""" Display Push dialog and perform the needed actions. """
39
def __init__(self, gladefile, comm):
40
""" Initialize the Push dialog. """
41
self.gladefile = gladefile
42
self.glade = gtk.glade.XML(self.gladefile, 'window_push')
45
self.dialog = OliveDialog(self.gladefile)
47
self.window = self.glade.get_widget('window_push')
49
# Dictionary for signal_autoconnect
50
dic = { "on_button_push_push_clicked": self.push,
51
"on_button_push_cancel_clicked": self.close,
52
"on_radiobutton_push_stored_toggled": self.stored_toggled,
53
"on_radiobutton_push_specific_toggled": self.specific_toggled, }
55
# Connect the signals to the handlers
56
self.glade.signal_autoconnect(dic)
58
# Get some useful widgets
59
self.entry_stored = self.glade.get_widget('entry_push_stored')
60
self.entry_location = self.glade.get_widget('entry_push_location')
61
self.check_remember = self.glade.get_widget('checkbutton_push_remember')
62
self.check_overwrite = self.glade.get_widget('checkbutton_push_overwrite')
63
self.check_create = self.glade.get_widget('checkbutton_push_create')
66
self.notbranch = False
68
loc = info.get_push_location(self.comm.get_path())
69
except errors.NotBranchError:
74
self.entry_stored.set_text(loc)
77
""" Display the Push dialog. """
79
self.dialog.error_dialog('Directory is not a branch.')
83
self.width, self.height = self.window.get_size()
85
def stored_toggled(self, widget):
86
if widget.get_active():
87
self.entry_stored.show()
88
self.entry_location.hide()
89
self.check_remember.hide()
90
self.check_create.hide()
91
self.window.resize(self.width, self.height)
93
self.entry_stored.hide()
94
self.entry_location.show()
95
self.check_remember.show()
96
self.check_create.show()
98
def specific_toggled(self, widget):
99
if widget.get_active():
100
self.entry_stored.hide()
101
self.entry_location.show()
102
self.check_remember.show()
103
self.check_create.show()
105
self.entry_stored.show()
106
self.entry_location.hide()
107
self.check_remember.hide()
108
self.check_create.hide()
110
def push(self, widget):
111
radio_stored = self.glade.get_widget('radiobutton_push_stored')
112
radio_specific = self.glade.get_widget('radiobutton_push_specific')
115
self.comm.set_busy(self.window)
116
if radio_stored.get_active():
118
revs = commit.push(self.comm.get_path(),
119
overwrite=self.check_overwrite.get_active())
120
except errors.NotBranchError:
121
self.dialog.error_dialog('Directory is not a branch.')
123
except errors.NoLocationKnown:
124
self.dialog.error_dialog('No location known.')
126
except errors.NonExistingParent, errmsg:
127
self.dialog.error_dialog('Parent directory doesn\'t exist: %s', errmsg)
129
except errors.DivergedBranchesError:
130
self.dialog.error_dialog('Branches have been diverged.')
134
elif radio_specific.get_active():
135
location = self.entry_location.get_text()
137
self.dialog.error_dialog('No location specified.')
141
revs = commit.push(self.comm.get_path(), location,
142
self.check_remember.get_active(),
143
self.check_overwrite.get_active(),
144
self.check_create.get_active())
145
except errors.NotBranchError:
146
self.dialog.error_dialog('Directory is not a branch.')
147
self.comm.set_busy(self.window, False)
149
except errors.NonExistingParent, errmsg:
150
self.dialog.error_dialog('Parent directory doesn\'t exist: %s', errmsg)
151
self.comm.set_busy(self.window, False)
153
except errors.DivergedBranchesError:
154
self.dialog.error_dialog('Branches have been diverged.')
155
self.comm.set_busy(self.window, False)
157
except errors.PathPrefixNotCreated:
158
self.dialog.error_dialog('Path prefix couldn\'t be created.')
159
self.comm.set_busy(self.window, False)
164
# This should really never happen
168
self.dialog.info_dialog('%d revision(s) pushed.' % revs)
170
def close(self, widget=None):
171
self.window.destroy()