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

Reply via email to