Beispiel #1
0
    def find_user_password(self, realm, authuri):
        authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
            self, realm, authuri)
        user, passwd = authinfo
        if user and passwd:
            self._writedebug(user, passwd)
            return (user, passwd)

        if not user or not passwd:
            res = httpconnectionmod.readauthforuri(self.ui, authuri, user)
            if res:
                group, auth = res
                user, passwd = auth.get('username'), auth.get('password')
                self.ui.debug("using auth.%s.* for authentication\n" % group)
        if not user or not passwd:
            u = util.url(authuri)
            u.query = None
            if not self.ui.interactive():
                raise util.Abort(_('http authorization required for %s') %
                                 util.hidepassword(str(u)))

            self.ui.write(_("http authorization required for %s\n") %
                          util.hidepassword(str(u)))
            self.ui.write(_("realm: %s\n") % realm)
            if user:
                self.ui.write(_("user: %s\n") % user)
            else:
                user = self.ui.prompt(_("user:"), default=None)

            if not passwd:
                passwd = self.ui.getpass()

        self.add_password(realm, authuri, user, passwd)
        self._writedebug(user, passwd)
        return (user, passwd)
Beispiel #2
0
def _incoming(displaychlist, subreporecurse, ui, repo, source,
        opts, buffered=False):
    """
    Helper for incoming / gincoming.
    displaychlist gets called with
        (remoterepo, incomingchangesetlist, displayer) parameters,
    and is supposed to contain only code that can't be unified.
    """
    source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
    other = peer(repo, opts, source)
    ui.status(_('comparing with %s\n') % util.hidepassword(source))
    revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))

    if revs:
        revs = [other.lookup(rev) for rev in revs]
    other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
                                revs, opts["bundle"], opts["force"])
    try:
        if not chlist:
            ui.status(_("no changes found\n"))
            return subreporecurse()

        displayer = cmdutil.show_changeset(ui, other, opts, buffered)

        # XXX once graphlog extension makes it into core,
        # should be replaced by a if graph/else
        displaychlist(other, chlist, displayer)

        displayer.close()
    finally:
        cleanupfn()
    subreporecurse()
    return 0 # exit code is zero since we found incoming changes
Beispiel #3
0
 def __init__(self, repo, remote, heads=None, force=False, bookmarks=()):
     # repo we pull into
     self.repo = repo
     # repo we pull from
     self.remote = remote
     # revision we try to pull (None is "all")
     self.heads = heads
     # bookmark pulled explicitly
     self.explicitbookmarks = bookmarks
     # do we force pull?
     self.force = force
     # the name the pull transaction
     self._trname = 'pull\n' + util.hidepassword(remote.url())
     # hold the transaction once created
     self._tr = None
     # set of common changeset between local and remote before pull
     self.common = None
     # set of pulled head
     self.rheads = None
     # list of missing changeset to fetch remotely
     self.fetch = None
     # remote bookmarks data
     self.remotebookmarks = None
     # result of changegroup pulling (used as return code by pull)
     self.cgresult = None
     # list of step already done
     self.stepsdone = set()
 def __init__(self, repo, remote, heads=None, force=False, bookmarks=()):
     # repo we pull into
     self.repo = repo
     # repo we pull from
     self.remote = remote
     # revision we try to pull (None is "all")
     self.heads = heads
     # bookmark pulled explicitly
     self.explicitbookmarks = bookmarks
     # do we force pull?
     self.force = force
     # the name the pull transaction
     self._trname = 'pull\n' + util.hidepassword(remote.url())
     # hold the transaction once created
     self._tr = None
     # set of common changeset between local and remote before pull
     self.common = None
     # set of pulled head
     self.rheads = None
     # list of missing changeset to fetch remotely
     self.fetch = None
     # remote bookmarks data
     self.remotebookmarks = None
     # result of changegroup pulling (used as return code by pull)
     self.cgresult = None
     # list of step already done
     self.stepsdone = set()
Beispiel #5
0
def _incoming(displaychlist,
              subreporecurse,
              ui,
              repo,
              source,
              opts,
              buffered=False):
    """
    Helper for incoming / gincoming.
    displaychlist gets called with
        (remoterepo, incomingchangesetlist, displayer) parameters,
    and is supposed to contain only code that can't be unified.
    """
    source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
    other = peer(repo, opts, source)
    ui.status(_('comparing with %s\n') % util.hidepassword(source))
    revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))

    if revs:
        revs = [other.lookup(rev) for rev in revs]
    other, chlist, cleanupfn = bundlerepo.getremotechanges(
        ui, repo, other, revs, opts["bundle"], opts["force"])
    try:
        if not chlist:
            ui.status(_("no changes found\n"))
            return subreporecurse()

        displayer = cmdutil.show_changeset(ui, other, opts, buffered)
        displaychlist(other, chlist, displayer)
        displayer.close()
    finally:
        cleanupfn()
    subreporecurse()
    return 0  # exit code is zero since we found incoming changes
Beispiel #6
0
 def transaction(self):
     """Return an open transaction object, constructing if necessary"""
     if not self._tr:
         trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
         self._tr = self.repo.transaction(trname)
         self._tr.hookargs['source'] = self.source
         self._tr.hookargs['url'] = self.url
     return self._tr
Beispiel #7
0
def _outgoing(ui, repo, dest, opts):
    dest = ui.expandpath(dest or "default-push", dest or "default")
    dest, branches = parseurl(dest, opts.get("branch"))
    ui.status(_("comparing with %s\n") % util.hidepassword(dest))
    revs, checkout = addbranchrevs(repo, repo, branches, opts.get("rev"))
    if revs:
        revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]

    other = peer(repo, opts, dest)
    outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs, force=opts.get("force"))
    o = outgoing.missing
    if not o:
        scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
    return o, other
Beispiel #8
0
    def find_user_password(self, realm, authuri):
        authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
            self, realm, authuri)
        user, passwd = authinfo
        if user and passwd:
            self._writedebug(user, passwd)
            return (user, passwd)

        if not user or not passwd:
            res = httpconnectionmod.readauthforuri(self.ui, authuri, user)
            if res:
                group, auth = res
                user, passwd = auth.get('username'), auth.get('password')
                self.ui.debug("using auth.%s.* for authentication\n" % group)
        if not user or not passwd:
            u = util.url(authuri)
            u.query = None
            if not self.ui.interactive():
                raise util.Abort(
                    _('http authorization required for %s') %
                    util.hidepassword(str(u)))

            self.ui.write(
                _("http authorization required for %s\n") %
                util.hidepassword(str(u)))
            self.ui.write(_("realm: %s\n") % realm)
            if user:
                self.ui.write(_("user: %s\n") % user)
            else:
                user = self.ui.prompt(_("user:"), default=None)

            if not passwd:
                passwd = self.ui.getpass()

        self.add_password(realm, authuri, user, passwd)
        self._writedebug(user, passwd)
        return (user, passwd)
Beispiel #9
0
def _outgoing(ui, repo, dest, opts):
    dest = ui.expandpath(dest or 'default-push', dest or 'default')
    dest, branches = parseurl(dest, opts.get('branch'))
    ui.status(_('comparing with %s\n') % util.hidepassword(dest))
    revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
    if revs:
        revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]

    other = peer(repo, opts, dest)
    outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
                                            force=opts.get('force'))
    o = outgoing.missing
    if not o:
        scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
    return o, other
Beispiel #10
0
def _outgoing(ui, repo, dest, opts):
    dest = ui.expandpath(dest or 'default-push', dest or 'default')
    dest, branches = parseurl(dest, opts.get('branch'))
    ui.status(_('comparing with %s\n') % util.hidepassword(dest))
    revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
    if revs:
        revs = [repo.lookup(rev) for rev in revs]

    other = peer(repo, opts, dest)
    outgoing = discovery.findcommonoutgoing(repo, other, revs,
                                            force=opts.get('force'))
    o = outgoing.missing
    if not o:
        scmutil.nochangesfound(repo.ui, outgoing.excluded)
        return None
    return o
Beispiel #11
0
def _outgoing(ui, repo, dest, opts):
    dest = ui.expandpath(dest or 'default-push', dest or 'default')
    dest, branches = parseurl(dest, opts.get('branch'))
    ui.status(_('comparing with %s\n') % util.hidepassword(dest))
    revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
    if revs:
        revs = [repo.lookup(rev) for rev in revs]

    other = peer(repo, opts, dest)
    common, outheads = discovery.findcommonoutgoing(repo,
                                                    other,
                                                    revs,
                                                    force=opts.get('force'))
    o = repo.changelog.findmissing(common, outheads)
    if not o:
        ui.status(_("no changes found\n"))
        return None
    return o
Beispiel #12
0
 def __init__(self, repo, remote, heads=None, force=False):
     # repo we pull into
     self.repo = repo
     # repo we pull from
     self.remote = remote
     # revision we try to pull (None is "all")
     self.heads = heads
     # do we force pull?
     self.force = force
     # the name the pull transaction
     self._trname = 'pull\n' + util.hidepassword(remote.url())
     # hold the transaction once created
     self._tr = None
     # set of common changeset between local and remote before pull
     self.common = None
     # set of pulled head
     self.rheads = None
     # list of missing changeset to fetch remotely
     self.fetch = None
     # result of changegroup pulling (used as return code by pull)
     self.cgresult = None
     # list of step remaining todo (related to future bundle2 usage)
     self.todosteps = set(['changegroup', 'phases', 'obsmarkers'])
Beispiel #13
0
def handleremotechangegroup(op, inpart):
    """apply a bundle10 on the repo, given an url and validation information

    All the information about the remote bundle to import are given as
    parameters. The parameters include:
      - url: the url to the bundle10.
      - size: the bundle10 file size. It is used to validate what was
        retrieved by the client matches the server knowledge about the bundle.
      - digests: a space separated list of the digest types provided as
        parameters.
      - digest:<digest-type>: the hexadecimal representation of the digest with
        that name. Like the size, it is used to validate what was retrieved by
        the client matches what the server knows about the bundle.

    When multiple digest types are given, all of them are checked.
    """
    try:
        raw_url = inpart.params['url']
    except KeyError:
        raise util.Abort(_('remote-changegroup: missing "%s" param') % 'url')
    parsed_url = util.url(raw_url)
    if parsed_url.scheme not in capabilities['b2x:remote-changegroup']:
        raise util.Abort(
            _('remote-changegroup does not support %s urls') %
            parsed_url.scheme)

    try:
        size = int(inpart.params['size'])
    except ValueError:
        raise util.Abort(
            _('remote-changegroup: invalid value for param "%s"') % 'size')
    except KeyError:
        raise util.Abort(_('remote-changegroup: missing "%s" param') % 'size')

    digests = {}
    for typ in inpart.params.get('digests', '').split():
        param = 'digest:%s' % typ
        try:
            value = inpart.params[param]
        except KeyError:
            raise util.Abort(
                _('remote-changegroup: missing "%s" param') % param)
        digests[typ] = value

    real_part = util.digestchecker(url.open(op.ui, raw_url), size, digests)

    # Make sure we trigger a transaction creation
    #
    # The addchangegroup function will get a transaction object by itself, but
    # we need to make sure we trigger the creation of a transaction object used
    # for the whole processing scope.
    op.gettransaction()
    import exchange
    cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
    if not isinstance(cg, changegroup.cg1unpacker):
        raise util.Abort(
            _('%s: not a bundle version 1.0') % util.hidepassword(raw_url))
    ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
    op.records.add('changegroup', {'return': ret})
    if op.reply is not None:
        # This is definitly not the final form of this
        # return. But one need to start somewhere.
        part = op.reply.newpart('b2x:reply:changegroup')
        part.addparam('in-reply-to', str(inpart.id), mandatory=False)
        part.addparam('return', '%i' % ret, mandatory=False)
    try:
        real_part.validate()
    except util.Abort, e:
        raise util.Abort(
            _('bundle at %s is corrupted:\n%s') %
            (util.hidepassword(raw_url), str(e)))
def addchangegroup(repo, source, srctype, url, emptyok=False):
    """Add the changegroup returned by source.read() to this repo.
    srctype is a string like 'push', 'pull', or 'unbundle'.  url is
    the URL of the repo where this changegroup is coming from.

    Return an integer summarizing the change to this repo:
    - nothing changed or no source: 0
    - more heads than before: 1+added heads (2..n)
    - fewer heads than before: -1-removed heads (-2..-n)
    - number of heads stays the same: 1
    """
    repo = repo.unfiltered()
    def csmap(x):
        repo.ui.debug("add changeset %s\n" % short(x))
        return len(cl)

    def revmap(x):
        return cl.rev(x)

    if not source:
        return 0

    repo.hook('prechangegroup', throw=True, source=srctype, url=url)

    changesets = files = revisions = 0
    efiles = set()

    # write changelog data to temp files so concurrent readers will not see
    # inconsistent view
    cl = repo.changelog
    cl.delayupdate()
    oldheads = cl.heads()

    tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
    try:
        trp = weakref.proxy(tr)
        # pull off the changeset group
        repo.ui.status(_("adding changesets\n"))
        clstart = len(cl)
        class prog(object):
            step = _('changesets')
            count = 1
            ui = repo.ui
            total = None
            def __call__(repo):
                repo.ui.progress(repo.step, repo.count, unit=_('chunks'),
                                 total=repo.total)
                repo.count += 1
        pr = prog()
        source.callback = pr

        source.changelogheader()
        srccontent = cl.addgroup(source, csmap, trp)
        if not (srccontent or emptyok):
            raise util.Abort(_("received changelog group is empty"))
        clend = len(cl)
        changesets = clend - clstart
        for c in xrange(clstart, clend):
            efiles.update(repo[c].files())
        efiles = len(efiles)
        repo.ui.progress(_('changesets'), None)

        # pull off the manifest group
        repo.ui.status(_("adding manifests\n"))
        pr.step = _('manifests')
        pr.count = 1
        pr.total = changesets # manifests <= changesets
        # no need to check for empty manifest group here:
        # if the result of the merge of 1 and 2 is the same in 3 and 4,
        # no new manifest will be created and the manifest group will
        # be empty during the pull
        source.manifestheader()
        repo.manifest.addgroup(source, revmap, trp)
        repo.ui.progress(_('manifests'), None)

        needfiles = {}
        if repo.ui.configbool('server', 'validate', default=False):
            # validate incoming csets have their manifests
            for cset in xrange(clstart, clend):
                mfest = repo.changelog.read(repo.changelog.node(cset))[0]
                mfest = repo.manifest.readdelta(mfest)
                # store file nodes we must see
                for f, n in mfest.iteritems():
                    needfiles.setdefault(f, set()).add(n)

        # process the files
        repo.ui.status(_("adding file changes\n"))
        pr.step = _('files')
        pr.count = 1
        pr.total = efiles
        source.callback = None

        newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
                                                needfiles)
        revisions += newrevs
        files += newfiles

        dh = 0
        if oldheads:
            heads = cl.heads()
            dh = len(heads) - len(oldheads)
            for h in heads:
                if h not in oldheads and repo[h].closesbranch():
                    dh -= 1
        htext = ""
        if dh:
            htext = _(" (%+d heads)") % dh

        repo.ui.status(_("added %d changesets"
                         " with %d changes to %d files%s\n")
                         % (changesets, revisions, files, htext))
        repo.invalidatevolatilesets()

        if changesets > 0:
            p = lambda: cl.writepending() and repo.root or ""
            if 'node' not in tr.hookargs:
                tr.hookargs['node'] = hex(cl.node(clstart))
            repo.hook('pretxnchangegroup', throw=True, source=srctype,
                      url=url, pending=p, **tr.hookargs)

        added = [cl.node(r) for r in xrange(clstart, clend)]
        publishing = repo.ui.configbool('phases', 'publish', True)
        if srctype in ('push', 'serve'):
            # Old servers can not push the boundary themselves.
            # New servers won't push the boundary if changeset already
            # exists locally as secret
            #
            # We should not use added here but the list of all change in
            # the bundle
            if publishing:
                phases.advanceboundary(repo, phases.public, srccontent)
            else:
                phases.advanceboundary(repo, phases.draft, srccontent)
                phases.retractboundary(repo, phases.draft, added)
        elif srctype != 'strip':
            # publishing only alter behavior during push
            #
            # strip should not touch boundary at all
            phases.retractboundary(repo, phases.draft, added)

        # make changelog see real files again
        cl.finalize(trp)

        tr.close()

        if changesets > 0:
            if srctype != 'strip':
                # During strip, branchcache is invalid but coming call to
                # `destroyed` will repair it.
                # In other case we can safely update cache on disk.
                branchmap.updatecache(repo.filtered('served'))
            def runhooks():
                # These hooks run when the lock releases, not when the
                # transaction closes. So it's possible for the changelog
                # to have changed since we last saw it.
                if clstart >= len(repo):
                    return

                # forcefully update the on-disk branch cache
                repo.ui.debug("updating the branch cache\n")
                repo.hook("changegroup", source=srctype, url=url,
                          **tr.hookargs)

                for n in added:
                    repo.hook("incoming", node=hex(n), source=srctype,
                              url=url)

                newheads = [h for h in repo.heads() if h not in oldheads]
                repo.ui.log("incoming",
                            "%s incoming changes - new heads: %s\n",
                            len(added),
                            ', '.join([hex(c[:6]) for c in newheads]))
            repo._afterlock(runhooks)

    finally:
        tr.release()
    # never return 0 here:
    if dh < 0:
        return dh - 1
    else:
        return dh + 1
Beispiel #15
0
            # this only happens with Python 2.3, later versions raise URLError
            raise util.Abort(_('http error, possibly caused by proxy setting'))
        # record the url we got redirected to
        resp_url = resp.geturl()
        if resp_url.endswith(qs):
            resp_url = resp_url[:-len(qs)]
        if self._url.rstrip('/') != resp_url.rstrip('/'):
            if not self.ui.quiet:
                self.ui.warn(_('real URL is %s\n') % resp_url)
        self._url = resp_url
        try:
            proto = resp.getheader('content-type')
        except AttributeError:
            proto = resp.headers.get('content-type', '')

        safeurl = util.hidepassword(self._url)
        if proto.startswith('application/hg-error'):
            raise error.OutOfBandError(resp.read())
        # accept old "text/plain" and "application/hg-changegroup" for now
        if not (proto.startswith('application/mercurial-') or
                (proto.startswith('text/plain')
                 and not resp.headers.get('content-length')) or
                proto.startswith('application/hg-changegroup')):
            self.ui.debug("requested URL: '%s'\n" % util.hidepassword(cu))
            raise error.RepoError(
                _("'%s' does not appear to be an hg repository:\n"
                  "---%%<--- (%s)\n%s\n---%%<---\n")
                % (safeurl, proto or 'no content-type', resp.read(1024)))

        if proto.startswith('application/mercurial-'):
            try:
Beispiel #16
0
def handleremotechangegroup(op, inpart):
    """apply a bundle10 on the repo, given an url and validation information

    All the information about the remote bundle to import are given as
    parameters. The parameters include:
      - url: the url to the bundle10.
      - size: the bundle10 file size. It is used to validate what was
        retrieved by the client matches the server knowledge about the bundle.
      - digests: a space separated list of the digest types provided as
        parameters.
      - digest:<digest-type>: the hexadecimal representation of the digest with
        that name. Like the size, it is used to validate what was retrieved by
        the client matches what the server knows about the bundle.

    When multiple digest types are given, all of them are checked.
    """
    try:
        raw_url = inpart.params['url']
    except KeyError:
        raise util.Abort(_('remote-changegroup: missing "%s" param') % 'url')
    parsed_url = util.url(raw_url)
    if parsed_url.scheme not in capabilities['b2x:remote-changegroup']:
        raise util.Abort(_('remote-changegroup does not support %s urls') %
            parsed_url.scheme)

    try:
        size = int(inpart.params['size'])
    except ValueError:
        raise util.Abort(_('remote-changegroup: invalid value for param "%s"')
            % 'size')
    except KeyError:
        raise util.Abort(_('remote-changegroup: missing "%s" param') % 'size')

    digests = {}
    for typ in inpart.params.get('digests', '').split():
        param = 'digest:%s' % typ
        try:
            value = inpart.params[param]
        except KeyError:
            raise util.Abort(_('remote-changegroup: missing "%s" param') %
                param)
        digests[typ] = value

    real_part = util.digestchecker(url.open(op.ui, raw_url), size, digests)

    # Make sure we trigger a transaction creation
    #
    # The addchangegroup function will get a transaction object by itself, but
    # we need to make sure we trigger the creation of a transaction object used
    # for the whole processing scope.
    op.gettransaction()
    import exchange
    cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
    if not isinstance(cg, changegroup.cg1unpacker):
        raise util.Abort(_('%s: not a bundle version 1.0') %
            util.hidepassword(raw_url))
    ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
    op.records.add('changegroup', {'return': ret})
    if op.reply is not None:
        # This is definitly not the final form of this
        # return. But one need to start somewhere.
        part = op.reply.newpart('b2x:reply:changegroup')
        part.addparam('in-reply-to', str(inpart.id), mandatory=False)
        part.addparam('return', '%i' % ret, mandatory=False)
    try:
        real_part.validate()
    except util.Abort, e:
        raise util.Abort(_('bundle at %s is corrupted:\n%s') %
            (util.hidepassword(raw_url), str(e)))
Beispiel #17
0
def addchangegroup(repo,
                   source,
                   srctype,
                   url,
                   emptyok=False,
                   targetphase=phases.draft,
                   expectedtotal=None):
    """Add the changegroup returned by source.read() to this repo.
    srctype is a string like 'push', 'pull', or 'unbundle'.  url is
    the URL of the repo where this changegroup is coming from.

    Return an integer summarizing the change to this repo:
    - nothing changed or no source: 0
    - more heads than before: 1+added heads (2..n)
    - fewer heads than before: -1-removed heads (-2..-n)
    - number of heads stays the same: 1
    """
    repo = repo.unfiltered()

    def csmap(x):
        repo.ui.debug("add changeset %s\n" % short(x))
        return len(cl)

    def revmap(x):
        return cl.rev(x)

    if not source:
        return 0

    changesets = files = revisions = 0
    efiles = set()

    tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
    # The transaction could have been created before and already carries source
    # information. In this case we use the top level data. We overwrite the
    # argument because we need to use the top level value (if they exist) in
    # this function.
    srctype = tr.hookargs.setdefault('source', srctype)
    url = tr.hookargs.setdefault('url', url)

    # write changelog data to temp files so concurrent readers will not see
    # inconsistent view
    cl = repo.changelog
    cl.delayupdate(tr)
    oldheads = cl.heads()
    try:
        repo.hook('prechangegroup', throw=True, **tr.hookargs)

        trp = weakref.proxy(tr)
        # pull off the changeset group
        repo.ui.status(_("adding changesets\n"))
        clstart = len(cl)

        class prog(object):
            def __init__(self, step, total):
                self._step = step
                self._total = total
                self._count = 1

            def __call__(self):
                repo.ui.progress(self._step,
                                 self._count,
                                 unit=_('chunks'),
                                 total=self._total)
                self._count += 1

        source.callback = prog(_('changesets'), expectedtotal)

        source.changelogheader()
        srccontent = cl.addgroup(source, csmap, trp)
        if not (srccontent or emptyok):
            raise util.Abort(_("received changelog group is empty"))
        clend = len(cl)
        changesets = clend - clstart
        for c in xrange(clstart, clend):
            efiles.update(repo[c].files())
        efiles = len(efiles)
        repo.ui.progress(_('changesets'), None)

        # pull off the manifest group
        repo.ui.status(_("adding manifests\n"))
        # manifests <= changesets
        source.callback = prog(_('manifests'), changesets)
        # no need to check for empty manifest group here:
        # if the result of the merge of 1 and 2 is the same in 3 and 4,
        # no new manifest will be created and the manifest group will
        # be empty during the pull
        source.manifestheader()
        repo.manifest.addgroup(source, revmap, trp)
        repo.ui.progress(_('manifests'), None)

        needfiles = {}
        if repo.ui.configbool('server', 'validate', default=False):
            # validate incoming csets have their manifests
            for cset in xrange(clstart, clend):
                mfnode = repo.changelog.read(repo.changelog.node(cset))[0]
                mfest = repo.manifest.readdelta(mfnode)
                # store file nodes we must see
                for f, n in mfest.iteritems():
                    needfiles.setdefault(f, set()).add(n)

        # process the files
        repo.ui.status(_("adding file changes\n"))
        source.callback = None
        pr = prog(_('files'), efiles)
        newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
                                                needfiles)
        revisions += newrevs
        files += newfiles

        dh = 0
        if oldheads:
            heads = cl.heads()
            dh = len(heads) - len(oldheads)
            for h in heads:
                if h not in oldheads and repo[h].closesbranch():
                    dh -= 1
        htext = ""
        if dh:
            htext = _(" (%+d heads)") % dh

        repo.ui.status(
            _("added %d changesets"
              " with %d changes to %d files%s\n") %
            (changesets, revisions, files, htext))
        repo.invalidatevolatilesets()

        if changesets > 0:
            p = lambda: tr.writepending() and repo.root or ""
            if 'node' not in tr.hookargs:
                tr.hookargs['node'] = hex(cl.node(clstart))
                hookargs = dict(tr.hookargs)
            else:
                hookargs = dict(tr.hookargs)
                hookargs['node'] = hex(cl.node(clstart))
            repo.hook('pretxnchangegroup', throw=True, pending=p, **hookargs)

        added = [cl.node(r) for r in xrange(clstart, clend)]
        publishing = repo.publishing()
        if srctype in ('push', 'serve'):
            # Old servers can not push the boundary themselves.
            # New servers won't push the boundary if changeset already
            # exists locally as secret
            #
            # We should not use added here but the list of all change in
            # the bundle
            if publishing:
                phases.advanceboundary(repo, tr, phases.public, srccontent)
            else:
                # Those changesets have been pushed from the outside, their
                # phases are going to be pushed alongside. Therefor
                # `targetphase` is ignored.
                phases.advanceboundary(repo, tr, phases.draft, srccontent)
                phases.retractboundary(repo, tr, phases.draft, added)
        elif srctype != 'strip':
            # publishing only alter behavior during push
            #
            # strip should not touch boundary at all
            phases.retractboundary(repo, tr, targetphase, added)

        if changesets > 0:
            if srctype != 'strip':
                # During strip, branchcache is invalid but coming call to
                # `destroyed` will repair it.
                # In other case we can safely update cache on disk.
                branchmap.updatecache(repo.filtered('served'))

            def runhooks():
                # These hooks run when the lock releases, not when the
                # transaction closes. So it's possible for the changelog
                # to have changed since we last saw it.
                if clstart >= len(repo):
                    return

                # forcefully update the on-disk branch cache
                repo.ui.debug("updating the branch cache\n")
                repo.hook("changegroup", **hookargs)

                for n in added:
                    args = hookargs.copy()
                    args['node'] = hex(n)
                    repo.hook("incoming", **args)

                newheads = [h for h in repo.heads() if h not in oldheads]
                repo.ui.log("incoming",
                            "%s incoming changes - new heads: %s\n",
                            len(added),
                            ', '.join([hex(c[:6]) for c in newheads]))

            tr.addpostclose('changegroup-runhooks-%020i' % clstart,
                            lambda tr: repo._afterlock(runhooks))

        tr.close()

    finally:
        tr.release()
        repo.ui.flush()
    # never return 0 here:
    if dh < 0:
        return dh - 1
    else:
        return dh + 1
Beispiel #18
0
    def _callstream(self, cmd, **args):
        if cmd == 'pushkey':
            args['data'] = ''
        data = args.pop('data', None)
        size = 0
        if util.safehasattr(data, 'length'):
            size = data.length
        elif data is not None:
            size = len(data)
        headers = args.pop('headers', {})
        if data is not None and 'Content-Type' not in headers:
            headers['Content-Type'] = 'application/mercurial-0.1'


        if size and self.ui.configbool('ui', 'usehttp2', False):
            headers['Expect'] = '100-Continue'
            headers['X-HgHttp2'] = '1'

        self.ui.debug("sending %s command\n" % cmd)
        q = [('cmd', cmd)]
        headersize = 0
        if len(args) > 0:
            httpheader = self.capable('httpheader')
            if httpheader:
                headersize = int(httpheader.split(',')[0])
        if headersize > 0:
            # The headers can typically carry more data than the URL.
            encargs = urllib.urlencode(sorted(args.items()))
            headerfmt = 'X-HgArg-%s'
            contentlen = headersize - len(headerfmt % '000' + ': \r\n')
            headernum = 0
            for i in xrange(0, len(encargs), contentlen):
                headernum += 1
                header = headerfmt % str(headernum)
                headers[header] = encargs[i:i + contentlen]
            varyheaders = [headerfmt % str(h) for h in range(1, headernum + 1)]
            headers['Vary'] = ','.join(varyheaders)
        else:
            q += sorted(args.items())
        qs = '?%s' % urllib.urlencode(q)
        cu = "%s%s" % (self._url, qs)
        req = self.requestbuilder(cu, data, headers)
        if data is not None:
            self.ui.debug("sending %s bytes\n" % size)
            req.add_unredirected_header('Content-Length', '%d' % size)
        try:
            resp = self.urlopener.open(req)
        except urllib2.HTTPError as inst:
            if inst.code == 401:
                raise util.Abort(_('authorization failed'))
            raise
        except httplib.HTTPException as inst:
            self.ui.debug('http error while sending %s command\n' % cmd)
            self.ui.traceback()
            raise IOError(None, inst)
        except IndexError:
            # this only happens with Python 2.3, later versions raise URLError
            raise util.Abort(_('http error, possibly caused by proxy setting'))
        # record the url we got redirected to
        resp_url = resp.geturl()
        if resp_url.endswith(qs):
            resp_url = resp_url[:-len(qs)]
        if self._url.rstrip('/') != resp_url.rstrip('/'):
            if not self.ui.quiet:
                self.ui.warn(_('real URL is %s\n') % resp_url)
        self._url = resp_url
        try:
            proto = resp.getheader('content-type')
        except AttributeError:
            proto = resp.headers.get('content-type', '')

        safeurl = util.hidepassword(self._url)
        if proto.startswith('application/hg-error'):
            raise error.OutOfBandError(resp.read())
        # accept old "text/plain" and "application/hg-changegroup" for now
        if not (proto.startswith('application/mercurial-') or
                (proto.startswith('text/plain')
                 and not resp.headers.get('content-length')) or
                proto.startswith('application/hg-changegroup')):
            self.ui.debug("requested URL: '%s'\n" % util.hidepassword(cu))
            raise error.RepoError(
                _("'%s' does not appear to be an hg repository:\n"
                  "---%%<--- (%s)\n%s\n---%%<---\n")
                % (safeurl, proto or 'no content-type', resp.read(1024)))

        if proto.startswith('application/mercurial-'):
            try:
                version = proto.split('-', 1)[1]
                version_info = tuple([int(n) for n in version.split('.')])
            except ValueError:
                raise error.RepoError(_("'%s' sent a broken Content-Type "
                                        "header (%s)") % (safeurl, proto))
            if version_info > (0, 1):
                raise error.RepoError(_("'%s' uses newer protocol %s") %
                                      (safeurl, version))

        return resp