Esempio n. 1
0
 def _get_repo(self,
               create,
               src_url=None,
               update_after_clone=False,
               bare=False):
     if create and os.path.exists(self.path):
         raise RepositoryError("Location already exist")
     if src_url and not create:
         raise RepositoryError("Create should be set to True if src_url is "
                               "given (clone operation creates repository)")
     try:
         if create and src_url:
             GitRepository._check_url(src_url)
             self.clone(src_url, update_after_clone, bare)
             return Repo(self.path)
         elif create:
             os.makedirs(self.path)
             if bare:
                 return Repo.init_bare(self.path)
             else:
                 return Repo.init(self.path)
         else:
             return Repo(self.path)
     except (NotGitRepository, OSError) as err:
         raise RepositoryError(err)
Esempio n. 2
0
 def get_branch(self):
     headpath = self.repository._repo.refs.refpath('HEAD')
     try:
         content = open(headpath).read()
         match = re.match(r'^ref: refs/heads/(?P<branch>.+)\n$', content)
         if match:
             return match.groupdict()['branch']
         else:
             raise RepositoryError("Couldn't compute workdir's branch")
     except IOError:
         # Try naive way...
         raise RepositoryError("Couldn't compute workdir's branch")
Esempio n. 3
0
    def _index(self, revision, method):
        c.anchor_url = anchor_url
        c.ignorews_url = _ignorews_url
        c.context_url = _context_url
        c.fulldiff = fulldiff = request.GET.get('fulldiff')
        #get ranges of revisions if preset
        rev_range = revision.split('...')[:2]
        enable_comments = True
        c.cs_repo = c.db_repo
        try:
            if len(rev_range) == 2:
                enable_comments = False
                rev_start = rev_range[0]
                rev_end = rev_range[1]
                rev_ranges = c.db_repo_scm_instance.get_changesets(
                    start=rev_start, end=rev_end)
            else:
                rev_ranges = [c.db_repo_scm_instance.get_changeset(revision)]

            c.cs_ranges = list(rev_ranges)
            if not c.cs_ranges:
                raise RepositoryError('Changeset range returned empty result')

        except (ChangesetDoesNotExistError, ), e:
            log.error(traceback.format_exc())
            msg = _('Such revision does not exist for this repository')
            h.flash(msg, category='error')
            raise HTTPNotFound()
Esempio n. 4
0
    def tag(self,
            name,
            user,
            revision=None,
            message=None,
            date=None,
            **kwargs):
        """
        Creates and returns a tag for the given ``revision``.

        :param name: name for new tag
        :param user: full username, i.e.: "Joe Doe <*****@*****.**>"
        :param revision: changeset id for which new tag would be created
        :param message: message of the tag's commit
        :param date: date of tag's commit

        :raises TagAlreadyExistError: if tag with same name already exists
        """
        if name in self.tags:
            raise TagAlreadyExistError("Tag %s already exists" % name)
        changeset = self.get_changeset(revision)
        local = kwargs.setdefault('local', False)

        if message is None:
            message = "Added tag %s for changeset %s" % (name,
                                                         changeset.short_id)

        if date is None:
            date = datetime.datetime.now().ctime()

        try:
            self._repo.tag(name, changeset._ctx.node(), message, local, user,
                           date)
        except Abort, e:
            raise RepositoryError(e.message)
Esempio n. 5
0
    def get_changesets(self,
                       start=None,
                       end=None,
                       start_date=None,
                       end_date=None,
                       branch_name=None,
                       reverse=False,
                       max_revisions=None):
        """
        Returns iterator of ``MercurialChangeset`` objects from start to end
        (both are inclusive)

        :param start: None, str, int or mercurial lookup format
        :param end:  None, str, int or mercurial lookup format
        :param start_date:
        :param end_date:
        :param branch_name:
        :param reversed: return changesets in reversed order
        """
        start_raw_id = self._get_revision(start)
        start_pos = None if start is None else self.revisions.index(
            start_raw_id)
        end_raw_id = self._get_revision(end)
        end_pos = None if end is None else self.revisions.index(end_raw_id)

        if start_pos is not None and end_pos is not None and start_pos > end_pos:
            raise RepositoryError("Start revision '%s' cannot be "
                                  "after end revision '%s'" % (start, end))

        if branch_name and branch_name not in self.allbranches:
            msg = "Branch %r not found in %s" % (branch_name, self.name)
            raise BranchDoesNotExistError(msg)
        if end_pos is not None:
            end_pos += 1
        # filter branches
        filter_ = []
        if branch_name:
            filter_.append(b'branch("%s")' % safe_bytes(branch_name))
        if start_date:
            filter_.append(b'date(">%s")' % safe_bytes(str(start_date)))
        if end_date:
            filter_.append(b'date("<%s")' % safe_bytes(str(end_date)))
        if filter_ or max_revisions:
            if filter_:
                revspec = b' and '.join(filter_)
            else:
                revspec = b'all()'
            if max_revisions:
                revspec = b'limit(%s, %d)' % (revspec, max_revisions)
            revisions = mercurial.scmutil.revrange(self._repo, [revspec])
        else:
            revisions = self.revisions

        # this is very much a hack to turn this into a list; a better solution
        # would be to get rid of this function entirely and use revsets
        revs = list(revisions)[start_pos:end_pos]
        if reverse:
            revs.reverse()

        return CollectionGenerator(self, revs)
Esempio n. 6
0
    def remove_tag(self, name, user, message=None, date=None):
        """
        Removes tag with the given ``name``.

        :param name: name of the tag to be removed
        :param user: full username, i.e.: "Joe Doe <*****@*****.**>"
        :param message: message of the tag's removal commit
        :param date: date of tag's removal commit

        :raises TagDoesNotExistError: if tag with given name does not exists
        """
        if name not in self.tags:
            raise TagDoesNotExistError("Tag %s does not exist" % name)
        if message is None:
            message = "Removed tag %s" % name
        if date is None:
            date = safe_bytes(
                datetime.datetime.now().strftime('%a, %d %b %Y %H:%M:%S'))
        local = False

        try:
            mercurial.tags.tag(self._repo,
                               safe_bytes(name), mercurial.commands.nullid,
                               safe_bytes(message), local, safe_bytes(user),
                               date)
            self.tags = self._get_tags()
        except mercurial.error.Abort as e:
            raise RepositoryError(e.args[0])
Esempio n. 7
0
    def _get_repo(self, create, src_url=None, update_after_clone=False):
        """
        Function will check for mercurial repository in given path and return
        a localrepo object. If there is no repository in that path it will
        raise an exception unless ``create`` parameter is set to True - in
        that case repository would be created and returned.
        If ``src_url`` is given, would try to clone repository from the
        location at given clone_point. Additionally it'll make update to
        working copy accordingly to ``update_after_clone`` flag
        """

        try:
            if src_url:
                url = safe_str(self._get_url(src_url))
                opts = {}
                if not update_after_clone:
                    opts.update({'noupdate': True})
                MercurialRepository._check_url(url, self.baseui)
                clone(self.baseui, url, self.path, **opts)

                # Don't try to create if we've already cloned repo
                create = False
            return localrepository(self.baseui, self.path, create=create)
        except (Abort, RepoError) as err:
            if create:
                msg = "Cannot create repository at %s. Original error was %s" \
                    % (self.path, err)
            else:
                msg = "Not valid repository at %s. Original error was %s" \
                    % (self.path, err)
            raise RepositoryError(msg)
Esempio n. 8
0
    def get_changesets(self,
                       start=None,
                       end=None,
                       start_date=None,
                       end_date=None,
                       branch_name=None,
                       reverse=False):
        """
        Returns iterator of ``MercurialChangeset`` objects from start to end
        (both are inclusive)

        :param start: None, str, int or mercurial lookup format
        :param end:  None, str, int or mercurial lookup format
        :param start_date:
        :param end_date:
        :param branch_name:
        :param reversed: return changesets in reversed order
        """

        start_raw_id = self._get_revision(start)
        start_pos = self.revisions.index(start_raw_id) if start else None
        end_raw_id = self._get_revision(end)
        end_pos = self.revisions.index(end_raw_id) if end else None

        if None not in [start, end] and start_pos > end_pos:
            raise RepositoryError("Start revision '%s' cannot be "
                                  "after end revision '%s'" % (start, end))

        if branch_name and branch_name not in self.allbranches.keys():
            msg = ("Branch %s not found in %s" % (branch_name, self))
            raise BranchDoesNotExistError(msg)
        if end_pos is not None:
            end_pos += 1
        #filter branches
        filter_ = []
        if branch_name:
            filter_.append('branch("%s")' % (branch_name))

        if start_date and not end_date:
            filter_.append('date(">%s")' % start_date)
        if end_date and not start_date:
            filter_.append('date("<%s")' % end_date)
        if start_date and end_date:
            filter_.append('date(">%s") and date("<%s")' %
                           (start_date, end_date))
        if filter_:
            revisions = scmutil.revrange(self._repo, filter_)
        else:
            revisions = self.revisions

        # this is very much a hack to turn this into a list; a better solution
        # would be to get rid of this function entirely and use revsets
        revs = list(revisions)[start_pos:end_pos]
        if reverse:
            revs = reversed(revs)

        return CollectionGenerator(self, revs)
Esempio n. 9
0
 def get_tree_for_dir(tree, dirname):
     for name, mode, id in tree.iteritems():
         if name == dirname:
             obj = self.repository._repo[id]
             if isinstance(obj, objects.Tree):
                 return obj
             else:
                 raise RepositoryError("Cannot create directory %s "
                 "at tree %s as path is occupied and is not a "
                 "Tree" % (dirname, tree))
     return None
Esempio n. 10
0
    def mark_as_fork(self, repo, fork, user):
        repo = self.__get_repo(repo)
        fork = self.__get_repo(fork)
        if fork and repo.repo_id == fork.repo_id:
            raise Exception("Cannot set repository as fork of itself")

        if fork and repo.repo_type != fork.repo_type:
            raise RepositoryError("Cannot set repository as fork of repository with other type")

        repo.fork = fork
        return repo
Esempio n. 11
0
 def pull(self, url):
     """
     Tries to pull changes from external location.
     """
     other = mercurial.hg.peer(self._repo, {},
                               safe_bytes(self._get_url(url)))
     try:
         mercurial.exchange.pull(self._repo, other, heads=None, force=None)
     except mercurial.error.Abort as err:
         # Propagate error but with vcs's type
         raise RepositoryError(str(err))
Esempio n. 12
0
    def _run_git_command(cls, cmd, **opts):
        """
        Runs given ``cmd`` as git command and returns tuple
        (stdout, stderr).

        :param cmd: git command to be executed
        :param opts: env options to pass into Subprocess command
        """

        if '_bare' in opts:
            _copts = []
            del opts['_bare']
        else:
            _copts = [
                '-c',
                'core.quotepath=false',
            ]
        safe_call = False
        if '_safe' in opts:
            #no exc on failure
            del opts['_safe']
            safe_call = True

        assert isinstance(cmd, list), cmd

        gitenv = os.environ
        # need to clean fix GIT_DIR !
        if 'GIT_DIR' in gitenv:
            del gitenv['GIT_DIR']
        gitenv['GIT_CONFIG_NOGLOBAL'] = '1'

        _git_path = settings.GIT_EXECUTABLE_PATH
        cmd = [_git_path] + _copts + cmd

        try:
            _opts = dict(
                env=gitenv,
                shell=False,
            )
            _opts.update(opts)
            p = subprocessio.SubprocessIOChunker(cmd, **_opts)
        except (EnvironmentError, OSError) as err:
            tb_err = ("Couldn't run git command (%s).\n"
                      "Original error was:%s\n" % (cmd, err))
            log.error(tb_err)
            if safe_call:
                return '', err
            else:
                raise RepositoryError(tb_err)

        return ''.join(p.output), ''.join(p.error)
Esempio n. 13
0
 def pull(self, url):
     """
     Tries to pull changes from external location.
     """
     url = self._get_url(url)
     other = peer(self._repo, {}, url)
     try:
         # hg 3.2 moved push / pull to exchange module
         from mercurial import exchange
         exchange.pull(self._repo, other, heads=None, force=None)
     except ImportError:
         self._repo.pull(other, heads=None, force=None)
     except Abort as err:
         # Propagate error but with vcs's type
         raise RepositoryError(str(err))
Esempio n. 14
0
    def tag(self,
            name,
            user,
            revision=None,
            message=None,
            date=None,
            **kwargs):
        """
        Creates and returns a tag for the given ``revision``.

        :param name: name for new tag
        :param user: full username, i.e.: "Joe Doe <*****@*****.**>"
        :param revision: changeset id for which new tag would be created
        :param message: message of the tag's commit
        :param date: date of tag's commit

        :raises TagAlreadyExistError: if tag with same name already exists
        """
        if name in self.tags:
            raise TagAlreadyExistError("Tag %s already exists" % name)
        changeset = self.get_changeset(revision)
        local = kwargs.setdefault('local', False)

        if message is None:
            message = "Added tag %s for changeset %s" % (name,
                                                         changeset.short_id)

        if date is None:
            date = safe_bytes(
                datetime.datetime.now().strftime('%a, %d %b %Y %H:%M:%S'))

        try:
            mercurial.tags.tag(self._repo, safe_bytes(name),
                               changeset._ctx.node(), safe_bytes(message),
                               local, safe_bytes(user), date)
        except mercurial.error.Abort as e:
            raise RepositoryError(e.args[0])

        # Reinitialize tags
        self.tags = self._get_tags()
        tag_id = self.tags[name]

        return self.get_changeset(revision=tag_id)
Esempio n. 15
0
    def remove_tag(self, name, user, message=None, date=None):
        """
        Removes tag with the given ``name``.

        :param name: name of the tag to be removed
        :param user: full username, i.e.: "Joe Doe <*****@*****.**>"
        :param message: message of the tag's removal commit
        :param date: date of tag's removal commit

        :raises TagDoesNotExistError: if tag with given name does not exists
        """
        if name not in self.tags:
            raise TagDoesNotExistError("Tag %s does not exist" % name)
        tagpath = posixpath.join(self._repo.refs.path, 'refs', 'tags', name)
        try:
            os.remove(tagpath)
            self._parsed_refs = self._get_parsed_refs()
            self.tags = self._get_tags()
        except OSError as e:
            raise RepositoryError(e.strerror)
Esempio n. 16
0
        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)
Esempio n. 17
0
    def __get_filenode(self, cs, path):
        """
        Returns file_node or raise HTTP error.

        :param cs: given changeset
        :param path: path to lookup
        """

        try:
            file_node = cs.get_node(path)
            if file_node.is_dir():
                raise RepositoryError('given path is a directory')
        except ChangesetDoesNotExistError:
            msg = _('Such revision does not exist for this repository')
            h.flash(msg, category='error')
            raise HTTPNotFound()
        except RepositoryError as e:
            h.flash(e, category='error')
            raise HTTPNotFound()

        return file_node
Esempio n. 18
0
    def _run_git_command(cls, cmd, cwd=None):
        """
        Runs given ``cmd`` as git command and returns output bytes in a tuple
        (stdout, stderr) ... or raise RepositoryError.

        :param cmd: git command to be executed
        :param cwd: passed directly to subprocess
        """
        # need to clean fix GIT_DIR !
        gitenv = dict(os.environ)
        gitenv.pop('GIT_DIR', None)
        gitenv['GIT_CONFIG_NOGLOBAL'] = '1'

        assert isinstance(cmd, list), cmd
        cmd = [settings.GIT_EXECUTABLE_PATH, '-c', 'core.quotepath=false'
               ] + cmd
        try:
            p = subprocessio.SubprocessIOChunker(cmd,
                                                 cwd=cwd,
                                                 env=gitenv,
                                                 shell=False)
        except (EnvironmentError, OSError) as err:
            # output from the failing process is in str(EnvironmentError)
            msg = ("Couldn't run git command %s.\n"
                   "Subprocess failed with '%s': %s\n" %
                   (cmd, type(err).__name__, err)).strip()
            log.error(msg)
            raise RepositoryError(msg)

        try:
            stdout = b''.join(p.output)
            stderr = b''.join(p.error)
        finally:
            p.close()
        # TODO: introduce option to make commands fail if they have any stderr output?
        if stderr:
            log.debug('stderr from %s:\n%s', cmd, stderr)
        else:
            log.debug('stderr from %s: None', cmd)
        return stdout, stderr
Esempio n. 19
0
    def __init__(self, repository, revision):
        self._stat_modes = {}
        self.repository = repository
        try:
            commit = self.repository._repo[ascii_bytes(revision)]
            if isinstance(commit, objects.Tag):
                revision = safe_str(commit.object[1])
                commit = self.repository._repo.get_object(commit.object[1])
        except KeyError:
            raise RepositoryError("Cannot get object with id %s" % revision)
        self.raw_id = ascii_str(commit.id)
        self.short_id = self.raw_id[:12]
        self._commit = commit  # a Dulwich Commmit with .id
        self._tree_id = commit.tree
        self._committer_property = 'committer'
        self._author_property = 'author'
        self._date_property = 'commit_time'
        self._date_tz_property = 'commit_timezone'
        self.revision = repository.revisions.index(self.raw_id)

        self.nodes = {}
        self._paths = {}
Esempio n. 20
0
    def repo_scan(self, repos_path=None):
        """
        Listing of repositories in given path. This path should not be a
        repository itself. Return a dictionary of repository objects mapping to
        vcs instances.

        :param repos_path: path to directory containing repositories
        """

        if repos_path is None:
            repos_path = self.repos_path

        log.info('scanning for repositories in %s', repos_path)

        baseui = make_ui()
        repos = {}

        for name, path in get_filesystem_repos(repos_path):
            # name need to be decomposed and put back together using the /
            # since this is internal storage separator for kallithea
            name = Repository.normalize_repo_name(name)

            try:
                if name in repos:
                    raise RepositoryError('Duplicate repository name %s '
                                          'found in %s' % (name, path))
                else:

                    klass = get_backend(path[0])

                    if path[0] == 'hg' and path[0] in BACKENDS:
                        repos[name] = klass(path[1], baseui=baseui)

                    if path[0] == 'git' and path[0] in BACKENDS:
                        repos[name] = klass(path[1])
            except OSError:
                continue
        log.debug('found %s paths with repositories', len(repos))
        return repos
Esempio n. 21
0
        def filectxfn(_repo, memctx, bytes_path):
            """
            Callback from Mercurial, returning ctx to commit for the given
            path.
            """
            path = safe_str(bytes_path)

            # check if this path is removed
            if path in (node.path for node in self.removed):
                return None

            # check if this path is added
            for node in self.added:
                if node.path == path:
                    return mercurial.context.memfilectx(
                        _repo,
                        memctx,
                        path=bytes_path,
                        data=node.content,
                        islink=False,
                        isexec=node.is_executable,
                        copysource=False)

            # or changed
            for node in self.changed:
                if node.path == path:
                    return mercurial.context.memfilectx(
                        _repo,
                        memctx,
                        path=bytes_path,
                        data=node.content,
                        islink=False,
                        isexec=node.is_executable,
                        copysource=False)

            raise RepositoryError("Given path haven't been marked as added, "
                                  "changed or removed (%s)" % path)
Esempio n. 22
0
    def remove_tag(self, name, user, message=None, date=None):
        """
        Removes tag with the given ``name``.

        :param name: name of the tag to be removed
        :param user: full username, i.e.: "Joe Doe <*****@*****.**>"
        :param message: message of the tag's removal commit
        :param date: date of tag's removal commit

        :raises TagDoesNotExistError: if tag with given name does not exists
        """
        if name not in self.tags:
            raise TagDoesNotExistError("Tag %s does not exist" % name)
        if message is None:
            message = "Removed tag %s" % name
        if date is None:
            date = datetime.datetime.now().ctime()
        local = False

        try:
            self._repo.tag(name, nullid, message, local, user, date)
            self.tags = self._get_tags()
        except Abort, e:
            raise RepositoryError(e.message)
Esempio n. 23
0
    def _index(self, revision, method):
        c.pull_request = None
        c.anchor_url = anchor_url
        c.ignorews_url = _ignorews_url
        c.context_url = _context_url
        c.fulldiff = fulldiff = request.GET.get('fulldiff')
        #get ranges of revisions if preset
        rev_range = revision.split('...')[:2]
        enable_comments = True
        c.cs_repo = c.db_repo
        try:
            if len(rev_range) == 2:
                enable_comments = False
                rev_start = rev_range[0]
                rev_end = rev_range[1]
                rev_ranges = c.db_repo_scm_instance.get_changesets(start=rev_start,
                                                             end=rev_end)
            else:
                rev_ranges = [c.db_repo_scm_instance.get_changeset(revision)]

            c.cs_ranges = list(rev_ranges)
            if not c.cs_ranges:
                raise RepositoryError('Changeset range returned empty result')

        except (ChangesetDoesNotExistError, EmptyRepositoryError):
            log.debug(traceback.format_exc())
            msg = _('Such revision does not exist for this repository')
            h.flash(msg, category='error')
            raise HTTPNotFound()

        c.changes = OrderedDict()

        c.lines_added = 0  # count of lines added
        c.lines_deleted = 0  # count of lines removes

        c.changeset_statuses = ChangesetStatus.STATUSES
        comments = dict()
        c.statuses = []
        c.inline_comments = []
        c.inline_cnt = 0

        # Iterate over ranges (default changeset view is always one changeset)
        for changeset in c.cs_ranges:
            if method == 'show':
                c.statuses.extend([ChangesetStatusModel().get_status(
                            c.db_repo.repo_id, changeset.raw_id)])

                # Changeset comments
                comments.update((com.comment_id, com)
                                for com in ChangesetCommentsModel()
                                .get_comments(c.db_repo.repo_id,
                                              revision=changeset.raw_id))

                # Status change comments - mostly from pull requests
                comments.update((st.comment_id, st.comment)
                                for st in ChangesetStatusModel()
                                .get_statuses(c.db_repo.repo_id,
                                              changeset.raw_id, with_revisions=True)
                                if st.comment_id is not None)

                inlines = ChangesetCommentsModel() \
                            .get_inline_comments(c.db_repo.repo_id,
                                                 revision=changeset.raw_id)
                c.inline_comments.extend(inlines)

            cs2 = changeset.raw_id
            cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset().raw_id
            context_lcl = get_line_ctx('', request.GET)
            ign_whitespace_lcl = get_ignore_ws('', request.GET)

            _diff = c.db_repo_scm_instance.get_diff(cs1, cs2,
                ignore_whitespace=ign_whitespace_lcl, context=context_lcl)
            diff_limit = self.cut_off_limit if not fulldiff else None
            diff_processor = diffs.DiffProcessor(_diff,
                                                 vcs=c.db_repo_scm_instance.alias,
                                                 format='gitdiff',
                                                 diff_limit=diff_limit)
            file_diff_data = []
            if method == 'show':
                _parsed = diff_processor.prepare()
                c.limited_diff = False
                if isinstance(_parsed, LimitedDiffContainer):
                    c.limited_diff = True
                for f in _parsed:
                    st = f['stats']
                    c.lines_added += st['added']
                    c.lines_deleted += st['deleted']
                    filename = f['filename']
                    fid = h.FID(changeset.raw_id, filename)
                    url_fid = h.FID('', filename)
                    diff = diff_processor.as_html(enable_comments=enable_comments,
                                                  parsed_lines=[f])
                    file_diff_data.append((fid, url_fid, f['operation'], f['old_filename'], filename, diff, st))
            else:
                # downloads/raw we only need RAW diff nothing else
                diff = diff_processor.as_raw()
                file_diff_data.append(('', None, None, None, diff, None))
            c.changes[changeset.raw_id] = (cs1, cs2, file_diff_data)

        #sort comments in creation order
        c.comments = [com for com_id, com in sorted(comments.items())]

        # count inline comments
        for __, lines in c.inline_comments:
            for comments in lines.values():
                c.inline_cnt += len(comments)

        if len(c.cs_ranges) == 1:
            c.changeset = c.cs_ranges[0]
            c.parent_tmpl = ''.join(['# Parent  %s\n' % x.raw_id
                                     for x in c.changeset.parents])
        if method == 'download':
            response.content_type = 'text/plain'
            response.content_disposition = 'attachment; filename=%s.diff' \
                                            % revision[:12]
            return diff
        elif method == 'patch':
            response.content_type = 'text/plain'
            c.diff = safe_unicode(diff)
            return render('changeset/patch_changeset.html')
        elif method == 'raw':
            response.content_type = 'text/plain'
            return diff
        elif method == 'show':
            self.__load_data()
            if len(c.cs_ranges) == 1:
                return render('changeset/changeset.html')
            else:
                c.cs_ranges_org = None
                c.cs_comments = {}
                revs = [ctx.revision for ctx in reversed(c.cs_ranges)]
                c.jsdata = graph_data(c.db_repo_scm_instance, revs)
                return render('changeset/changeset_range.html')
Esempio n. 24
0
    def get_changesets(self,
                       start=None,
                       end=None,
                       start_date=None,
                       end_date=None,
                       branch_name=None,
                       reverse=False,
                       max_revisions=None):
        """
        Returns iterator of ``GitChangeset`` objects from start to end (both
        are inclusive), in ascending date order (unless ``reverse`` is set).

        :param start: changeset ID, as str; first returned changeset
        :param end: changeset ID, as str; last returned changeset
        :param start_date: if specified, changesets with commit date less than
          ``start_date`` would be filtered out from returned set
        :param end_date: if specified, changesets with commit date greater than
          ``end_date`` would be filtered out from returned set
        :param branch_name: if specified, changesets not reachable from given
          branch would be filtered out from returned set
        :param reverse: if ``True``, returned generator would be reversed
          (meaning that returned changesets would have descending date order)

        :raise BranchDoesNotExistError: If given ``branch_name`` does not
            exist.
        :raise ChangesetDoesNotExistError: If changeset for given ``start`` or
          ``end`` could not be found.

        """
        if branch_name and branch_name not in self.branches:
            raise BranchDoesNotExistError("Branch '%s' not found" %
                                          branch_name)
        # actually we should check now if it's not an empty repo to not spaw
        # subprocess commands
        if self._empty:
            raise EmptyRepositoryError("There are no changesets yet")

        # %H at format means (full) commit hash, initial hashes are retrieved
        # in ascending date order
        cmd = ['log', '--date-order', '--reverse', '--pretty=format:%H']
        if max_revisions:
            cmd += ['--max-count=%s' % max_revisions]
        if start_date:
            cmd += ['--since', start_date.strftime('%m/%d/%y %H:%M:%S')]
        if end_date:
            cmd += ['--until', end_date.strftime('%m/%d/%y %H:%M:%S')]
        if branch_name:
            cmd.append(branch_name)
        else:
            cmd.append(settings.GIT_REV_FILTER)

        revs = self.run_git_command(cmd).splitlines()
        start_pos = 0
        end_pos = len(revs)
        if start:
            _start = self._get_revision(start)
            try:
                start_pos = revs.index(_start)
            except ValueError:
                pass

        if end is not None:
            _end = self._get_revision(end)
            try:
                end_pos = revs.index(_end)
            except ValueError:
                pass

        if None not in [start, end] and start_pos > end_pos:
            raise RepositoryError('start cannot be after end')

        if end_pos is not None:
            end_pos += 1

        revs = revs[start_pos:end_pos]
        if reverse:
            revs.reverse()

        return CollectionGenerator(self, revs)
Esempio n. 25
0
    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)

        if not isinstance(message, str):
            raise RepositoryError('message must be a str - got %r' %
                                  type(message))
        if not isinstance(author, str):
            raise RepositoryError('author must be a str - got %r' %
                                  type(author))

        from .repository import MercurialRepository
        if branch is None:
            branch = MercurialRepository.DEFAULT_BRANCH_NAME
        kwargs[b'branch'] = safe_bytes(branch)

        def filectxfn(_repo, memctx, bytes_path):
            """
            Callback from Mercurial, returning ctx to commit for the given
            path.
            """
            path = safe_str(bytes_path)

            # check if this path is removed
            if path in (node.path for node in self.removed):
                return None

            # check if this path is added
            for node in self.added:
                if node.path == path:
                    return mercurial.context.memfilectx(
                        _repo,
                        memctx,
                        path=bytes_path,
                        data=node.content,
                        islink=False,
                        isexec=node.is_executable,
                        copysource=False)

            # or changed
            for node in self.changed:
                if node.path == path:
                    return mercurial.context.memfilectx(
                        _repo,
                        memctx,
                        path=bytes_path,
                        data=node.content,
                        islink=False,
                        isexec=node.is_executable,
                        copysource=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 = safe_bytes(date.strftime('%a, %d %b %Y %H:%M:%S'))

        commit_ctx = mercurial.context.memctx(
            repo=self.repository._repo,
            parents=parents,
            text=b'',
            files=[safe_bytes(x) for x in self.get_paths()],
            filectxfn=filectxfn,
            user=safe_bytes(author),
            date=date,
            extra=kwargs)

        # injecting given _repo params
        commit_ctx._text = safe_bytes(message)
        commit_ctx._user = safe_bytes(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 = ascii_str(self.repository.get_changeset(new_ctx.hex()))
        self.repository.revisions.append(ascii_str(mercurial.node.hex(n)))
        self._repo = self.repository._get_repo(create=False)
        self.repository.branches = self.repository._get_branches()
        tip = self.repository.get_changeset()
        self.reset()
        return tip
Esempio n. 26
0
    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