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_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_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_revision(self, revision): """ Get's an ID revision given as str. This will always return a fill 40 char revision number :param revision: str or int or None """ 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): raise ChangesetDoesNotExistError("Revision %s does not " "exist for this repository" % (revision)) return revision
def _get_branches(self, closed=False): """ Get's branches for this repository Returns only not closed branches by default :param closed: return also closed branches for mercurial """ if self._empty: return {} def _branchtags(localrepo): """ Patched version of mercurial branchtags to not return the closed branches :param localrepo: locarepository instance """ bt = {} bt_closed = {} for bn, heads in localrepo.branchmap().iteritems(): tip = heads[-1] if 'close' in localrepo.changelog.read(tip)[5]: bt_closed[bn] = tip else: bt[bn] = tip if closed: bt.update(bt_closed) return bt sortkey = lambda ctx: ctx[0] # sort by name _branches = [( safe_unicode(n), hex(h), ) for n, h in _branchtags(self._repo).items()] return OrderedDict(sorted(_branches, key=sortkey, reverse=False))
def _get_branches(self, closed=False): """ Get's branches for this repository Returns only not closed branches by default :param closed: return also closed branches for mercurial """ if self._empty: return {} def _branchtags(localrepo): """ Patched version of mercurial branchtags to not return the closed branches :param localrepo: locarepository instance """ bt = {} bt_closed = {} for bn, heads in localrepo.branchmap().iteritems(): tip = heads[-1] if 'close' in localrepo.changelog.read(tip)[5]: bt_closed[bn] = tip else: bt[bn] = tip if closed: bt.update(bt_closed) return bt sortkey = lambda ctx: ctx[0] # sort by name _branches = [(safe_unicode(n), hex(h),) for n, h in _branchtags(self._repo).items()] return OrderedDict(sorted(_branches, key=sortkey, reverse=False))
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 derieved :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): # Raising exception is a 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(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(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 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 derieved :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): # Raising exception is a 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( 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( 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