On Sun, Jul 12, 2009 at 3:28 PM, emmanuel<goaway1...@gmail.com> wrote: > # HG changeset patch > # User erosa <goaway1...@gmail.com> > # Date 1247430071 14400 > # Node ID 6fac56c1f654e4f8ecc244564410a59c623ecca1 > # Parent f7e45cdf3f0c6b04f70732c74e4c2ddbb0c8710b > add ability to archive selected revision > > hggtk: add archive command and archive dialog box > history: add archive command to context menu
Nicely done, pushed to crew. I only have two comments: 1) You don't have to cc: me with patches, the mailing list is just fine. 2) You can credit yourself with the copyright for archive.py. Feel free to submit a patch to make that change. Thanks. -- Steve Borho > diff -r f7e45cdf3f0c -r 6fac56c1f654 hggtk/archive.py > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/hggtk/archive.py Sun Jul 12 16:21:11 2009 -0400 > @@ -0,0 +1,209 @@ > +# > +# archive.py - TortoiseHg's dialog for archiving a repo revision > +# > +# Copyright (C) 2007 TK Soh <teekay...@gmail.com> > +# > + > +import os > +import gtk > +import gobject > +import pango > + > +from mercurial import hg, ui > + > +from thgutil.i18n import _ > +from thgutil import hglib, paths > + > +from hggtk import hgcmd, gtklib > + > +_working_dir_parent_ = _('= Working Directory Parent =') > + > +class ArchiveDialog(gtk.Window): > + """ Dialog to archive a Mercurial repo """ > + def __init__(self, rev=None): > + """ Initialize the Dialog """ > + gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) > + gtklib.set_tortoise_icon(self, 'menucheckout.ico') > + gtklib.set_tortoise_keys(self) > + > + self.set_default_size(550, 120) > + self.notify_func = None > + > + try: > + repo = hg.repository(ui.ui(), path=paths.find_root()) > + except hglib.RepoError: > + gobject.idle_add(self.destroy) > + return > + > + title = _('Archive - %s') % > hglib.toutf(os.path.basename(repo.root)) > + self.set_title(title) > + > + vbox = gtk.VBox() > + self.add(vbox) > + > + hbox = gtk.HBox() > + lbl = gtk.Label(_('Archive revision:')) > + hbox.pack_start(lbl, False, False, 2) > + > + # revisions editable combo box > + combo = gtk.combo_box_entry_new_text() > + hbox.pack_start(combo, True, True, 2) > + vbox.pack_start(hbox, False, False, 10) > + if rev: > + combo.append_text(str(rev)) > + else: > + combo.append_text(_working_dir_parent_) > + combo.set_active(0) > + for b in repo.branchtags(): > + combo.append_text(b) > + tags = list(repo.tags()) > + tags.sort() > + tags.reverse() > + for t in tags: > + combo.append_text(t) > + > + vbox.add(self.get_destination_container(self.get_default_path())) > + vbox.add(self.get_type_container()) > + > + hbbox = gtk.HButtonBox() > + hbbox.set_layout(gtk.BUTTONBOX_END) > + vbox.pack_start(hbbox, False, False, 2) > + close = gtk.Button(_('Close')) > + close.connect('clicked', lambda x: self.destroy()) > + > + accelgroup = gtk.AccelGroup() > + self.add_accel_group(accelgroup) > + key, modifier = gtk.accelerator_parse('Escape') > + close.add_accelerator('clicked', accelgroup, key, 0, > + gtk.ACCEL_VISIBLE) > + hbbox.add(close) > + > + archive = gtk.Button(_('Archive')) > + archive.connect('clicked', self.archive, combo, repo) > + mod = gtklib.get_thg_modifier() > + key, modifier = gtk.accelerator_parse(mod+'Return') > + archive.add_accelerator('clicked', accelgroup, key, modifier, > + gtk.ACCEL_VISIBLE) > + hbbox.add(archive) > + archive.grab_focus() > + > + entry = combo.child > + entry.connect('activate', self.entry_activated, archive, combo, > repo) > + > + def get_type_container(self): > + """Return a frame containing the supported archive types""" > + frame = gtk.Frame(_('Archive type')) > + vbox = gtk.VBox() > + > + self.filesradio = gtk.RadioButton(None, _('Directory of files')) > + self.tarradio = gtk.RadioButton(self.filesradio, > _('Uncompressed tar archive')) > + self.tbz2radio = gtk.RadioButton(self.filesradio, _('Tar > archive compressed using bzip2')) > + self.tgzradio = gtk.RadioButton(self.filesradio, _('Tar archive > compressed using gzip')) > + self.uzipradio = gtk.RadioButton(self.filesradio, > _('Uncompressed zip archive')) > + self.zipradio = gtk.RadioButton(self.filesradio, _('Zip archive > compressed using deflate')) > + > + vbox.pack_start(self.filesradio, True, True, 2) > + vbox.pack_start(self.tarradio, True, True, 2) > + vbox.pack_start(self.tbz2radio, True, True, 2) > + vbox.pack_start(self.tgzradio, True, True, 2) > + vbox.pack_start(self.uzipradio, True, True, 2) > + vbox.pack_start(self.zipradio, True, True, 2) > + frame.add(vbox) > + frame.set_border_width(2) > + return frame > + > + def get_destination_container(self, default_path): > + """Return an hbox containing the widgets for the destination > path""" > + hbox = gtk.HBox() > + lbl = gtk.Label(_('Destination Path:')) > + > + # create drop-down list for source paths > + self.destlist = gtk.ListStore(str) > + destcombo = gtk.ComboBoxEntry(self.destlist, 0) > + self.destentry = destcombo.get_child() > + self.destentry.set_text(default_path) > + self.destentry.set_position(-1) > + > + # replace the drop-down widget so we can modify it's properties > + destcombo.clear() > + cell = gtk.CellRendererText() > + cell.set_property('ellipsize', pango.ELLIPSIZE_MIDDLE) > + destcombo.pack_start(cell) > + destcombo.add_attribute(cell, 'text', 0) > + > + destbrowse = gtk.Button(_('Browse...')) > + destbrowse.connect('clicked', self.browse_clicked) > + hbox.pack_start(lbl, False, False) > + hbox.pack_start(destcombo, True, True, 2) > + hbox.pack_end(destbrowse, False, False, 5) > + return hbox > + > + def get_default_path(self): > + """Return the default destination path""" > + return hglib.toutf(os.getcwd()) > + > + def get_save_file_dialog(self, filter): > + """Return a configured save file dialog""" > + return gtklib.NativeSaveFileDialogWrapper( > + InitialDir=self.destentry.get_text(), > + Title=_('Select Destination File'), > + Filter=filter) > + > + def get_selected_archive_type(self): > + """Return a dictionary describing the selected archive type""" > + dict = {} > + if self.tarradio.get_active(): > + dict['type'] = 'tar' > + dict['filter'] = ((_('Tar archives'), '*.tar'),) > + elif self.tbz2radio.get_active(): > + dict['type'] = 'tbz2' > + dict['filter'] = ((_('Bzip2 tar archives'), '*.tbz2'),) > + elif self.tgzradio.get_active(): > + dict['type'] = 'tgz' > + dict['filter'] = ((_('Gzip tar archives'), '*.tgz'),) > + elif self.uzipradio.get_active(): > + dict['type'] = 'uzip' > + dict['filter'] = ((_('Uncompressed zip archives'), '*.uzip'),) > + elif self.zipradio.get_active(): > + dict['type'] = 'zip' > + dict['filter'] = ((_('Compressed zip archives'), '*.zip'),) > + else: > + dict['type'] = 'files' > + > + return dict > + > + def entry_activated(self, entry, button, combo, repo): > + self.update(button, combo, repo) > + > + def browse_clicked(self, button): > + """Select the destination directory or file""" > + archive_type = self.get_selected_archive_type() > + if archive_type['type'] == 'files': > + response = gtklib.NativeFolderSelectDialog( > + initial=self.destentry.get_text(), > + title=_('Select Destination Folder')).run() > + else: > + filter = archive_type['filter'] > + response = self.get_save_file_dialog(filter).run() > + > + if response: > + self.destentry.set_text(response) > + > + def archive(self, button, combo, repo): > + rev = combo.get_active_text() > + > + cmdline = ['hg', 'archive', '--verbose'] > + if rev != _working_dir_parent_: > + cmdline.append('--rev') > + cmdline.append(rev) > + > + cmdline.append('-t') > + cmdline.append(self.get_selected_archive_type()['type']) > + cmdline.append(self.destentry.get_text()) > + > + dlg = hgcmd.CmdDialog(cmdline) > + dlg.run() > + dlg.hide() > + > +def run(ui, *pats, **opts): > + return ArchiveDialog(opts.get('rev')) > diff -r f7e45cdf3f0c -r 6fac56c1f654 hggtk/hgtk.py > --- a/hggtk/hgtk.py Sun Jul 12 10:06:16 2009 -0500 > +++ b/hggtk/hgtk.py Sun Jul 12 16:21:11 2009 -0400 > @@ -611,6 +611,11 @@ > cmdlist = [' '.join(c[0]) for c in cmdlist.values()] > ui.write("%s\n" % "\n".join(sorted(cmdlist))) > > +def archive(ui, *pats, **opts): > + """create an unversioned archive of a repository revision""" > + from hggtk.archive import run > + gtkrun(run, ui, *pats, **opts) > + > globalopts = [ > ('R', 'repository', '', > _('repository root directory or symbolic path name')), > @@ -676,4 +681,7 @@ > [('o', 'options', None, _('show the command options'))], > _('[-o] CMD')), > "help": (help_, [], _('hgtk help [COMMAND]')), > + "^archive": (archive, > + [('r', 'rev', '', _('revision to update'))], > + ('hgtk archive')), > } > diff -r f7e45cdf3f0c -r 6fac56c1f654 hggtk/history.py > --- a/hggtk/history.py Sun Jul 12 10:06:16 2009 -0500 > +++ b/hggtk/history.py Sun Jul 12 16:21:11 2009 -0400 > @@ -20,7 +20,7 @@ > from hggtk.logview.treeview import TreeView as LogTreeView > > from hggtk import gdialog, gtklib, hgcmd, datamine, logfilter > -from hggtk import backout, status, hgemail, tagadd, update, merge > +from hggtk import backout, status, hgemail, tagadd, update, merge, archive > from hggtk import changeset > > def create_menu(label, callback): > @@ -400,6 +400,7 @@ > m.append(create_menu(_('add/remove _tag'), self.add_tag)) > m.append(create_menu(_('backout revision'), self.backout_rev)) > m.append(create_menu(_('_revert'), self.revert)) > + m.append(create_menu(_('_archive'), self.archive)) > > # need mq extension for strip command > extensions.loadall(self.ui) > @@ -755,6 +756,15 @@ > elif not oldparents == newparents: > self.refresh_model() > > + def archive(self, menuitem): > + rev = self.currow[treemodel.REVID] > + parents = [x.node() for x in self.repo.parents()] > + dialog = archive.ArchiveDialog(rev) > + dialog.set_transient_for(self) > + dialog.show_all() > + dialog.present() > + dialog.set_transient_for(None) > + > def selection_changed(self, treeview): > self.currow = self.graphview.get_revision() > rev = self.currow[treemodel.REVID] > > > # HG changeset patch > # User Emmanuel Rosa <goaway1...@gmail.com> > # Date 1247430071 14400 > # Node ID 6fac56c1f654e4f8ecc244564410a59c623ecca1 > # Parent f7e45cdf3f0c6b04f70732c74e4c2ddbb0c8710b > add ability to archive selected revision > > hggtk: add archive command and archive dialog box > history: add archive command to context menu > > diff -r f7e45cdf3f0c -r 6fac56c1f654 hggtk/archive.py > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/hggtk/archive.py Sun Jul 12 16:21:11 2009 -0400 > @@ -0,0 +1,209 @@ > +# > +# archive.py - TortoiseHg's dialog for archiving a repo revision > +# > +# Copyright (C) 2007 TK Soh <teekay...@gmail.com> > +# > + > +import os > +import gtk > +import gobject > +import pango > + > +from mercurial import hg, ui > + > +from thgutil.i18n import _ > +from thgutil import hglib, paths > + > +from hggtk import hgcmd, gtklib > + > +_working_dir_parent_ = _('= Working Directory Parent =') > + > +class ArchiveDialog(gtk.Window): > + """ Dialog to archive a Mercurial repo """ > + def __init__(self, rev=None): > + """ Initialize the Dialog """ > + gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) > + gtklib.set_tortoise_icon(self, 'menucheckout.ico') > + gtklib.set_tortoise_keys(self) > + > + self.set_default_size(550, 120) > + self.notify_func = None > + > + try: > + repo = hg.repository(ui.ui(), path=paths.find_root()) > + except hglib.RepoError: > + gobject.idle_add(self.destroy) > + return > + > + title = _('Archive - %s') % hglib.toutf(os.path.basename(repo.root)) > + self.set_title(title) > + > + vbox = gtk.VBox() > + self.add(vbox) > + > + hbox = gtk.HBox() > + lbl = gtk.Label(_('Archive revision:')) > + hbox.pack_start(lbl, False, False, 2) > + > + # revisions editable combo box > + combo = gtk.combo_box_entry_new_text() > + hbox.pack_start(combo, True, True, 2) > + vbox.pack_start(hbox, False, False, 10) > + if rev: > + combo.append_text(str(rev)) > + else: > + combo.append_text(_working_dir_parent_) > + combo.set_active(0) > + for b in repo.branchtags(): > + combo.append_text(b) > + tags = list(repo.tags()) > + tags.sort() > + tags.reverse() > + for t in tags: > + combo.append_text(t) > + > + vbox.add(self.get_destination_container(self.get_default_path())) > + vbox.add(self.get_type_container()) > + > + hbbox = gtk.HButtonBox() > + hbbox.set_layout(gtk.BUTTONBOX_END) > + vbox.pack_start(hbbox, False, False, 2) > + close = gtk.Button(_('Close')) > + close.connect('clicked', lambda x: self.destroy()) > + > + accelgroup = gtk.AccelGroup() > + self.add_accel_group(accelgroup) > + key, modifier = gtk.accelerator_parse('Escape') > + close.add_accelerator('clicked', accelgroup, key, 0, > + gtk.ACCEL_VISIBLE) > + hbbox.add(close) > + > + archive = gtk.Button(_('Archive')) > + archive.connect('clicked', self.archive, combo, repo) > + mod = gtklib.get_thg_modifier() > + key, modifier = gtk.accelerator_parse(mod+'Return') > + archive.add_accelerator('clicked', accelgroup, key, modifier, > + gtk.ACCEL_VISIBLE) > + hbbox.add(archive) > + archive.grab_focus() > + > + entry = combo.child > + entry.connect('activate', self.entry_activated, archive, combo, repo) > + > + def get_type_container(self): > + """Return a frame containing the supported archive types""" > + frame = gtk.Frame(_('Archive type')) > + vbox = gtk.VBox() > + > + self.filesradio = gtk.RadioButton(None, _('Directory of files')) > + self.tarradio = gtk.RadioButton(self.filesradio, _('Uncompressed tar > archive')) > + self.tbz2radio = gtk.RadioButton(self.filesradio, _('Tar archive > compressed using bzip2')) > + self.tgzradio = gtk.RadioButton(self.filesradio, _('Tar archive > compressed using gzip')) > + self.uzipradio = gtk.RadioButton(self.filesradio, _('Uncompressed > zip archive')) > + self.zipradio = gtk.RadioButton(self.filesradio, _('Zip archive > compressed using deflate')) > + > + vbox.pack_start(self.filesradio, True, True, 2) > + vbox.pack_start(self.tarradio, True, True, 2) > + vbox.pack_start(self.tbz2radio, True, True, 2) > + vbox.pack_start(self.tgzradio, True, True, 2) > + vbox.pack_start(self.uzipradio, True, True, 2) > + vbox.pack_start(self.zipradio, True, True, 2) > + frame.add(vbox) > + frame.set_border_width(2) > + return frame > + > + def get_destination_container(self, default_path): > + """Return an hbox containing the widgets for the destination path""" > + hbox = gtk.HBox() > + lbl = gtk.Label(_('Destination Path:')) > + > + # create drop-down list for source paths > + self.destlist = gtk.ListStore(str) > + destcombo = gtk.ComboBoxEntry(self.destlist, 0) > + self.destentry = destcombo.get_child() > + self.destentry.set_text(default_path) > + self.destentry.set_position(-1) > + > + # replace the drop-down widget so we can modify it's properties > + destcombo.clear() > + cell = gtk.CellRendererText() > + cell.set_property('ellipsize', pango.ELLIPSIZE_MIDDLE) > + destcombo.pack_start(cell) > + destcombo.add_attribute(cell, 'text', 0) > + > + destbrowse = gtk.Button(_('Browse...')) > + destbrowse.connect('clicked', self.browse_clicked) > + hbox.pack_start(lbl, False, False) > + hbox.pack_start(destcombo, True, True, 2) > + hbox.pack_end(destbrowse, False, False, 5) > + return hbox > + > + def get_default_path(self): > + """Return the default destination path""" > + return hglib.toutf(os.getcwd()) > + > + def get_save_file_dialog(self, filter): > + """Return a configured save file dialog""" > + return gtklib.NativeSaveFileDialogWrapper( > + InitialDir=self.destentry.get_text(), > + Title=_('Select Destination File'), > + Filter=filter) > + > + def get_selected_archive_type(self): > + """Return a dictionary describing the selected archive type""" > + dict = {} > + if self.tarradio.get_active(): > + dict['type'] = 'tar' > + dict['filter'] = ((_('Tar archives'), '*.tar'),) > + elif self.tbz2radio.get_active(): > + dict['type'] = 'tbz2' > + dict['filter'] = ((_('Bzip2 tar archives'), '*.tbz2'),) > + elif self.tgzradio.get_active(): > + dict['type'] = 'tgz' > + dict['filter'] = ((_('Gzip tar archives'), '*.tgz'),) > + elif self.uzipradio.get_active(): > + dict['type'] = 'uzip' > + dict['filter'] = ((_('Uncompressed zip archives'), '*.uzip'),) > + elif self.zipradio.get_active(): > + dict['type'] = 'zip' > + dict['filter'] = ((_('Compressed zip archives'), '*.zip'),) > + else: > + dict['type'] = 'files' > + > + return dict > + > + def entry_activated(self, entry, button, combo, repo): > + self.update(button, combo, repo) > + > + def browse_clicked(self, button): > + """Select the destination directory or file""" > + archive_type = self.get_selected_archive_type() > + if archive_type['type'] == 'files': > + response = gtklib.NativeFolderSelectDialog( > + initial=self.destentry.get_text(), > + title=_('Select Destination Folder')).run() > + else: > + filter = archive_type['filter'] > + response = self.get_save_file_dialog(filter).run() > + > + if response: > + self.destentry.set_text(response) > + > + def archive(self, button, combo, repo): > + rev = combo.get_active_text() > + > + cmdline = ['hg', 'archive', '--verbose'] > + if rev != _working_dir_parent_: > + cmdline.append('--rev') > + cmdline.append(rev) > + > + cmdline.append('-t') > + cmdline.append(self.get_selected_archive_type()['type']) > + cmdline.append(self.destentry.get_text()) > + > + dlg = hgcmd.CmdDialog(cmdline) > + dlg.run() > + dlg.hide() > + > +def run(ui, *pats, **opts): > + return ArchiveDialog(opts.get('rev')) > diff -r f7e45cdf3f0c -r 6fac56c1f654 hggtk/hgtk.py > --- a/hggtk/hgtk.py Sun Jul 12 10:06:16 2009 -0500 > +++ b/hggtk/hgtk.py Sun Jul 12 16:21:11 2009 -0400 > @@ -611,6 +611,11 @@ > cmdlist = [' '.join(c[0]) for c in cmdlist.values()] > ui.write("%s\n" % "\n".join(sorted(cmdlist))) > > +def archive(ui, *pats, **opts): > + """create an unversioned archive of a repository revision""" > + from hggtk.archive import run > + gtkrun(run, ui, *pats, **opts) > + > globalopts = [ > ('R', 'repository', '', > _('repository root directory or symbolic path name')), > @@ -676,4 +681,7 @@ > [('o', 'options', None, _('show the command options'))], > _('[-o] CMD')), > "help": (help_, [], _('hgtk help [COMMAND]')), > + "^archive": (archive, > + [('r', 'rev', '', _('revision to update'))], > + ('hgtk archive')), > } > diff -r f7e45cdf3f0c -r 6fac56c1f654 hggtk/history.py > --- a/hggtk/history.py Sun Jul 12 10:06:16 2009 -0500 > +++ b/hggtk/history.py Sun Jul 12 16:21:11 2009 -0400 > @@ -20,7 +20,7 @@ > from hggtk.logview.treeview import TreeView as LogTreeView > > from hggtk import gdialog, gtklib, hgcmd, datamine, logfilter > -from hggtk import backout, status, hgemail, tagadd, update, merge > +from hggtk import backout, status, hgemail, tagadd, update, merge, archive > from hggtk import changeset > > def create_menu(label, callback): > @@ -400,6 +400,7 @@ > m.append(create_menu(_('add/remove _tag'), self.add_tag)) > m.append(create_menu(_('backout revision'), self.backout_rev)) > m.append(create_menu(_('_revert'), self.revert)) > + m.append(create_menu(_('_archive'), self.archive)) > > # need mq extension for strip command > extensions.loadall(self.ui) > @@ -755,6 +756,15 @@ > elif not oldparents == newparents: > self.refresh_model() > > + def archive(self, menuitem): > + rev = self.currow[treemodel.REVID] > + parents = [x.node() for x in self.repo.parents()] > + dialog = archive.ArchiveDialog(rev) > + dialog.set_transient_for(self) > + dialog.show_all() > + dialog.present() > + dialog.set_transient_for(None) > + > def selection_changed(self, treeview): > self.currow = self.graphview.get_revision() > rev = self.currow[treemodel.REVID] > > ------------------------------------------------------------------------------ > Enter the BlackBerry Developer Challenge > This is your chance to win up to $100,000 in prizes! For a limited time, > vendors submitting new applications to BlackBerry App World(TM) will have > the opportunity to enter the BlackBerry Developer Challenge. See full prize > details at: http://p.sf.net/sfu/Challenge > _______________________________________________ > Tortoisehg-develop mailing list > Tortoisehg-develop@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/tortoisehg-develop > > ------------------------------------------------------------------------------ Enter the BlackBerry Developer Challenge This is your chance to win up to $100,000 in prizes! For a limited time, vendors submitting new applications to BlackBerry App World(TM) will have the opportunity to enter the BlackBerry Developer Challenge. See full prize details at: http://p.sf.net/sfu/Challenge _______________________________________________ Tortoisehg-develop mailing list Tortoisehg-develop@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tortoisehg-develop