Пример #1
0
def _rebundle(bundlerepo, bundleroots, unknownhead, cgversion, bundlecaps):
    """
    Bundle may include more revision then user requested. For example,
    if user asks for revision but bundle also consists its descendants.
    This function will filter out all revision that user is not requested.
    """
    parts = []

    outgoing = discovery.outgoing(bundlerepo,
                                  commonheads=bundleroots,
                                  missingheads=[unknownhead])
    cgstream = changegroup.makestream(bundlerepo,
                                      outgoing,
                                      cgversion,
                                      "pull",
                                      bundlecaps=bundlecaps)
    cgstream = util.chunkbuffer(cgstream).read()
    cgpart = bundle2.bundlepart("changegroup", data=cgstream)
    cgpart.addparam("version", cgversion)
    parts.append(cgpart)

    # This parsing should be refactored to be shared with
    # exchange.getbundlechunks. But I'll do that in a separate diff.
    if bundlecaps is None:
        bundlecaps = set()
    b2caps = {}
    for bcaps in bundlecaps:
        if bcaps.startswith("bundle2="):
            blob = util.urlreq.unquote(bcaps[len("bundle2="):])
            b2caps.update(bundle2.decodecaps(blob))

    if constants.scratchmutationparttype in b2caps:
        mutdata = mutation.bundle(bundlerepo, outgoing.missing)
        parts.append(
            bundle2.bundlepart(constants.scratchmutationparttype,
                               data=mutdata))

    try:
        treemod = extensions.find("treemanifest")
        remotefilelog = extensions.find("remotefilelog")
    except KeyError:
        pass
    else:
        missing = outgoing.missing
        if remotefilelog.shallowbundle.cansendtrees(bundlerepo,
                                                    missing,
                                                    source="pull",
                                                    bundlecaps=bundlecaps,
                                                    b2caps=b2caps):
            try:
                treepart = treemod.createtreepackpart(
                    bundlerepo, outgoing, treemod.TREEGROUP_PARTTYPE2)
                parts.append(treepart)
            except BaseException as ex:
                parts.append(bundle2.createerrorpart(str(ex)))

    try:
        snapshot = extensions.find("snapshot")
    except KeyError:
        pass
    else:
        snapshot.bundleparts.appendsnapshotmetadatabundlepart(
            bundlerepo, outgoing.missing, parts)

    return parts
Пример #2
0
def processparts(orig, repo, op, unbundler):
    if unbundler.params.get("infinitepush") != "True":
        return orig(repo, op, unbundler)

    handleallparts = repo.ui.configbool("infinitepush", "storeallparts")

    partforwardingwhitelist = [constants.scratchmutationparttype]
    try:
        treemfmod = extensions.find("treemanifest")
        partforwardingwhitelist.append(treemfmod.TREEGROUP_PARTTYPE2)
    except KeyError:
        pass

    try:
        snapshot = extensions.find("snapshot")
        partforwardingwhitelist.append(
            snapshot.bundleparts.snapshotmetadataparttype)
    except KeyError:
        pass

    bundler = bundle2.bundle20(repo.ui)
    compress = repo.ui.config("infinitepush", "bundlecompression", "UN")
    bundler.setcompression(compress)
    cgparams = None
    scratchbookpart = None
    with bundle2.partiterator(repo, op, unbundler) as parts:
        for part in parts:
            bundlepart = None
            if part.type == "replycaps":
                # This configures the current operation to allow reply parts.
                bundle2._processpart(op, part)
            elif part.type == constants.scratchbranchparttype:
                # Scratch branch parts need to be converted to normal
                # changegroup parts, and the extra parameters stored for later
                # when we upload to the store. Eventually those parameters will
                # be put on the actual bundle instead of this part, then we can
                # send a vanilla changegroup instead of the scratchbranch part.
                cgversion = part.params.get("cgversion", "01")
                bundlepart = bundle2.bundlepart("changegroup",
                                                data=part.read())
                bundlepart.addparam("version", cgversion)
                cgparams = part.params

                # If we're not dumping all parts into the new bundle, we need to
                # alert the future pushkey and phase-heads handler to skip
                # the part.
                if not handleallparts:
                    op.records.add(
                        constants.scratchbranchparttype + "_skippushkey", True)
                    op.records.add(
                        constants.scratchbranchparttype + "_skipphaseheads",
                        True)
            elif part.type == constants.scratchbookmarksparttype:
                # Save this for later processing. Details below.
                #
                # Upstream https://phab.mercurial-scm.org/D1389 and its
                # follow-ups stop part.seek support to reduce memory usage
                # (https://bz.mercurial-scm.org/5691). So we need to copy
                # the part so it can be consumed later.
                scratchbookpart = copiedpart(part)
            else:
                if handleallparts or part.type in partforwardingwhitelist:
                    # Ideally we would not process any parts, and instead just
                    # forward them to the bundle for storage, but since this
                    # differs from previous behavior, we need to put it behind a
                    # config flag for incremental rollout.
                    bundlepart = bundle2.bundlepart(part.type,
                                                    data=part.read())
                    for key, value in part.params.iteritems():
                        bundlepart.addparam(key, value)

                    # Certain parts require a response
                    if part.type == "pushkey":
                        if op.reply is not None:
                            rpart = op.reply.newpart("reply:pushkey")
                            rpart.addparam("in-reply-to",
                                           str(part.id),
                                           mandatory=False)
                            rpart.addparam("return", "1", mandatory=False)
                else:
                    bundle2._processpart(op, part)

            if handleallparts:
                op.records.add(part.type, {"return": 1})
            if bundlepart:
                bundler.addpart(bundlepart)

    # If commits were sent, store them
    if cgparams:
        buf = util.chunkbuffer(bundler.getchunks())
        fd, bundlefile = tempfile.mkstemp()
        try:
            try:
                fp = util.fdopen(fd, "wb")
                fp.write(buf.read())
            finally:
                fp.close()
            storebundle(op, cgparams, bundlefile)
        finally:
            try:
                os.unlink(bundlefile)
            except Exception:
                # we would rather see the original exception
                pass

    # The scratch bookmark part is sent as part of a push backup. It needs to be
    # processed after the main bundle has been stored, so that any commits it
    # references are available in the store.
    if scratchbookpart:
        bundle2._processpart(op, scratchbookpart)
Пример #3
0
def getstream(fname):
    with open(fname, "rb") as f:
        return util.chunkbuffer([f.read()])