def _get_revision(self, revision): """ Gets an ID revision given as str. This will always return a fill 40 char revision number :param revision: str or int or None """ if isinstance(revision, unicode): revision = safe_str(revision) if self._empty: raise EmptyRepositoryError("There are no changesets yet") if revision in [-1, 'tip', None]: revision = 'tip' try: revision = hex(self._repo.lookup(revision)) except (IndexError, ValueError, RepoLookupError, TypeError): msg = ("Revision %s does not exist for %s" % (revision, self)) raise ChangesetDoesNotExistError(msg) except (LookupError, ): msg = ("Ambiguous identifier `%s` for %s" % (revision, self)) raise ChangesetDoesNotExistError(msg) return revision
def _get_revision(self, revision): """ Gets an ID revision given as str. This will always return a fill 40 char revision number :param revision: str or int or None """ if isinstance(revision, unicode): revision = safe_str(revision) if self._empty: raise EmptyRepositoryError("There are no changesets yet") if revision in [-1, 'tip', None]: revision = 'tip' try: revision = hex(self._repo.lookup(revision)) except (LookupError, ): msg = ("Ambiguous identifier `%s` for %s" % (revision, self)) raise ChangesetDoesNotExistError(msg) except (IndexError, ValueError, RepoLookupError, TypeError): msg = ("Revision %s does not exist for %s" % (revision, self)) raise ChangesetDoesNotExistError(msg) return revision
def _get_bookmarks(self): if self._empty: return {} sortkey = lambda ctx: ctx[0] # sort by name _bookmarks = [(safe_unicode(n), hex(h),) for n, h in self._repo._bookmarks.items()] return OrderedDict(sorted(_bookmarks, key=sortkey, reverse=True))
def precursors(self): precursors = set() nm = self._ctx._repo.changelog.nodemap for p in self._ctx._repo.obsstore.precursors.get(self._ctx.node(), ()): pr = nm.get(p[0]) if pr is not None: precursors.add(hex(p[0])[:12]) return precursors
def successors(self): successors = obsolete.successorssets(self._ctx._repo, self._ctx.node()) if successors: # flatten the list here handles both divergent (len > 1) # and the usual case (len = 1) successors = [hex(n)[:12] for sub in successors for n in sub if n != self._ctx.node()] return successors
def _get_bookmarks(self): if self._empty: return {} sortkey = lambda ctx: ctx[0] # sort by name _bookmarks = [( safe_unicode(n), hex(h), ) for n, h in self._repo._bookmarks.items()] return OrderedDict(sorted(_bookmarks, key=sortkey, reverse=True))
def get_file_annotate(self, path): """ Returns a generator of four element tuples with lineno, sha, changeset lazy loader and line """ fctx = self._get_filectx(path) for i, annotate_data in enumerate(fctx.annotate()): ln_no = i + 1 sha = hex(annotate_data[0].node()) yield (ln_no, sha, lambda: self.repository.get_changeset(sha), annotate_data[1],)
def get_file_annotate(self, path): """ Returns a generator of four element tuples with lineno, sha, changeset lazy loader and line """ fctx = self._get_filectx(path) for i, annotate_data in enumerate(fctx.annotate(linenumber=False)): ln_no = i + 1 sha = hex(annotate_data[0][0].node()) yield (ln_no, sha, lambda: self.repository.get_changeset(sha), annotate_data[1],)
def _get_branches(self, normal=True, closed=False): """ Gets branches for this repository Returns only not closed branches by default :param closed: return also closed branches for mercurial :param normal: return also normal branches """ if self._empty: return {} bt = OrderedDict() for bn, _heads, tip, isclosed in sorted(self._repo.branchmap().iterbranches()): if isclosed: if closed: bt[safe_unicode(bn)] = hex(tip) else: if normal: bt[safe_unicode(bn)] = hex(tip) return bt
def _get_branches(self, normal=True, closed=False): """ Gets branches for this repository Returns only not closed branches by default :param closed: return also closed branches for mercurial :param normal: return also normal branches """ if self._empty: return {} bt = OrderedDict() for bn, _heads, tip, isclosed in sorted( self._repo.branchmap().iterbranches()): if isclosed: if closed: bt[safe_unicode(bn)] = hex(tip) else: if normal: bt[safe_unicode(bn)] = hex(tip) return bt
def get_file_history(self, path, limit=None): """ Returns history of file as reversed list of ``Changeset`` objects for which file at given ``path`` has been modified. """ fctx = self._get_filectx(path) hist = [] cnt = 0 for cs in reversed([x for x in fctx.filelog()]): cnt += 1 hist.append(hex(fctx.filectx(cs).node())) if limit and cnt == limit: break return [self.repository.get_changeset(node) for node in hist]
def get_file_history(self, path, limit=None): """ Returns history of file as reversed list of ``Changeset`` objects for which file at given ``path`` has been modified. """ fctx = self._get_filectx(path) hist = [] cnt = 0 for cs in reversed([x for x in fctx.filelog()]): cnt += 1 hist.append(hex(fctx.filectx(cs).node())) if limit is not None and cnt == limit: break return [self.repository.get_changeset(node) for node in hist]
def commit(self, message, author, parents=None, branch=None, date=None, **kwargs): """ Performs in-memory commit (doesn't check workdir in any way) and returns newly created ``Changeset``. Updates repository's ``revisions``. :param message: message of the commit :param author: full username, i.e. "Joe Doe <*****@*****.**>" :param parents: single parent or sequence of parents from which commit would be derived :param date: ``datetime.datetime`` instance. Defaults to ``datetime.datetime.now()``. :param branch: branch name, as string. If none given, default backend's branch would be used. :raises ``CommitError``: if any error occurs while committing """ self.check_integrity(parents) from .repository import MercurialRepository if not isinstance(message, unicode) or not isinstance(author, unicode): raise RepositoryError('Given message and author needs to be ' 'an <unicode> instance got %r & %r instead' % (type(message), type(author))) if branch is None: branch = MercurialRepository.DEFAULT_BRANCH_NAME kwargs['branch'] = branch def filectxfn(_repo, memctx, path): """ Marks given path as added/changed/removed in a given _repo. This is for internal mercurial commit function. """ # check if this path is removed if path in (node.path for node in self.removed): if getattr(memctx, '_returnnoneformissingfiles', False): return None else: # (hg < 3.2) Raising exception is the way to mark node for # removal raise IOError(errno.ENOENT, '%s is deleted' % path) # check if this path is added for node in self.added: if node.path == path: return memfilectx(_repo, path=node.path, data=(node.content.encode('utf8') if not node.is_binary else node.content), islink=False, isexec=node.is_executable, copied=False) # or changed for node in self.changed: if node.path == path: return memfilectx(_repo, path=node.path, data=(node.content.encode('utf8') if not node.is_binary else node.content), islink=False, isexec=node.is_executable, copied=False) raise RepositoryError("Given path haven't been marked as added," "changed or removed (%s)" % path) parents = [None, None] for i, parent in enumerate(self.parents): if parent is not None: parents[i] = parent._ctx.node() if date and isinstance(date, datetime.datetime): date = date.ctime() commit_ctx = memctx(repo=self.repository._repo, parents=parents, text='', files=self.get_paths(), filectxfn=filectxfn, user=author, date=date, extra=kwargs) loc = lambda u: tolocal(u.encode('utf-8')) # injecting given _repo params commit_ctx._text = loc(message) commit_ctx._user = loc(author) commit_ctx._date = date # TODO: Catch exceptions! n = self.repository._repo.commitctx(commit_ctx) # Returns mercurial node self._commit_ctx = commit_ctx # For reference # Update vcs repository object & recreate mercurial _repo # new_ctx = self.repository._repo[node] # new_tip = self.repository.get_changeset(new_ctx.hex()) new_id = hex(n) self.repository.revisions.append(new_id) self._repo = self.repository._get_repo(create=False) self.repository.branches = self.repository._get_branches() tip = self.repository.get_changeset() self.reset() return tip
def _get_all_revisions(self): return map(lambda x: hex(x[7]), self._repo.changelog.index)[:-1]
def commit(self, message, author, parents=None, branch=None, date=None, **kwargs): """ Performs in-memory commit (doesn't check workdir in any way) and returns newly created ``Changeset``. Updates repository's ``revisions``. :param message: message of the commit :param author: full username, i.e. "Joe Doe <*****@*****.**>" :param parents: single parent or sequence of parents from which commit would be derived :param date: ``datetime.datetime`` instance. Defaults to ``datetime.datetime.now()``. :param branch: branch name, as string. If none given, default backend's branch would be used. :raises ``CommitError``: if any error occurs while committing """ self.check_integrity(parents) from .repository import MercurialRepository if not isinstance(message, unicode) or not isinstance(author, unicode): raise RepositoryError('Given message and author needs to be ' 'an <unicode> instance got %r & %r instead' % (type(message), type(author))) if branch is None: branch = MercurialRepository.DEFAULT_BRANCH_NAME kwargs['branch'] = branch def filectxfn(_repo, memctx, path): """ Marks given path as added/changed/removed in a given _repo. This is for internal mercurial commit function. """ # check if this path is removed if path in (node.path for node in self.removed): if getattr(memctx, '_returnnoneformissingfiles', False): return None else: # (hg < 3.2) Raising exception is the way to mark node for # removal raise IOError(errno.ENOENT, '%s is deleted' % path) # check if this path is added for node in self.added: if node.path == path: return memfilectx( _repo, path=node.path, data=(node.content.encode('utf8') if not node.is_binary else node.content), islink=False, isexec=node.is_executable, copied=False) # or changed for node in self.changed: if node.path == path: return memfilectx( _repo, path=node.path, data=(node.content.encode('utf8') if not node.is_binary else node.content), islink=False, isexec=node.is_executable, copied=False) raise RepositoryError("Given path haven't been marked as added," "changed or removed (%s)" % path) parents = [None, None] for i, parent in enumerate(self.parents): if parent is not None: parents[i] = parent._ctx.node() if date and isinstance(date, datetime.datetime): date = date.strftime('%a, %d %b %Y %H:%M:%S') commit_ctx = memctx(repo=self.repository._repo, parents=parents, text='', files=self.get_paths(), filectxfn=filectxfn, user=author, date=date, extra=kwargs) loc = lambda u: tolocal(u.encode('utf-8')) # injecting given _repo params commit_ctx._text = loc(message) commit_ctx._user = loc(author) commit_ctx._date = date # TODO: Catch exceptions! n = self.repository._repo.commitctx(commit_ctx) # Returns mercurial node self._commit_ctx = commit_ctx # For reference # Update vcs repository object & recreate mercurial _repo # new_ctx = self.repository._repo[node] # new_tip = self.repository.get_changeset(new_ctx.hex()) new_id = hex(n) self.repository.revisions.append(new_id) self._repo = self.repository._get_repo(create=False) self.repository.branches = self.repository._get_branches() tip = self.repository.get_changeset() self.reset() return tip