Beispiel #1
0
def handlechangegroup_widen(op, inpart):
    """Changegroup exchange handler which restores temporarily-stripped nodes"""
    # We saved a bundle with stripped node data we must now restore.
    # This approach is based on mercurial/repair.py@6ee26a53c111.
    repo = op.repo
    ui = op.ui

    chgrpfile = op._widen_bundle
    del op._widen_bundle
    vfs = repo.vfs

    ui.note(_(b"adding branch\n"))
    f = vfs.open(chgrpfile, b"rb")
    try:
        gen = exchange.readbundle(ui, f, chgrpfile, vfs)
        # silence internal shuffling chatter
        override = {(b'ui', b'quiet'): True}
        if ui.verbose:
            override = {}
        with ui.configoverride(override):
            if isinstance(gen, bundle2.unbundle20):
                with repo.transaction(b'strip') as tr:
                    bundle2.processbundle(repo, gen, lambda: tr)
            else:
                gen.apply(
                    repo, b'strip', b'bundle:' + vfs.join(chgrpfile), True
                )
    finally:
        f.close()

    # remove undo files
    for undovfs, undofile in repo.undofiles():
        try:
            undovfs.unlink(undofile)
        except OSError as e:
            if e.errno != errno.ENOENT:
                ui.warn(
                    _(b'error removing %s: %s\n')
                    % (undovfs.join(undofile), stringutil.forcebytestr(e))
                )

    # Remove partial backup only if there were no exceptions
    op._widen_uninterr.__exit__(None, None, None)
    vfs.unlink(chgrpfile)
Beispiel #2
0
def gitgetmeta(ui, repo, source='default'):
    '''get git metadata from a server that supports fb_gitmeta'''
    source, branch = hg.parseurl(ui.expandpath(source))
    other = hg.peer(repo, {}, source)
    ui.status(_('getting git metadata from %s\n') %
              util.hidepassword(source))

    kwargs = {'bundlecaps': exchange.caps20to10(repo)}
    capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
    kwargs['bundlecaps'].add('bundle2=' + util.urlreq.quote(capsblob))
    # this would ideally not be in the bundlecaps at all, but adding new kwargs
    # for wire transmissions is not possible as of Mercurial d19164a018a1
    kwargs['bundlecaps'].add('fb_gitmeta')
    kwargs['heads'] = [nullid]
    kwargs['cg'] = False
    kwargs['common'] = _getcommonheads(repo)
    bundle = other.getbundle('pull', **kwargs)
    try:
        op = bundle2.processbundle(repo, bundle)
    except error.BundleValueError as exc:
        raise error.Abort('missing support for %s' % exc)
    writebytes = op.records['fb:gitmeta:writebytes']
    ui.status(_('wrote %d files (%d bytes)\n') %
              (len(writebytes), sum(writebytes)))
Beispiel #3
0
def _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
           newincludes, newexcludes):
    newmatch = narrowspec.match(repo.root, newincludes, newexcludes)

    # for now we assume that if a server has ellipses enabled, we will be
    # exchanging ellipses nodes. In future we should add ellipses as a client
    # side requirement (maybe) to distinguish a client is shallow or not and
    # then send that information to server whether we want ellipses or not.
    # Theoretically a non-ellipses repo should be able to use narrow
    # functionality from an ellipses enabled server
    ellipsesremote = wireprototypes.ELLIPSESCAP in remote.capabilities()

    def pullbundle2extraprepare_widen(orig, pullop, kwargs):
        orig(pullop, kwargs)
        # The old{in,ex}cludepats have already been set by orig()
        kwargs['includepats'] = newincludes
        kwargs['excludepats'] = newexcludes
    wrappedextraprepare = extensions.wrappedfunction(exchange,
        '_pullbundle2extraprepare', pullbundle2extraprepare_widen)

    # define a function that narrowbundle2 can call after creating the
    # backup bundle, but before applying the bundle from the server
    def setnewnarrowpats():
        repo.setnarrowpats(newincludes, newexcludes)
    repo.setnewnarrowpats = setnewnarrowpats
    # silence the devel-warning of applying an empty changegroup
    overrides = {('devel', 'all-warnings'): False}

    with ui.uninterruptable():
        common = commoninc[0]
        if ellipsesremote:
            ds = repo.dirstate
            p1, p2 = ds.p1(), ds.p2()
            with ds.parentchange():
                ds.setparents(node.nullid, node.nullid)
            with wrappedextraprepare,\
                 repo.ui.configoverride(overrides, 'widen'):
                exchange.pull(repo, remote, heads=common)
            with ds.parentchange():
                ds.setparents(p1, p2)
        else:
            with remote.commandexecutor() as e:
                bundle = e.callcommand('narrow_widen', {
                    'oldincludes': oldincludes,
                    'oldexcludes': oldexcludes,
                    'newincludes': newincludes,
                    'newexcludes': newexcludes,
                    'cgversion': '03',
                    'commonheads': common,
                    'known': [],
                    'ellipses': False,
                }).result()

            with repo.transaction('widening') as tr,\
                 repo.ui.configoverride(overrides, 'widen'):
                tgetter = lambda: tr
                bundle2.processbundle(repo, bundle,
                        transactiongetter=tgetter)

        repo.setnewnarrowpats()
        actions = {k: [] for k in 'a am f g cd dc r dm dg m e k p pr'.split()}
        addgaction = actions['g'].append

        mf = repo['.'].manifest().matches(newmatch)
        for f, fn in mf.iteritems():
            if f not in repo.dirstate:
                addgaction((f, (mf.flags(f), False),
                            "add from widened narrow clone"))

        merge.applyupdates(repo, actions, wctx=repo[None],
                           mctx=repo['.'], overwrite=False)
        merge.recordupdates(repo, actions, branchmerge=False)
Beispiel #4
0
def _widen(
    ui,
    repo,
    remote,
    commoninc,
    oldincludes,
    oldexcludes,
    newincludes,
    newexcludes,
):
    # for now we assume that if a server has ellipses enabled, we will be
    # exchanging ellipses nodes. In future we should add ellipses as a client
    # side requirement (maybe) to distinguish a client is shallow or not and
    # then send that information to server whether we want ellipses or not.
    # Theoretically a non-ellipses repo should be able to use narrow
    # functionality from an ellipses enabled server
    remotecap = remote.capabilities()
    ellipsesremote = any(cap in remotecap
                         for cap in wireprototypes.SUPPORTED_ELLIPSESCAP)

    # check whether we are talking to a server which supports old version of
    # ellipses capabilities
    isoldellipses = (ellipsesremote
                     and wireprototypes.ELLIPSESCAP1 in remotecap
                     and wireprototypes.ELLIPSESCAP not in remotecap)

    def pullbundle2extraprepare_widen(orig, pullop, kwargs):
        orig(pullop, kwargs)
        # The old{in,ex}cludepats have already been set by orig()
        kwargs[b'includepats'] = newincludes
        kwargs[b'excludepats'] = newexcludes

    wrappedextraprepare = extensions.wrappedfunction(
        exchange, b'_pullbundle2extraprepare', pullbundle2extraprepare_widen)

    # define a function that narrowbundle2 can call after creating the
    # backup bundle, but before applying the bundle from the server
    def setnewnarrowpats():
        repo.setnarrowpats(newincludes, newexcludes)

    repo.setnewnarrowpats = setnewnarrowpats
    # silence the devel-warning of applying an empty changegroup
    overrides = {(b'devel', b'all-warnings'): False}

    common = commoninc[0]
    with ui.uninterruptible():
        if ellipsesremote:
            ds = repo.dirstate
            p1, p2 = ds.p1(), ds.p2()
            with ds.parentchange():
                ds.setparents(node.nullid, node.nullid)
        if isoldellipses:
            with wrappedextraprepare:
                exchange.pull(repo, remote, heads=common)
        else:
            known = []
            if ellipsesremote:
                known = [
                    ctx.node() for ctx in repo.set(b'::%ln', common)
                    if ctx.node() != node.nullid
                ]
            with remote.commandexecutor() as e:
                bundle = e.callcommand(
                    b'narrow_widen',
                    {
                        b'oldincludes': oldincludes,
                        b'oldexcludes': oldexcludes,
                        b'newincludes': newincludes,
                        b'newexcludes': newexcludes,
                        b'cgversion': b'03',
                        b'commonheads': common,
                        b'known': known,
                        b'ellipses': ellipsesremote,
                    },
                ).result()

            trmanager = exchange.transactionmanager(repo, b'widen',
                                                    remote.url())
            with trmanager, repo.ui.configoverride(overrides, b'widen'):
                op = bundle2.bundleoperation(repo,
                                             trmanager.transaction,
                                             source=b'widen')
                # TODO: we should catch error.Abort here
                bundle2.processbundle(repo, bundle, op=op)

        if ellipsesremote:
            with ds.parentchange():
                ds.setparents(p1, p2)

        with repo.transaction(b'widening'):
            repo.setnewnarrowpats()
            narrowspec.updateworkingcopy(repo)
            narrowspec.copytoworkingcopy(repo)
Beispiel #5
0
def strip(ui, repo, nodelist, backup=True, topic='backup'):

    # Simple way to maintain backwards compatibility for this
    # argument.
    if backup in ['none', 'strip']:
        backup = False

    repo = repo.unfiltered()
    repo.destroying()

    cl = repo.changelog
    # TODO handle undo of merge sets
    if isinstance(nodelist, str):
        nodelist = [nodelist]
    striplist = [cl.rev(node) for node in nodelist]
    striprev = min(striplist)

    # Some revisions with rev > striprev may not be descendants of striprev.
    # We have to find these revisions and put them in a bundle, so that
    # we can restore them after the truncations.
    # To create the bundle we use repo.changegroupsubset which requires
    # the list of heads and bases of the set of interesting revisions.
    # (head = revision in the set that has no descendant in the set;
    #  base = revision in the set that has no ancestor in the set)
    tostrip = set(striplist)
    for rev in striplist:
        for desc in cl.descendants([rev]):
            tostrip.add(desc)

    files = _collectfiles(repo, striprev)
    saverevs = _collectbrokencsets(repo, files, striprev)

    # compute heads
    saveheads = set(saverevs)
    for r in xrange(striprev + 1, len(cl)):
        if r not in tostrip:
            saverevs.add(r)
            saveheads.difference_update(cl.parentrevs(r))
            saveheads.add(r)
    saveheads = [cl.node(r) for r in saveheads]

    # compute base nodes
    if saverevs:
        descendants = set(cl.descendants(saverevs))
        saverevs.difference_update(descendants)
    savebases = [cl.node(r) for r in saverevs]
    stripbases = [cl.node(r) for r in tostrip]

    # For a set s, max(parents(s) - s) is the same as max(heads(::s - s)), but
    # is much faster
    newbmtarget = repo.revs('max(parents(%ld) - (%ld))', tostrip, tostrip)
    if newbmtarget:
        newbmtarget = repo[newbmtarget.first()].node()
    else:
        newbmtarget = '.'

    bm = repo._bookmarks
    updatebm = []
    for m in bm:
        rev = repo[bm[m]].rev()
        if rev in tostrip:
            updatebm.append(m)

    # create a changegroup for all the branches we need to keep
    backupfile = None
    vfs = repo.vfs
    node = nodelist[-1]
    if backup:
        backupfile = _bundle(repo, stripbases, cl.heads(), node, topic)
        repo.ui.status(_("saved backup bundle to %s\n") %
                       vfs.join(backupfile))
        repo.ui.log("backupbundle", "saved backup bundle to %s\n",
                    vfs.join(backupfile))
    if saveheads or savebases:
        # do not compress partial bundle if we remove it from disk later
        chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
                            compress=False)

    mfst = repo.manifest

    tr = repo.transaction("strip")
    offset = len(tr.entries)

    try:
        tr.startgroup()
        cl.strip(striprev, tr)
        mfst.strip(striprev, tr)
        for fn in files:
            repo.file(fn).strip(striprev, tr)
        tr.endgroup()

        try:
            for i in xrange(offset, len(tr.entries)):
                file, troffset, ignore = tr.entries[i]
                repo.svfs(file, 'a').truncate(troffset)
                if troffset == 0:
                    repo.store.markremoved(file)
            tr.close()
        except: # re-raises
            tr.abort()
            raise

        if saveheads or savebases:
            ui.note(_("adding branch\n"))
            f = vfs.open(chgrpfile, "rb")
            gen = exchange.readbundle(ui, f, chgrpfile, vfs)
            if not repo.ui.verbose:
                # silence internal shuffling chatter
                repo.ui.pushbuffer()
            if isinstance(gen, bundle2.unbundle20):
                tr = repo.transaction('strip')
                tr.hookargs = {'source': 'strip',
                               'url': 'bundle:' + vfs.join(chgrpfile)}
                try:
                    bundle2.processbundle(repo, gen, lambda: tr)
                    tr.close()
                finally:
                    tr.release()
            else:
                changegroup.addchangegroup(repo, gen, 'strip',
                                           'bundle:' + vfs.join(chgrpfile),
                                           True)
            if not repo.ui.verbose:
                repo.ui.popbuffer()
            f.close()

        # remove undo files
        for undovfs, undofile in repo.undofiles():
            try:
                undovfs.unlink(undofile)
            except OSError, e:
                if e.errno != errno.ENOENT:
                    ui.warn(_('error removing %s: %s\n') %
                            (undovfs.join(undofile), str(e)))

        for m in updatebm:
            bm[m] = repo[newbmtarget].node()
        bm.write()
Beispiel #6
0
def strip(ui, repo, nodelist, backup=True, topic='backup'):

    # Simple way to maintain backwards compatibility for this
    # argument.
    if backup in ['none', 'strip']:
        backup = False

    repo = repo.unfiltered()
    repo.destroying()

    cl = repo.changelog
    # TODO handle undo of merge sets
    if isinstance(nodelist, str):
        nodelist = [nodelist]
    striplist = [cl.rev(node) for node in nodelist]
    striprev = min(striplist)

    # Some revisions with rev > striprev may not be descendants of striprev.
    # We have to find these revisions and put them in a bundle, so that
    # we can restore them after the truncations.
    # To create the bundle we use repo.changegroupsubset which requires
    # the list of heads and bases of the set of interesting revisions.
    # (head = revision in the set that has no descendant in the set;
    #  base = revision in the set that has no ancestor in the set)
    tostrip = set(striplist)
    for rev in striplist:
        for desc in cl.descendants([rev]):
            tostrip.add(desc)

    files = _collectfiles(repo, striprev)
    saverevs = _collectbrokencsets(repo, files, striprev)

    # compute heads
    saveheads = set(saverevs)
    for r in xrange(striprev + 1, len(cl)):
        if r not in tostrip:
            saverevs.add(r)
            saveheads.difference_update(cl.parentrevs(r))
            saveheads.add(r)
    saveheads = [cl.node(r) for r in saveheads]

    # compute base nodes
    if saverevs:
        descendants = set(cl.descendants(saverevs))
        saverevs.difference_update(descendants)
    savebases = [cl.node(r) for r in saverevs]
    stripbases = [cl.node(r) for r in tostrip]

    # For a set s, max(parents(s) - s) is the same as max(heads(::s - s)), but
    # is much faster
    newbmtarget = repo.revs('max(parents(%ld) - (%ld))', tostrip, tostrip)
    if newbmtarget:
        newbmtarget = repo[newbmtarget.first()].node()
    else:
        newbmtarget = '.'

    bm = repo._bookmarks
    updatebm = []
    for m in bm:
        rev = repo[bm[m]].rev()
        if rev in tostrip:
            updatebm.append(m)

    # create a changegroup for all the branches we need to keep
    backupfile = None
    vfs = repo.vfs
    if backup:
        backupfile = _bundle(repo, stripbases, cl.heads(), node, topic)
        repo.ui.status(_("saved backup bundle to %s\n") % vfs.join(backupfile))
        repo.ui.log("backupbundle", "saved backup bundle to %s\n",
                    vfs.join(backupfile))
    if saveheads or savebases:
        # do not compress partial bundle if we remove it from disk later
        chgrpfile = _bundle(repo,
                            savebases,
                            saveheads,
                            node,
                            'temp',
                            compress=False)

    mfst = repo.manifest

    tr = repo.transaction("strip")
    offset = len(tr.entries)

    try:
        tr.startgroup()
        cl.strip(striprev, tr)
        mfst.strip(striprev, tr)
        for fn in files:
            repo.file(fn).strip(striprev, tr)
        tr.endgroup()

        try:
            for i in xrange(offset, len(tr.entries)):
                file, troffset, ignore = tr.entries[i]
                repo.svfs(file, 'a').truncate(troffset)
                if troffset == 0:
                    repo.store.markremoved(file)
            tr.close()
        except:  # re-raises
            tr.abort()
            raise

        if saveheads or savebases:
            ui.note(_("adding branch\n"))
            f = vfs.open(chgrpfile, "rb")
            gen = exchange.readbundle(ui, f, chgrpfile, vfs)
            if not repo.ui.verbose:
                # silence internal shuffling chatter
                repo.ui.pushbuffer()
            if isinstance(gen, bundle2.unbundle20):
                tr = repo.transaction('strip')
                try:
                    bundle2.processbundle(repo, gen, lambda: tr)
                    tr.close()
                finally:
                    tr.release()
            else:
                changegroup.addchangegroup(repo, gen, 'strip',
                                           'bundle:' + vfs.join(chgrpfile),
                                           True)
            if not repo.ui.verbose:
                repo.ui.popbuffer()
            f.close()

        # remove undo files
        for undovfs, undofile in repo.undofiles():
            try:
                undovfs.unlink(undofile)
            except OSError, e:
                if e.errno != errno.ENOENT:
                    ui.warn(
                        _('error removing %s: %s\n') %
                        (undovfs.join(undofile), str(e)))

        for m in updatebm:
            bm[m] = repo[newbmtarget].node()
        bm.write()