1
1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
19
pygtk.require("2.0")
31
import olive.backend.commit as commit
32
import olive.backend.errors as errors
33
import olive.backend.info as info
36
""" Display Push dialog and perform the needed actions. """
37
def __init__(self, gladefile, comm):
25
from errors import show_bzr_error
27
from bzrlib.config import LocationConfig
28
import bzrlib.errors as errors
30
from dialog import error_dialog, info_dialog, question_dialog
32
from history import UrlHistory
34
class PushDialog(gtk.Dialog):
35
""" New implementation of the Push dialog. """
36
def __init__(self, branch, parent=None):
38
37
""" Initialize the Push dialog. """
39
self.gladefile = gladefile
40
self.glade = gtk.glade.XML(self.gladefile, 'window_push')
44
self.window = self.glade.get_widget('window_push')
46
# Dictionary for signal_autoconnect
47
dic = { "on_button_push_push_clicked": self.push,
48
"on_button_push_cancel_clicked": self.close,
49
"on_radiobutton_push_stored_toggled": self.stored_toggled,
50
"on_radiobutton_push_specific_toggled": self.specific_toggled, }
52
# Connect the signals to the handlers
53
self.glade.signal_autoconnect(dic)
55
# Get some useful widgets
56
self.entry_stored = self.glade.get_widget('entry_push_stored')
57
self.entry_location = self.glade.get_widget('entry_push_location')
58
self.check_remember = self.glade.get_widget('checkbutton_push_remember')
59
self.check_overwrite = self.glade.get_widget('checkbutton_push_overwrite')
60
self.check_create = self.glade.get_widget('checkbutton_push_create')
63
loc = info.get_push_location(self.comm.get_path())
65
self.entry_stored.set_text(loc)
68
""" Display the Push dialog. """
70
self.width, self.height = self.window.get_size()
72
def stored_toggled(self, widget):
73
if widget.get_active():
74
self.entry_stored.show()
75
self.entry_location.hide()
76
self.check_remember.hide()
77
self.check_create.hide()
78
self.window.resize(self.width, self.height)
80
self.entry_stored.hide()
81
self.entry_location.show()
82
self.check_remember.show()
83
self.check_create.show()
85
def specific_toggled(self, widget):
86
if widget.get_active():
87
self.entry_stored.hide()
88
self.entry_location.show()
89
self.check_remember.show()
90
self.check_create.show()
92
self.entry_stored.show()
93
self.entry_location.hide()
94
self.check_remember.hide()
95
self.check_create.hide()
97
def push(self, widget):
98
from dialog import OliveDialog
99
dialog = OliveDialog(self.gladefile)
101
radio_stored = self.glade.get_widget('radiobutton_push_stored')
102
radio_specific = self.glade.get_widget('radiobutton_push_specific')
38
gtk.Dialog.__init__(self, title="Push - Olive",
41
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
47
self._label_location = gtk.Label(_("Location:"))
48
self._label_test = gtk.Label(_("(click the Test button to check write access)"))
49
self._check_remember = gtk.CheckButton(_("_Remember as default location"),
51
self._check_prefix = gtk.CheckButton(_("Create the path _leading up to the location"),
53
self._check_overwrite = gtk.CheckButton(_("_Overwrite target if diverged"),
55
self._combo = gtk.ComboBoxEntry()
56
self._button_test = gtk.Button(_("_Test"), use_underline=True)
57
self._button_push = gtk.Button(_("_Push"), use_underline=True)
58
self._hbox_location = gtk.HBox()
59
self._hbox_test = gtk.HBox()
60
self._image_test = gtk.Image()
63
self._button_test.connect('clicked', self._on_test_clicked)
64
self._button_push.connect('clicked', self._on_push_clicked)
67
self._image_test.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)
68
self._label_location.set_alignment(0, 0.5)
69
self._label_test.set_alignment(0, 0.5)
70
self._hbox_location.set_spacing(3)
71
self._hbox_test.set_spacing(3)
72
self.vbox.set_spacing(3)
75
self._hbox_location.pack_start(self._label_location, False, False)
76
self._hbox_location.pack_start(self._combo, True, True)
77
self._hbox_test.pack_start(self._image_test, False, False)
78
self._hbox_test.pack_start(self._label_test, True, True)
79
self.vbox.pack_start(self._hbox_location)
80
self.vbox.pack_start(self._check_remember)
81
self.vbox.pack_start(self._check_prefix)
82
self.vbox.pack_start(self._check_overwrite)
83
self.vbox.pack_start(self._hbox_test)
84
self.action_area.pack_start(self._button_test)
85
self.action_area.pack_end(self._button_push)
90
# Build location history
91
self._history = UrlHistory(self.branch.get_config(), 'push_history')
94
def _build_history(self):
95
""" Build up the location history. """
96
self._combo_model = gtk.ListStore(str)
97
for item in self._history.get_entries():
98
self._combo_model.append([ item ])
99
self._combo.set_model(self._combo_model)
100
self._combo.set_text_column(0)
102
location = self.branch.get_push_location()
104
self._combo.get_child().set_text(location)
106
def _on_test_clicked(self, widget):
107
""" Test button clicked handler. """
109
_urlRE = re.compile(r'^(?P<proto>[^:/\\]+)://(?P<path>.*)$')
111
url = self._combo.get_child().get_text()
113
m = _urlRE.match(url)
115
proto = m.groupdict()['proto']
116
if (proto == 'sftp') or (proto == 'file') or (proto == 'ftp'):
117
# have write acces (most probably)
118
self._image_test.set_from_stock(gtk.STOCK_YES, 4)
119
self._label_test.set_markup(_('<b>Write access is probably available</b>'))
122
self._image_test.set_from_stock(gtk.STOCK_NO, 4)
123
self._label_test.set_markup(_('<b>No write access</b>'))
126
self._image_test.set_from_stock(gtk.STOCK_DIALOG_QUESTION, 4)
127
self._label_test.set_markup(_('<b>Could not determine</b>'))
130
def _on_push_clicked(self, widget):
131
""" Push button clicked handler. """
132
location = self._combo.get_child().get_text()
105
self.comm.set_busy(self.window)
106
if radio_stored.get_active():
108
revs = commit.push(self.comm.get_path(),
109
overwrite=self.check_overwrite.get_active())
110
except errors.NotBranchError:
111
dialog.error_dialog('Directory is not a branch.')
113
except errors.NoLocationKnown:
114
dialog.error_dialog('No location known.')
116
except errors.NonExistingParent, errmsg:
117
dialog.error_dialog('Parent directory doesn\'t exist: %s', errmsg)
119
except errors.DivergedBranchesError:
120
dialog.error_dialog('Branches have been diverged.')
124
elif radio_specific.get_active():
125
location = self.entry_location.get_text()
127
dialog.error_dialog('No location specified.')
131
revs = commit.push(self.comm.get_path(), location,
132
self.check_remember.get_active(),
133
self.check_overwrite.get_active(),
134
self.check_create.get_active())
135
except errors.NotBranchError:
136
dialog.error_dialog('Directory is not a branch.')
137
self.comm.set_busy(self.window, False)
139
except errors.NonExistingParent, errmsg:
140
dialog.error_dialog('Parent directory doesn\'t exist: %s', errmsg)
141
self.comm.set_busy(self.window, False)
143
except errors.DivergedBranchesError:
144
dialog.error_dialog('Branches have been diverged.')
145
self.comm.set_busy(self.window, False)
147
except errors.PathPrefixNotCreated:
148
dialog.error_dialog('Path prefix couldn\'t be created.')
149
self.comm.set_busy(self.window, False)
154
# This should really never happen
158
dialog.info_dialog('%d revision(s) pushed.' % revs)
160
def close(self, widget=None):
161
self.window.destroy()
135
revs = do_push(self.branch,
137
overwrite=self._check_overwrite.get_active(),
138
remember=self._check_remember.get_active(),
139
create_prefix=self._check_prefix.get_active())
140
except errors.DivergedBranches:
141
response = question_dialog(_('Branches have been diverged'),
142
_('You cannot push if branches have diverged.\nOverwrite?'))
143
if response == gtk.RESPONSE_OK:
144
revs = do_push(self.branch, overwrite=True)
147
self._history.add_entry(location)
148
info_dialog(_('Push successful'),
149
_("%d revision(s) pushed.") % revs)
151
self.response(gtk.RESPONSE_OK)
153
def do_push(branch, location=None, remember=False, overwrite=False,
154
create_prefix=False):
155
""" Update a mirror of a branch.
157
:param branch: the source branch
159
:param location: the location of the branch that you'd like to update
161
:param remember: if set, the location will be stored
163
:param overwrite: overwrite target location if it diverged
165
:param create_prefix: create the path leading up to the branch if it doesn't exist
167
:return: number of revisions pushed
169
from bzrlib.bzrdir import BzrDir
170
from bzrlib.transport import get_transport
174
stored_loc = br_from.get_push_location()
176
if stored_loc is None:
177
error_dialog(_('Push location is unknown'),
178
_('Please specify a location manually.'))
181
location = stored_loc
183
transport = get_transport(location)
184
location_url = transport.base
186
if br_from.get_push_location() is None or remember:
187
br_from.set_push_location(location_url)
192
dir_to = BzrDir.open(location_url)
193
br_to = dir_to.open_branch()
194
except errors.NotBranchError:
196
transport = transport.clone('..')
197
if not create_prefix:
199
relurl = transport.relpath(location_url)
200
transport.mkdir(relurl)
201
except errors.NoSuchFile:
202
error_dialog(_('Non existing parent directory'),
203
_("The parent directory (%s)\ndoesn't exist.") % location)
206
current = transport.base
207
needed = [(transport, transport.relpath(location_url))]
210
transport, relpath = needed[-1]
211
transport.mkdir(relpath)
213
except errors.NoSuchFile:
214
new_transport = transport.clone('..')
215
needed.append((new_transport,
216
new_transport.relpath(transport.base)))
217
if new_transport.base == transport.base:
218
error_dialog(_('Path prefix not created'),
219
_("The path leading up to the specified location couldn't\nbe created."))
221
dir_to = br_from.bzrdir.clone(location_url,
222
revision_id=br_from.last_revision())
223
br_to = dir_to.open_branch()
224
count = len(br_to.revision_history())
226
old_rh = br_to.revision_history()
228
tree_to = dir_to.open_workingtree()
229
except errors.NotLocalUrl:
230
# FIXME - what to do here? how should we warn the user?
231
#warning('This transport does not update the working '
232
# 'tree of: %s' % (br_to.base,))
233
count = br_to.pull(br_from, overwrite)
234
except errors.NoWorkingTree:
235
count = br_to.pull(br_from, overwrite)
237
count = tree_to.pull(br_from, overwrite)