示例#1
0
    def list(self, arg=None):
        assert not arg or arg == 'for-push'

        fetch = Git.config('cinnabar.fetch')
        if fetch:
            heads = [unhexlify(fetch)]
            branchmap = {None: heads}
            bookmarks = {}

        elif self._repo.capable('batch'):
            batch = self._repo.batch()
            branchmap = batch.branchmap()
            heads = batch.heads()
            bookmarks = batch.listkeys('bookmarks')
            batch.submit()
            branchmap = branchmap.value
            heads = heads.value
            bookmarks = bookmarks.value
            if heads == ['\0' * 20]:
                heads = []
        else:
            while True:
                branchmap = self._repo.branchmap()
                heads = self._repo.heads()
                if heads == ['\0' * 20]:
                    heads = []
                # Some branch heads can be non-heads topologically, but if
                # some heads don't appear in the branchmap, then something
                # was pushed to the repo between branchmap() and heads()
                if set(heads).issubset(set(chain(*branchmap.values()))):
                    break
            bookmarks = self._repo.listkeys('bookmarks')

        self._bookmarks = bookmarks
        branchmap = self._branchmap = BranchMap(self._store, branchmap,
                                                heads)
        self._has_unknown_heads = bool(self._branchmap.unknown_heads())
        if self._graft and self._has_unknown_heads and not arg:
            self._store.prepare_graft()
            self._store.init_fast_import()
            get_heads = set(branchmap.heads()) & branchmap.unknown_heads()
            getbundle(self._repo, self._store, get_heads, branchmap.names())
            # We may have failed to graft all changesets, in which case we
            # skipped them. If that's what happened, we want to create a
            # new branchmap containing all we do know about, so that we can
            # avoid telling git about things we don't know, because if we
            # didn't, it would ask for them, and subsequently fail because
            # they are missing.
            # Since we can't know for sure what the right tips might be for
            # each branch, we won't expose the tips. This means we don't
            # need to care about the order of the heads for the new
            # branchmap.
            self._has_unknown_heads = any(not(self._store.changeset_ref(h))
                                          for h in get_heads)
            if self._has_unknown_heads:
                new_branchmap = {
                    branch: set(h for h in branchmap.heads(branch))
                    for branch in branchmap.names()
                }
                new_branchmap = {
                    branch: set(h for h in branchmap.heads(branch)
                                if h not in branchmap.unknown_heads())
                    for branch in branchmap.names()
                }
                new_heads = set(h for h in branchmap.heads()
                                if h not in branchmap.unknown_heads())
                for status, head, branch in self._store._hgheads.iterchanges():
                    branch_heads = new_branchmap.get(branch)
                    if status == VersionedDict.REMOVED:
                        if branch_heads and head in branch_heads:
                            branch_heads.remove(head)
                        if head in new_heads:
                            new_heads.remove(head)
                    else:
                        if not branch_heads:
                            branch_heads = new_branchmap[branch] = set()
                        branch_heads.add(head)
                        new_heads.add(head)

                branchmap = self._branchmap = BranchMap(
                    self._store, new_branchmap, list(new_heads))

        refs = []
        for branch in sorted(branchmap.names()):
            branch_tip = branchmap.tip(branch)
            for head in sorted(branchmap.heads(branch)):
                sha1 = branchmap.git_sha1(head)
                refs.append(
                    ('hg/heads/%s/%s' % (
                        sanitize_branch_name(branch), head), sha1))
                if head == branch_tip:
                    continue
                refs.append(
                    ('refs/heads/branches/%s/%s' % (
                        sanitize_branch_name(branch), head), sha1))
            if branch_tip:
                refs.append(
                    ('refs/heads/branches/%s/tip' % (
                        sanitize_branch_name(branch)),
                     branchmap.git_sha1(branch_tip)))
                refs.append(
                    ('hg/tips/%s' % (
                        sanitize_branch_name(branch)),
                     branchmap.git_sha1(branch_tip)))

        for name, sha1 in sorted(bookmarks.iteritems()):
            if sha1 == NULL_NODE_ID:
                continue
            ref = self._store.changeset_ref(sha1)
            if self._graft and not ref:
                continue
            refs.append(
                ('hg/bookmarks/%s' % sanitize_branch_name(name),
                 ref if ref else '?'))
            refs.append(
                ('refs/heads/bookmarks/%s' % sanitize_branch_name(name),
                 ref if ref else '?'))
        if fetch:
            sha1 = self._store.changeset_ref(fetch)
            refs.append(('hg/revs/%s' % fetch, sha1 or '?'))
        if not self._has_unknown_heads:
            for tag, ref in sorted(self._store.tags(branchmap.heads())):
                refs.append(
                    ('refs/tags/%s' % sanitize_branch_name(tag), ref))

        if '@' in bookmarks:
            self._HEAD = 'bookmarks/@'
        head = bookmarks.get('@', branchmap.tip('default'))
        if self._graft and head:
            head = self._store.changeset_ref(head)
        if head:
            refs.append(('HEAD', '@refs/heads/%s' % self._HEAD))

        for k, v in sorted(refs):
            self._helper.write('%s %s\n' % (v, k))

        self._helper.write('\n')
        self._helper.flush()
示例#2
0
    def list(self, arg=None):
        assert not arg or arg == 'for-push'

        fetch = (Git.config('cinnabar.fetch') or '').split()
        if fetch:
            heads = [unhexlify(f) for f in fetch]
            branchmap = {None: heads}
            bookmarks = {}

        elif self._repo.capable('batch'):
            if hasattr(self._repo, 'commandexecutor'):
                with self._repo.commandexecutor() as e:
                    branchmap = e.callcommand('branchmap', {})
                    heads = e.callcommand('heads', {})
                    bookmarks = e.callcommand('listkeys',
                                              {'namespace': 'bookmarks'})
                branchmap = branchmap.result()
                heads = heads.result()
                bookmarks = bookmarks.result()
            elif hasattr(self._repo, 'iterbatch'):
                batch = self._repo.iterbatch()
                batch.branchmap()
                batch.heads()
                batch.listkeys('bookmarks')
                batch.submit()
                branchmap, heads, bookmarks = batch.results()
            else:
                batch = self._repo.batch()
                branchmap = batch.branchmap()
                heads = batch.heads()
                bookmarks = batch.listkeys('bookmarks')
                batch.submit()
                branchmap = branchmap.value
                heads = heads.value
                bookmarks = bookmarks.value
            if heads == ['\0' * 20]:
                heads = []
        else:
            while True:
                branchmap = self._repo.branchmap()
                heads = self._repo.heads()
                if heads == ['\0' * 20]:
                    heads = []
                # Some branch heads can be non-heads topologically, but if
                # some heads don't appear in the branchmap, then something
                # was pushed to the repo between branchmap() and heads()
                if set(heads).issubset(
                        set(chain(*(v for _, v in branchmap.iteritems())))):
                    break
            bookmarks = self._repo.listkeys('bookmarks')

        self._bookmarks = bookmarks
        branchmap = self._branchmap = BranchMap(self._store, branchmap, heads)
        self._has_unknown_heads = bool(self._branchmap.unknown_heads())
        if self._graft and self._has_unknown_heads and not arg:
            self._store.prepare_graft()
            get_heads = set(branchmap.heads()) & branchmap.unknown_heads()
            getbundle(self._repo, self._store, get_heads, branchmap.names())
            # We may have failed to graft all changesets, in which case we
            # skipped them. If that's what happened, we want to create a
            # new branchmap containing all we do know about, so that we can
            # avoid telling git about things we don't know, because if we
            # didn't, it would ask for them, and subsequently fail because
            # they are missing.
            # Since we can't know for sure what the right tips might be for
            # each branch, we won't expose the tips. This means we don't
            # need to care about the order of the heads for the new
            # branchmap.
            self._has_unknown_heads = any(not (self._store.changeset_ref(h))
                                          for h in get_heads)
            if self._has_unknown_heads:
                new_branchmap = {
                    branch: set(h for h in branchmap.heads(branch))
                    for branch in branchmap.names()
                }
                new_branchmap = {
                    branch: set(h for h in branchmap.heads(branch)
                                if h not in branchmap.unknown_heads())
                    for branch in branchmap.names()
                }
                new_heads = set(h for h in branchmap.heads()
                                if h not in branchmap.unknown_heads())
                for status, head, branch in self._store._hgheads.iterchanges():
                    branch_heads = new_branchmap.get(branch)
                    if status == VersionedDict.REMOVED:
                        if branch_heads and head in branch_heads:
                            branch_heads.remove(head)
                        if head in new_heads:
                            new_heads.remove(head)
                    else:
                        if not branch_heads:
                            branch_heads = new_branchmap[branch] = set()
                        branch_heads.add(head)
                        new_heads.add(head)

                branchmap = self._branchmap = BranchMap(
                    self._store, new_branchmap, list(new_heads))

        refs_style = None
        if not fetch and branchmap.heads():
            refs_styles = [
                None,
                '',
                'all',
                'bookmarks',
                'heads',
                'tips',
            ]

            refs_configs = ['cinnabar.refs']
            if arg == 'for-push':
                refs_configs.insert(0, 'cinnabar.pushrefs')

            for refs_config in refs_configs:
                refs_style = Git.config(refs_config,
                                        remote=self._remote.name,
                                        values=refs_styles)
                if refs_style:
                    break

        refs_style = refs_style or 'all'
        self._refs_style = refs_style

        refs = {}
        if refs_style in ('all', 'heads', 'tips'):
            if refs_style == 'all':
                self._head_template = 'refs/heads/branches/{}/{}'
                self._tip_template = 'refs/heads/branches/{}/tip'
            elif refs_style == 'heads':
                self._head_template = 'refs/heads/{}/{}'
            elif refs_style == 'tips':
                self._tip_template = 'refs/heads/{}'

            for branch in sorted(branchmap.names()):
                branch_tip = branchmap.tip(branch)
                if refs_style != 'tips':
                    for head in sorted(branchmap.heads(branch)):
                        if head == branch_tip and refs_style == 'all':
                            continue
                        refs[self._head_template.format(branch, head)] = head
                if branch_tip and refs_style != 'heads':
                    refs[self._tip_template.format(branch)] = branch_tip

        if refs_style in ('all', 'bookmarks'):
            if refs_style == 'all':
                self._bookmark_template = 'refs/heads/bookmarks/{}'
            else:
                self._bookmark_template = 'refs/heads/{}'
            for name, sha1 in sorted(bookmarks.iteritems()):
                if sha1 == NULL_NODE_ID:
                    continue
                ref = self._store.changeset_ref(sha1)
                if self._graft and not ref:
                    continue
                refs[self._bookmark_template.format(name)] = sha1

        for f in fetch:
            refs['hg/revs/%s' % f] = f

        head_ref = None
        if refs_style in ('all', 'bookmarks') and '@' in bookmarks:
            head_ref = self._bookmark_template.format('@')
        elif refs_style in ('all', 'tips'):
            head_ref = self._tip_template.format('default')
        elif refs_style == 'heads':
            head_ref = self._head_template.format('default',
                                                  branchmap.tip('default'))

        if head_ref:
            head = refs.get(head_ref)
            if self._graft and head:
                head = self._store.changeset_ref(head)
            if head:
                refs['HEAD'] = '@{}'.format(head_ref)

        self._refs = {sanitize_branch_name(k): v for k, v in refs.iteritems()}

        head_prefix = strip_suffix((self._head_template or ''), '{}/{}')
        for k, v in sorted(self._refs.iteritems()):
            if head_prefix and k.startswith(head_prefix):
                v = self._store.changeset_ref(v) or self._branchmap.git_sha1(v)
            elif not v.startswith('@'):
                v = self._store.changeset_ref(v) or '?'
            if not self._graft or v != '?':
                self._helper.write('%s %s\n' % (v, k))

        self._helper.write('\n')
        self._helper.flush()