shared repository extension

Brendan Cully brendan at kublai.com
Fri Nov 14 00:28:15 CST 2008


I've whipped up a little sugar for the symlink-.hg trick here:

http://hg.kublai.com/mercurial/extensions/sharedrepo/

It adds a --shared flag to the clone command. If you use it, the
working directory will share the repository of the source instead of
copying it. It's a lot like symlinking source/.hg/store to
dest/.hg/store, but should work in environments without symlinks.

This is only a proof of concept. I am thinking about extending it to
hide non-local revisions so that shared repositories appear more like
normal ones (until you delete the master repository!), but that'll
take a bit more effort.

For reference, the code looks like this:
-------------- next part --------------
# Shared repository extension
#
# Copyright 2008 Brendan Cully <brendan at kublai.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

'''shared repository support

This extension adds the --shared option to the clone command. When this
option is used, the destination uses the location passed as the argument
to --shared as its data store.
'''

from mercurial.i18n import _
from mercurial import commands, extensions, hg, localrepo, util

def sharedclone(orig, ui, source, dest=None, rev=None, noupdate=False, **kwargs):
    """
    With --shared, clone will set up the destination to use the existing
    source repository instead of creating a new one. The source repository
    must be local.
    """
    if kwargs.get('shared'):
        if not hg.islocal(source):
            raise util.Abort(_('source repository must be local'))

        if dest is None:
            dest = hg.defaultdest(source)
            ui.status(_("destination directory: %s\n") % dest)

        dest = hg.localpath(dest)
        if not hg.islocal(dest):
            raise util.Abort(_('destination repository must be local'))

        s, d = hg.clone(ui, source, dest=dest, rev=['null'], update=False)
        hgrc = d.opener('hgrc', 'a', text=True)
        hgrc.write('\n[shared]\nrepository = %s\n' % s.root)
        hgrc.close()
        reqs = d.opener('requires', 'a', text=True)
        reqs.write('shared\n')
        reqs.close()

        if not noupdate:
            d = hg.repository(ui, dest)
            d.ui.status(_("updating working directory\n"))
            for test in (rev and rev[-1] or None, 'default', 'tip'):
                try:
                    uprev = d.lookup(test)
                    break
                except:
                    continue
            hg.update(d, uprev)

        return

    return orig(ui, source, dest=dest, rev=rev, noupdate=noupdate, **kwargs)

def uisetup(ui):
    desc = extensions.wrapcommand(commands.table, 'clone', sharedclone)
    desc[0].__doc__ += sharedclone.__doc__
    opts = desc[1]
    opts.append(('', 'shared', None, _('reuse source repository')))

    lr = localrepo.localrepository
    lr.supported = tuple(list(lr.supported) + ['shared'])

def reposetup(ui, repo):
    if repo.local():
        spath = repo.ui.config('shared', 'repository')
        if spath:
            sr = hg.repository(ui, spath)
            repo.store = sr.store
            repo.sopener = sr.sopener
            repo.spath = sr.spath
            repo.sjoin = sr.sjoin




More information about the Mercurial mailing list