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()
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()