PageRenderTime 31ms CodeModel.GetById 11ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/tortoisehg/hgtk/archive.py

https://bitbucket.org/tortoisehg/hgtk/
Python | 245 lines | 223 code | 12 blank | 10 comment | 2 complexity | 1b24739535486b2765da0f09932f794e MD5 | raw file
  1# archive.py - TortoiseHg's dialog for archiving a repo revision
  2#
  3# Copyright 2009 Emmanuel Rosa <goaway1000@gmail.com>
  4#
  5# This software may be used and distributed according to the terms of the
  6# GNU General Public License version 2, incorporated herein by reference.
  7
  8import os
  9import gtk
 10
 11from mercurial import error
 12
 13from tortoisehg.util.i18n import _
 14from tortoisehg.util import hglib
 15
 16from tortoisehg.hgtk import gtklib, gdialog
 17
 18WD_PARENT = _('= Working Directory Parent =')
 19
 20class ArchiveDialog(gdialog.GDialog):
 21    """ Dialog to archive a Mercurial repo """
 22    def __init__(self, rev=None):
 23        gdialog.GDialog.__init__(self)
 24        self.initrev = rev
 25
 26    ### Start of Overriding Section ###
 27
 28    def get_title(self, reponame):
 29        return _('Archive - %s') % reponame
 30
 31    def get_icon(self):
 32        return 'menucheckout.ico'
 33
 34    def get_body(self, vbox):
 35        self.prevtarget = None
 36
 37        # layout table
 38        self.table = table = gtklib.LayoutTable()
 39        vbox.pack_start(table, True, True, 2)
 40
 41        ## revision combo
 42        self.combo = gtk.combo_box_entry_new_text()
 43        self.combo.child.set_width_chars(28)
 44        self.combo.child.connect('activate',
 45                                 lambda b: self.response(gtk.RESPONSE_OK))
 46        if self.initrev == '':
 47            self.combo.append_text(WD_PARENT)
 48        else:
 49            self.combo.append_text(str(self.initrev))
 50        self.combo.set_active(0)
 51        for b in self.repo.branchtags():
 52            self.combo.append_text(b)
 53        tags = list(self.repo.tags())
 54        tags.sort()
 55        tags.reverse()
 56        for t in tags:
 57            self.combo.append_text(t)
 58
 59        table.add_row(_('Archive revision:'), self.combo)
 60
 61        self.opt_files_in_rev = gtk.CheckButton(
 62                    _('Only files modified/created in this revision'))
 63        table.add_row('', self.opt_files_in_rev, ypad=0)
 64
 65        ## dest combo & browse button
 66        self.destentry = gtk.Entry()
 67        self.destentry.set_width_chars(46)
 68
 69        destbrowse = gtk.Button(_('Browse...'))
 70        destbrowse.connect('clicked', self.browse_clicked)
 71
 72        table.add_row(_('Destination path:'), self.destentry, 0, destbrowse)
 73
 74        ## archive types
 75        self.filesradio = gtk.RadioButton(None, _('Directory of files'))
 76        self.filesradio.connect('toggled', self.type_changed)
 77        table.add_row(_('Archive types:'), self.filesradio, ypad=0)
 78        def add_type(label):
 79            radio = gtk.RadioButton(self.filesradio, label)
 80            radio.connect('toggled', self.type_changed)
 81            table.add_row(None, radio, ypad=0)
 82            return radio
 83        self.tarradio = add_type(_('Uncompressed tar archive'))
 84        self.tbz2radio = add_type(_('Tar archive compressed using bzip2'))
 85        self.tgzradio = add_type(_('Tar archive compressed using gzip'))
 86        self.uzipradio = add_type(_('Uncompressed zip archive'))
 87        self.zipradio = add_type(_('Zip archive compressed using deflate'))
 88
 89        # signal handler
 90        self.combo.connect('changed', lambda c: self.update_path())
 91
 92        # prepare to show
 93        self.update_path(hglib.toutf(self.repo.root))
 94
 95    def get_buttons(self):
 96        return [('archive', _('Archive'), gtk.RESPONSE_OK),
 97                ('close', gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)]
 98
 99    def get_action_map(self):
100        return {gtk.RESPONSE_OK: self.archive}
101
102    def switch_to(self, normal, working, cmd):
103        self.table.set_sensitive(normal)
104        self.buttons['archive'].set_property('visible', normal)
105        self.buttons['close'].set_property('visible', normal)
106        if normal:
107            self.buttons['close'].grab_focus()
108
109    def command_done(self, returncode, useraborted, *args):
110        if returncode == 0:
111            self.cmd.set_result(_('Archived successfully'), style='ok')
112        elif useraborted:
113            self.cmd.set_result(_('Canceled archiving'), style='error')
114        else:
115            self.cmd.set_result(_('Failed to archive'), style='error')
116
117    ### End of Overriding Section ###
118
119    def type_changed(self, radio):
120        if not radio.get_active():
121            return
122        self.update_path()
123
124    def update_path(self, path=None):
125        def remove_ext(path):
126            for ext in ('.tar', '.tar.bz2', '.tar.gz', '.zip'):
127                if path.endswith(ext):
128                    return path.replace(ext, '')
129            return path
130        def remove_rev(path):
131            model = self.combo.get_model()
132            revs = [rev[0] for rev in model]
133            revs.append(wdrev)
134            if not self.prevtarget is None:
135                revs.append(self.prevtarget)
136            for rev in ['_' + rev for rev in revs]:
137                if path.endswith(rev):
138                    return path.replace(rev, '')
139            return path
140        def add_rev(path, rev):
141            return '%s_%s' % (path, rev)
142        def add_ext(path):
143            select = self.get_selected_archive_type()
144            if select['type'] != 'files':
145                path += select['ext']
146            return path
147        text = self.combo.get_active_text()
148        if len(text) == 0:
149            return
150        wdrev = str(self.repo['.'].rev())
151        if text == WD_PARENT:
152            text = wdrev
153        else:
154            try:
155                self.repo[text]
156            except (error.RepoError, error.LookupError):
157                return
158        if path is None:
159            path = self.destentry.get_text()
160        path = remove_ext(path)
161        path = remove_rev(path)
162        path = add_rev(path, text)
163        path = add_ext(path)
164        self.destentry.set_text(path)
165        self.prevtarget = text
166
167    def get_selected_archive_type(self):
168        """Return a dictionary describing the selected archive type"""
169        if self.tarradio.get_active():
170            return {'type': 'tar', 'ext': '.tar',
171                    'label': _('Tar archives')}
172        elif self.tbz2radio.get_active():
173            return {'type': 'tbz2', 'ext': '.tar.bz2',
174                    'label': _('Bzip2 tar archives')}
175        elif self.tgzradio.get_active():
176            return {'type': 'tgz', 'ext': '.tar.gz',
177                    'label': _('Gzip tar archives')}
178        elif self.uzipradio.get_active():
179            return {'type': 'uzip', 'ext': '.zip',
180                    'label': ('Uncompressed zip archives')}
181        elif self.zipradio.get_active():
182            return {'type': 'zip', 'ext': '.zip',
183                    'label': _('Compressed zip archives')}
184        return {'type': 'files', 'ext': None, 'label': None}
185
186    def browse_clicked(self, button):
187        """Select the destination directory or file"""
188        dest = hglib.fromutf(self.destentry.get_text())
189        if not os.path.exists(dest):
190            dest = os.path.dirname(dest)
191        select = self.get_selected_archive_type()
192        if select['type'] == 'files':
193            response = gtklib.NativeFolderSelectDialog(
194                            initial=dest,
195                            title=_('Select Destination Folder')).run()
196        else:
197            ext = '*' + select['ext']
198            label = '%s (%s)' % (select['label'], ext)
199            response = gtklib.NativeSaveFileDialogWrapper(
200                            initial=dest, 
201                            title=_('Select Destination File'),
202                            filter=((label, ext),
203                                    (_('All Files (*.*)'), '*.*'))).run()
204        if response:
205            self.destentry.set_text(response)
206
207    def archive(self):
208        # verify input
209        type = self.get_selected_archive_type()['type']
210        dest = self.destentry.get_text()
211        if os.path.exists(dest):
212            if type != 'files':
213                ret = gdialog.Confirm(_('Confirm Overwrite'), [], self,
214                            _('The destination "%s" already exists!\n\n'
215                              'Do you want to overwrite it?') % dest).run()
216                if ret != gtk.RESPONSE_YES:
217                    return False
218            elif len(os.listdir(dest)) > 0:
219                ret = gdialog.Confirm(_('Confirm Overwrite'), [], self,
220                            _('The directory "%s" isn\'t empty!\n\n'
221                              'Do you want to overwrite it?') % dest).run()
222                if ret != gtk.RESPONSE_YES:
223                    return False
224
225        # prepare command line
226        cmdline = ['hg', 'archive', '--verbose']
227        rev = self.combo.get_active_text()
228        if rev != WD_PARENT:
229            cmdline.append('--rev')
230            cmdline.append(rev)
231        cmdline.append('-t')
232        cmdline.append(type)
233        if self.opt_files_in_rev.get_active():
234            ctx = self.repo[rev]
235            for f in ctx.files():
236                cmdline.append('-I')
237                cmdline.append(f)
238        cmdline.append('--')
239        cmdline.append(hglib.fromutf(dest))
240
241        # start archiving
242        self.execute_command(cmdline)
243
244def run(ui, *pats, **opts):
245    return ArchiveDialog(opts.get('rev'))