/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 push.py

  • Committer: Jelmer Vernooij
  • Date: 2007-07-15 18:12:57 UTC
  • Revision ID: jelmer@samba.org-20070715181257-g264qus2zyi3v39z
Add RevisionSelectionBox widget, use in TagDialog.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
 
2
# Copyright (C) 2007 by Jelmer Vernooij <jelmer@samba.org>
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
21
22
    pass
22
23
    
23
24
import gtk
24
 
import gtk.gdk
25
 
import gtk.glade
26
 
 
 
25
 
 
26
from errors import show_bzr_error
 
27
 
 
28
# FIXME: This needs to be public JRV 20070714
 
29
from bzrlib.builtins import _create_prefix
 
30
from bzrlib.config import LocationConfig
27
31
import bzrlib.errors as errors
28
32
 
29
 
from olive import gladefile
30
 
from dialog import error_dialog, info_dialog
31
 
 
32
 
class OlivePush:
33
 
    """ Display Push dialog and perform the needed actions. """
34
 
    def __init__(self, branch):
 
33
from dialog import error_dialog, info_dialog, question_dialog
 
34
 
 
35
from history import UrlHistory
 
36
 
 
37
class PushDialog(gtk.Dialog):
 
38
    """ New implementation of the Push dialog. """
 
39
    def __init__(self, repository, revid, branch=None, parent=None):
35
40
        """ Initialize the Push dialog. """
36
 
        self.glade = gtk.glade.XML(gladefile, 'window_push')
 
41
        gtk.Dialog.__init__(self, title="Push - Olive",
 
42
                                  parent=parent,
 
43
                                  flags=0,
 
44
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
37
45
        
38
 
        self.window = self.glade.get_widget('window_push')
39
 
 
 
46
        # Get arguments
 
47
        self.repository = repository
 
48
        self.revid = revid
40
49
        self.branch = branch
41
50
        
42
 
        # Dictionary for signal_autoconnect
43
 
        dic = { "on_button_push_push_clicked": self.push,
44
 
                "on_button_push_cancel_clicked": self.close,
45
 
                "on_button_push_test_clicked": self.test,
46
 
                "on_radiobutton_push_stored_toggled": self.stored_toggled,
47
 
                "on_radiobutton_push_specific_toggled": self.specific_toggled, }
48
 
        
49
 
        # Connect the signals to the handlers
50
 
        self.glade.signal_autoconnect(dic)
51
 
        
52
 
        # Get some useful widgets
53
 
        self.radio_stored = self.glade.get_widget('radiobutton_push_stored')
54
 
        self.radio_specific = self.glade.get_widget('radiobutton_push_specific')
55
 
        self.entry_stored = self.glade.get_widget('entry_push_stored')
56
 
        self.entry_location = self.glade.get_widget('entry_push_location')
57
 
        self.check_remember = self.glade.get_widget('checkbutton_push_remember')
58
 
        self.check_overwrite = self.glade.get_widget('checkbutton_push_overwrite')
59
 
        self.check_create = self.glade.get_widget('checkbutton_push_create')
60
 
        self.label_test = self.glade.get_widget('label_push_test')
61
 
        self.image_test = self.glade.get_widget('image_push_test')
62
 
        
63
 
        # Set initial state
64
 
        self.entry_location.set_sensitive(0)
65
 
        self.check_remember.set_sensitive(0)
66
 
        self.check_create.set_sensitive(0)
67
 
        
68
 
        self.entry_stored.set_text(branch.get_push_location())
69
 
    
70
 
    def display(self):
71
 
        """ Display the Push dialog. """
72
 
        self.window.show()
73
 
        self.width, self.height = self.window.get_size()
74
 
    
75
 
    def stored_toggled(self, widget):
76
 
        if widget.get_active():
77
 
            self.entry_stored.set_sensitive(1)
78
 
            self.entry_location.set_sensitive(0)
79
 
            self.check_remember.set_sensitive(0)
80
 
            self.check_create.set_sensitive(0)
81
 
        else:
82
 
            self.entry_stored.set_sensitive(0)
83
 
            self.entry_location.set_sensitive(1)
84
 
            self.check_remember.set_sensitive(1)
85
 
            self.check_create.set_sensitive(1)
86
 
    
87
 
    def specific_toggled(self, widget):
88
 
        if widget.get_active():
89
 
            self.entry_stored.set_sensitive(0)
90
 
            self.entry_location.set_sensitive(1)
91
 
            self.check_remember.set_sensitive(1)
92
 
            self.check_create.set_sensitive(1)
93
 
        else:
94
 
            self.entry_stored.set_sensitive(1)
95
 
            self.entry_location.set_sensitive(0)
96
 
            self.check_remember.set_sensitive(0)
97
 
            self.check_create.set_sensitive(0)
98
 
    
99
 
    def push(self, widget):
100
 
        revs = 0
101
 
        if self.radio_stored.get_active():
102
 
            try:
103
 
                revs = do_push(self.branch,
104
 
                               overwrite=self.check_overwrite.get_active())
105
 
            except errors.NotBranchError:
106
 
                error_dialog(_('Directory is not a branch'),
107
 
                             _('You can perform this action only in a branch.'))
108
 
                return
109
 
            except errors.DivergedBranches:
110
 
                error_dialog(_('Branches have been diverged'),
111
 
                             _('You cannot push if branches have diverged. Use the\noverwrite option if you want to push anyway.'))
112
 
                return
113
 
        elif self.radio_specific.get_active():
114
 
            location = self.entry_location.get_text()
115
 
            if location == '':
116
 
                error_dialog(_('No location specified'),
117
 
                             _('Please specify a location or use the default.'))
118
 
                return
119
 
            
120
 
            try:
121
 
                revs = do_push(self.branch, location,
122
 
                               self.check_remember.get_active(),
123
 
                               self.check_overwrite.get_active(),
124
 
                               self.check_create.get_active())
125
 
            except errors.NotBranchError:
126
 
                error_dialog(_('Directory is not a branch'),
127
 
                             _('You can perform this action only in a branch.'))
128
 
                return
129
 
            except errors.DivergedBranches:
130
 
                error_dialog(_('Branches have been diverged'),
131
 
                             _('You cannot push if branches have diverged. Use the\noverwrite option if you want to push anyway.'))
132
 
                return
133
 
        
134
 
        self.close()
135
 
        info_dialog(_('Push successful'),
136
 
                    _('%d revision(s) pushed.') % revs)
137
 
    
138
 
    def test(self, widget):
139
 
        """ Test if write access possible. """
 
51
        # Create the widgets
 
52
        self._label_location = gtk.Label(_("Location:"))
 
53
        self._label_test = gtk.Label(_("(click the Test button to check write access)"))
 
54
        self._combo = gtk.ComboBoxEntry()
 
55
        self._button_test = gtk.Button(_("_Test"), use_underline=True)
 
56
        self._button_push = gtk.Button(_("_Push"), use_underline=True)
 
57
        self._hbox_location = gtk.HBox()
 
58
        self._hbox_test = gtk.HBox()
 
59
        self._image_test = gtk.Image()
 
60
        
 
61
        # Set callbacks
 
62
        self._button_test.connect('clicked', self._on_test_clicked)
 
63
        self._button_push.connect('clicked', self._on_push_clicked)
 
64
        
 
65
        # Set properties
 
66
        self._image_test.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)
 
67
        self._label_location.set_alignment(0, 0.5)
 
68
        self._label_test.set_alignment(0, 0.5)
 
69
        self._hbox_location.set_spacing(3)
 
70
        self._hbox_test.set_spacing(3)
 
71
        self.vbox.set_spacing(3)
 
72
        
 
73
        # Pack widgets
 
74
        self._hbox_location.pack_start(self._label_location, False, False)
 
75
        self._hbox_location.pack_start(self._combo, True, True)
 
76
        self._hbox_test.pack_start(self._image_test, False, False)
 
77
        self._hbox_test.pack_start(self._label_test, True, True)
 
78
        self.vbox.pack_start(self._hbox_location)
 
79
        self.vbox.pack_start(self._hbox_test)
 
80
        self.action_area.pack_start(self._button_test)
 
81
        self.action_area.pack_end(self._button_push)
 
82
        
 
83
        # Show the dialog
 
84
        self.vbox.show_all()
 
85
        
 
86
        # Build location history
 
87
        self._history = UrlHistory(self.branch.get_config(), 'push_history')
 
88
        self._build_history()
 
89
        
 
90
    def _build_history(self):
 
91
        """ Build up the location history. """
 
92
        self._combo_model = gtk.ListStore(str)
 
93
        for item in self._history.get_entries():
 
94
            self._combo_model.append([ item ])
 
95
        self._combo.set_model(self._combo_model)
 
96
        self._combo.set_text_column(0)
 
97
        
 
98
        if self.branch is not None:
 
99
            location = self.branch.get_push_location()
 
100
            if location is not None:
 
101
                self._combo.get_child().set_text(location)
 
102
    
 
103
    def _on_test_clicked(self, widget):
 
104
        """ Test button clicked handler. """
140
105
        import re
141
106
        _urlRE = re.compile(r'^(?P<proto>[^:/\\]+)://(?P<path>.*)$')
142
107
        
143
 
        if self.radio_stored.get_active():
144
 
            url = self.entry_stored.get_text()
145
 
        elif self.radio_specific.get_active():
146
 
            url = self.entry_location.get_text()
 
108
        url = self._combo.get_child().get_text()
147
109
        
148
110
        m = _urlRE.match(url)
149
111
        if m:
150
112
            proto = m.groupdict()['proto']
151
 
            if (proto == 'sftp') or (proto == 'file') or (proto == 'ftp'):
152
 
                # have write acces (most probably)
153
 
                self.image_test.set_from_stock(gtk.STOCK_YES, 4)
154
 
                self.label_test.set_markup(_('<b>Write access is probably available</b>'))
 
113
            # FIXME: This should ask the transport or branch rather than 
 
114
            # guessing using regular expressions. JRV 20070714
 
115
            if proto in ('sftp', 'file', 'ftp'):
 
116
                # have write access (most probably)
 
117
                self._image_test.set_from_stock(gtk.STOCK_YES, 4)
 
118
                self._label_test.set_markup(_('<b>Write access is probably available</b>'))
155
119
            else:
156
120
                # no write access
157
 
                self.image_test.set_from_stock(gtk.STOCK_NO, 4)
158
 
                self.label_test.set_markup(_('<b>No write access</b>'))
 
121
                self._image_test.set_from_stock(gtk.STOCK_NO, 4)
 
122
                self._label_test.set_markup(_('<b>No write access</b>'))
159
123
        else:
160
124
            # couldn't determine
161
 
            self.image_test.set_from_stock(gtk.STOCK_DIALOG_QUESTION, 4)
162
 
            self.label_test.set_markup(_('<b>Could not determine</b>'))
 
125
            self._image_test.set_from_stock(gtk.STOCK_DIALOG_QUESTION, 4)
 
126
            self._label_test.set_markup(_('<b>Could not determine</b>'))
163
127
    
164
 
    def close(self, widget=None):
165
 
        self.window.destroy()
166
 
 
167
 
def do_push(branch, location=None, remember=False, overwrite=False,
168
 
         create_prefix=False):
 
128
    @show_bzr_error
 
129
    def _on_push_clicked(self, widget):
 
130
        """ Push button clicked handler. """
 
131
        location = self._combo.get_child().get_text()
 
132
        revs = 0
 
133
        if self.branch is not None and self.branch.get_push_location() is None:
 
134
            response = question_dialog(_('Set default push location'),
 
135
                                       _('There is no default push location set.\nSet %r as default now?') % location)
 
136
            if response == gtk.REPONSE_OK:
 
137
                self.branch.set_push_location(location)
 
138
 
 
139
        try:
 
140
            revs = do_push(self.branch, location=location, overwrite=False)
 
141
        except errors.DivergedBranches:
 
142
            response = question_dialog(_('Branches have been diverged'),
 
143
                                       _('You cannot push if branches have diverged.\nOverwrite?'))
 
144
            if response == gtk.RESPONSE_OK:
 
145
                revs = do_push(self.branch, location=location, overwrite=True)
 
146
            return
 
147
        
 
148
        self._history.add_entry(location)
 
149
        info_dialog(_('Push successful'),
 
150
                    _("%d revision(s) pushed.") % revs)
 
151
        
 
152
        self.response(gtk.RESPONSE_OK)
 
153
 
 
154
def do_push(br_from, location, overwrite):
169
155
    """ Update a mirror of a branch.
170
156
    
171
 
    :param branch: the source branch
 
157
    :param br_from: the source branch
172
158
    
173
159
    :param location: the location of the branch that you'd like to update
174
160
    
175
 
    :param remember: if set, the location will be stored
176
 
    
177
161
    :param overwrite: overwrite target location if it diverged
178
162
    
179
 
    :param create_prefix: create the path leading up to the branch if it doesn't exist
180
 
    
181
163
    :return: number of revisions pushed
182
164
    """
183
 
    from bzrlib.branch import Branch
184
165
    from bzrlib.bzrdir import BzrDir
185
166
    from bzrlib.transport import get_transport
186
167
        
187
 
    br_from = Branch.open_containing(branch)[0]
188
 
    
189
 
    stored_loc = br_from.get_push_location()
190
 
    if location is None:
191
 
        if stored_loc is None:
192
 
            error_dialog(_('Push location is unknown'),
193
 
                                     _('Please specify a location manually.'))
194
 
            return
195
 
        else:
196
 
            location = stored_loc
197
 
 
198
168
    transport = get_transport(location)
199
169
    location_url = transport.base
200
170
 
201
 
    if br_from.get_push_location() is None or remember:
202
 
        br_from.set_push_location(location_url)
203
 
 
204
171
    old_rh = []
205
172
 
206
173
    try:
209
176
    except errors.NotBranchError:
210
177
        # create a branch.
211
178
        transport = transport.clone('..')
212
 
        if not create_prefix:
213
 
            try:
214
 
                relurl = transport.relpath(location_url)
215
 
                transport.mkdir(relurl)
216
 
            except errors.NoSuchFile:
217
 
                error_dialog(_('Non existing parent directory'),
218
 
                             _("The parent directory (%s)\ndoesn't exist.") % location)
 
179
        try:
 
180
            relurl = transport.relpath(location_url)
 
181
            transport.mkdir(relurl)
 
182
        except errors.NoSuchFile:
 
183
            response = question_dialog(_('Non existing parent directory'),
 
184
                         _("The parent directory (%s)\ndoesn't exist. Create?") % location)
 
185
            if response == gtk.RESPONSE_OK:
 
186
                _create_prefix(transport)
 
187
            else:
219
188
                return
220
 
        else:
221
 
            current = transport.base
222
 
            needed = [(transport, transport.relpath(location_url))]
223
 
            while needed:
224
 
                try:
225
 
                    transport, relpath = needed[-1]
226
 
                    transport.mkdir(relpath)
227
 
                    needed.pop()
228
 
                except errors.NoSuchFile:
229
 
                    new_transport = transport.clone('..')
230
 
                    needed.append((new_transport,
231
 
                                   new_transport.relpath(transport.base)))
232
 
                    if new_transport.base == transport.base:
233
 
                        error_dialog(_('Path prefix not created'),
234
 
                                     _("The path leading up to the specified location couldn't\nbe created."))
235
 
                        return
236
189
        dir_to = br_from.bzrdir.clone(location_url,
237
190
            revision_id=br_from.last_revision())
238
191
        br_to = dir_to.open_branch()
243
196
            tree_to = dir_to.open_workingtree()
244
197
        except errors.NotLocalUrl:
245
198
            # FIXME - what to do here? how should we warn the user?
246
 
            #warning('This transport does not update the working '
247
 
            #        'tree of: %s' % (br_to.base,))
248
199
            count = br_to.pull(br_from, overwrite)
249
200
        except errors.NoWorkingTree:
250
201
            count = br_to.pull(br_from, overwrite)