Пример #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:
             self._check_url(src_url)
             self.clone(src_url, update_after_clone, bare)
             return Repo(self.path)
         elif create:
             os.mkdir(self.path)
             if bare:
                 return Repo.init_bare(self.path)
             else:
                 return Repo.init(self.path)
         else:
             return Repo(self.path)
     except (NotGitRepository, OSError), err:
         raise RepositoryError(err)
Пример #2
0
    def _local_merge(self, merge_message, user_name, user_email, heads):
        """
        Merge the given head into the checked out branch.

        It will force a merge commit.

        Currently it raises an error if the repo is empty, as it is not possible
        to create a merge commit in an empty repo.

        :param merge_message: The message to use for the merge commit.
        :param heads: the heads to merge.
        """
        if self.bare:
            raise RepositoryError('Cannot merge into a bare git repository')

        if not heads:
            return

        if self.is_empty():
            # TODO(skreft): do somehting more robust in this case.
            raise RepositoryError(
                'Do not know how to merge into empty repositories yet')

        # N.B.(skreft): the --no-ff option is used to enforce the creation of a
        # commit message. We also specify the user who is doing the merge.
        cmd = ['-c', 'user.name=%s' % safe_str(user_name),
               '-c', 'user.email=%s' % safe_str(user_email),
               'merge', '--no-ff', '-m', safe_str(merge_message)]
        cmd.extend(heads)
        try:
            self.run_git_command(cmd, fail_on_stderr=False)
        except RepositoryError:
            # Cleanup any merge leftovers
            self.run_git_command(['merge', '--abort'], fail_on_stderr=False)
            raise
Пример #3
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")
Пример #4
0
def get_commit_from_ref_name(repo, ref_name, ref_type=None):
    """
    Gets the commit for a `ref_name` taking into account `ref_type`.
    Needed in case a bookmark / tag share the same name.

    :param repo: the repo instance
    :param ref_name: the name of the ref to get
    :param ref_type: optional, used to disambiguate colliding refs
    """
    repo_scm = repo.scm_instance()
    ref_type_mapping = {
        'book': repo_scm.bookmarks,
        'bookmark': repo_scm.bookmarks,
        'tag': repo_scm.tags,
        'branch': repo_scm.branches,
    }

    commit_id = ref_name
    if repo_scm.alias != 'svn':  # pass svn refs straight to backend until
        # the branch issue with svn is fixed
        if ref_type and ref_type in ref_type_mapping:
            try:
                commit_id = ref_type_mapping[ref_type][ref_name]
            except KeyError:
                raise RepositoryError('%s "%s" does not exist' %
                                      (ref_type, ref_name))

    return repo_scm.get_commit(commit_id)
Пример #5
0
    def __init__(self, repository, revision):
        self._stat_modes = {}
        self.repository = repository

        try:
            commit = self.repository._repo.get_object(revision)
            if isinstance(commit, objects.Tag):
                revision = 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 = revision
        self.id = self.raw_id
        self.short_id = self.raw_id[:12]
        self._commit = commit

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

        self.message = safe_unicode(commit.message)

        self.nodes = {}
        self._paths = {}
Пример #6
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 = str(self._get_url(src_url))
                opts = {}
                if not update_after_clone:
                    opts.update({'noupdate': True})
                try:
                    self._check_url(url)
                    clone(self.baseui, url, self.path, **opts)
#                except urllib2.URLError:
#                    raise Abort("Got HTTP 404 error")
                except Exception:
                    raise
                # Don't try to create if we've already cloned repo
                create = False
            return localrepository(self.baseui, self.path, create=create)
        except (Abort, RepoError), 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)
Пример #7
0
    def index(self, revision):

        c.anchor_url = anchor_url
        c.ignorews_url = _ignorews_url
        c.context_url = _context_url
        limit_off = request.GET.get('fulldiff')
        #get ranges of revisions if preset
        rev_range = revision.split('...')[:2]
        enable_comments = True
        try:
            if len(rev_range) == 2:
                enable_comments = False
                rev_start = rev_range[0]
                rev_end = rev_range[1]
                rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
                                                             end=rev_end)
            else:
                rev_ranges = [c.rhodecode_repo.get_changeset(revision)]

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

        except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
            log.error(traceback.format_exc())
            h.flash(str(e), category='warning')
            return redirect(url('home'))
Пример #8
0
    def run_git_command(self, cmd):
        """
        Runs given ``cmd`` as git command and returns tuple
        (returncode, stdout, stderr).

        .. note::
           This method exists only until log/blame functionality is implemented
           at Dulwich (see https://bugs.launchpad.net/bugs/645142). Parsing
           os command's output is road to hell...

        :param cmd: git command to be executed
        """

        _copts = [
            '-c',
            'core.quotepath=false',
        ]
        _str_cmd = False
        if isinstance(cmd, basestring):
            cmd = [cmd]
            _str_cmd = True

        cmd = ['GIT_CONFIG_NOGLOBAL=1', 'git'] + _copts + cmd
        if _str_cmd:
            cmd = ' '.join(cmd)
        try:
            opts = dict(shell=isinstance(cmd, basestring),
                        stdout=PIPE,
                        stderr=PIPE)
            if os.path.isdir(self.path):
                opts['cwd'] = self.path
            p = Popen(cmd, **opts)
        except OSError, err:
            raise RepositoryError("Couldn't run git command (%s).\n"
                                  "Original error was:%s" % (cmd, err))
Пример #9
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):
                # 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)
Пример #10
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

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

        config = make_db_config()
        config.set('extensions', 'largefiles', '')
        repos = {}

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

            try:
                if name in repos:
                    raise RepositoryError('Duplicate repository name %s '
                                          'found in %s' % (name, path))
                elif path[0] in rhodecode.BACKENDS:
                    klass = get_backend(path[0])
                    repos[name] = klass(path[1], config=config)
            except OSError:
                continue
        log.debug('found %s paths with repositories', len(repos))
        return repos
Пример #11
0
    def _init_repo(self, create, src_url=None, update_after_clone=False):
        """
        Function will check for mercurial repository in given path. 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.

        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.
        """
        if create and os.path.exists(self.path):
            raise RepositoryError(
                "Cannot create repository at %s, location already exist" %
                self.path)

        if src_url:
            url = str(self._get_url(src_url))
            MercurialRepository.check_url(url, self.config)

            self._remote.clone(url, self.path, update_after_clone)

            # Don't try to create if we've already cloned repo
            create = False

        if create:
            os.makedirs(self.path, mode=0755)

        self._remote.localrepository(create)
Пример #12
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)
Пример #13
0
 def pull(self, url):
     """
     Tries to pull changes from external location.
     """
     url = self._get_url(url)
     try:
         pull(self.baseui, self._repo, url)
     except Abort, err:
         # Propagate error but with vcs's type
         raise RepositoryError(str(err))
Пример #14
0
    def test_raises_an_error_when_commit_not_found(self):
        repo = Mock()
        ref = 'branch:master:{}'.format(self.commit_hash)

        with patch(
                'rhodecode.api.utils.get_commit_from_ref_name') as get_commit:
            get_commit.side_effect = RepositoryError('Commit not found')
            with pytest.raises(JSONRPCError) as excinfo:
                utils.get_commit_or_error(ref, repo)
            expected_message = 'Ref `{}` does not exist'.format(ref)
            assert excinfo.value.message == expected_message
Пример #15
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
Пример #16
0
 def _local_pull(self, repository_path, branch_name):
     """
     Pull a branch from a local repository.
     """
     if self.bare:
         raise RepositoryError('Cannot pull into a bare git repository')
     # N.B.(skreft): The --ff-only option is to make sure this is a
     # fast-forward (i.e., we are only pulling new changes and there are no
     # conflicts with our current branch)
     # Additionally, that option needs to go before --no-tags, otherwise git
     # pull complains about it being an unknown flag.
     cmd = ['pull', '--ff-only', '--no-tags', repository_path, branch_name]
     self.run_git_command(cmd, fail_on_stderr=False)
Пример #17
0
    def _init_repo(self, create, src_url):
        if create and os.path.exists(self.path):
            raise RepositoryError(
                "Cannot create repository at %s, location already exist" %
                self.path)

        if create:
            self._remote.create_repository(settings.SVN_COMPATIBLE_VERSION)
            if src_url:
                src_url = _sanitize_url(src_url)
                self._remote.import_remote_repository(src_url)
        else:
            self._check_path()
Пример #18
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
        self.sa.add(repo)
        return repo
Пример #19
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

        _str_cmd = False
        if isinstance(cmd, basestring):
            cmd = [cmd]
            _str_cmd = True

        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
        if _str_cmd:
            cmd = ' '.join(cmd)

        try:
            _opts = dict(
                env=gitenv,
                shell=True,
            )
            _opts.update(opts)
            p = subprocessio.SubprocessIOChunker(cmd, **_opts)
        except (EnvironmentError, OSError), 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)
Пример #20
0
    def _init_repo(self, create, src_url=None, update_after_clone=False,
                   bare=False):
        if create and os.path.exists(self.path):
            raise RepositoryError(
                "Cannot create repository at %s, location already exist"
                % self.path)

        try:
            if create and src_url:
                GitRepository.check_url(src_url, self.config)
                self.clone(src_url, update_after_clone, bare)
            elif create:
                os.makedirs(self.path, mode=0755)

                if bare:
                    self._remote.init_bare()
                else:
                    self._remote.init()
            else:
                self._remote.assert_correct_path()
        # TODO: johbo: check if we have to translate the OSError here
        except OSError as err:
            raise RepositoryError(err)
Пример #21
0
    def get_commits(self,
                    start_id=None,
                    end_id=None,
                    start_date=None,
                    end_date=None,
                    branch_name=None,
                    pre_load=None):
        if self.is_empty():
            raise EmptyRepositoryError("There are no commit_ids yet")
        self._validate_branch_name(branch_name)

        if start_id is not None:
            self._validate_commit_id(start_id)
        if end_id is not None:
            self._validate_commit_id(end_id)

        start_raw_id = self._sanitize_commit_id(start_id)
        start_pos = self.commit_ids.index(start_raw_id) if start_id else None
        end_raw_id = self._sanitize_commit_id(end_id)
        end_pos = max(0, self.commit_ids.index(end_raw_id)) if end_id else None

        if None not in [start_id, end_id] and start_pos > end_pos:
            raise RepositoryError(
                "Start commit '%s' cannot be after end commit '%s'" %
                (start_id, end_id))
        if end_pos is not None:
            end_pos += 1

        # Date based filtering
        if start_date or end_date:
            start_raw_id, end_raw_id = self._remote.lookup_interval(
                date_astimestamp(start_date) if start_date else None,
                date_astimestamp(end_date) if end_date else None)
            start_pos = start_raw_id - 1
            end_pos = end_raw_id

        commit_ids = self.commit_ids

        # TODO: johbo: Reconsider impact of DEFAULT_BRANCH_NAME here
        if branch_name not in [None, self.DEFAULT_BRANCH_NAME]:
            svn_rev = long(self.commit_ids[-1])
            commit_ids = self._remote.node_history(path=branch_name,
                                                   revision=svn_rev,
                                                   limit=None)
            commit_ids = [str(i) for i in reversed(commit_ids)]

        if start_pos or end_pos:
            commit_ids = commit_ids[start_pos:end_pos]
        return base.CollectionGenerator(self, commit_ids, pre_load=pre_load)
Пример #22
0
    def _current_branch(self):
        """
        Return the name of the current branch.

        It only works for non bare repositories (i.e. repositories with a
        working copy)
        """
        if self.bare:
            raise RepositoryError('Bare git repos do not have active branches')

        if self.is_empty():
            return None

        stdout, _ = self.run_git_command(['rev-parse', '--abbrev-ref', 'HEAD'])
        return stdout.strip()
    def test_merge_raises_exception(self, vcsbackend):
        self.prepare_for_success(vcsbackend)
        expected_merge_response = MergeResponse(False, False, None,
                                                MergeFailureReason.UNKNOWN)

        with mock.patch.object(self.target_repo,
                               '_merge_repo',
                               side_effect=RepositoryError()):
            merge_response = self.target_repo.merge(self.target_ref,
                                                    self.source_repo,
                                                    self.source_ref,
                                                    self.workspace,
                                                    dry_run=True)

        assert merge_response == expected_merge_response
Пример #24
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():
            raise BranchDoesNotExistError('Branch %s not found in'
                                          ' this repository' % branch_name)
        if end_pos is not None:
            end_pos += 1

        slice_ = reversed(self.revisions[start_pos:end_pos]) if reverse else \
            self.revisions[start_pos:end_pos]

        for id_ in slice_:
            cs = self.get_changeset(id_)
            if branch_name and cs.branch != branch_name:
                continue
            if start_date and cs.date < start_date:
                continue
            if end_date and cs.date > end_date:
                continue

            yield cs
Пример #25
0
    def __get_filenode_or_redirect(self, repo_name, cs, path):
        """
        Returns file_node, if error occurs or given path is directory,
        it'll redirect to top level path

        :param repo_name: repo_name
        :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 RepositoryError, e:
            h.flash(str(e), category='error')
            raise HTTPNotFound()
    def test_merge_can_be_rejected_by_pre_push_hook(self, pr_util, user_admin,
                                                    capture_rcextensions,
                                                    merge_extras):
        pull_request = pr_util.create_pull_request(approved=True,
                                                   mergeable=True)
        # TODO: johbo: Needed for sqlite, try to find an automatic way for it
        Session().commit()

        with mock.patch('rhodecode.EXTENSIONS.PRE_PUSH_HOOK') as pre_pull:
            pre_pull.side_effect = RepositoryError("Disallow push!")
            merge_status = PullRequestModel().merge(pull_request,
                                                    user_admin,
                                                    extras=merge_extras)

        assert not merge_status.executed
        assert 'pre_push' not in capture_rcextensions
        assert 'post_push' not in capture_rcextensions
Пример #27
0
    def __get_filenode_or_redirect(self, repo_name, cs, path):
        """
        Returns file_node, if error occurs or given path is directory,
        it'll redirect to top level path

        :param repo_name: repo_name
        :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 RepositoryError, e:
            h.flash(str(e), category='warning')
            redirect(
                h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
Пример #28
0
    def _checkout(self, branch_name, create=False):
        """
        Checkout a branch in the working directory.

        It tries to create the branch if create is True, failing if the branch
        already exists.

        It only works for non bare repositories (i.e. repositories with a
        working copy)
        """
        if self.bare:
            raise RepositoryError('Cannot checkout branches in a bare git repo')

        cmd = ['checkout']
        if create:
            cmd.append('-b')
        cmd.append(branch_name)
        self.run_git_command(cmd, fail_on_stderr=False)
Пример #29
0
    def get_commit(self, commit_id=None, commit_idx=None, pre_load=None):
        """
        Returns `GitCommit` object representing commit from git repository
        at the given `commit_id` or head (most recent commit) if None given.
        """
        if commit_id is not None:
            self._validate_commit_id(commit_id)
        elif commit_idx is not None:
            self._validate_commit_idx(commit_idx)
            commit_id = commit_idx
        commit_id = self._get_commit_id(commit_id)
        try:
            # Need to call remote to translate id for tagging scenario
            commit_id = self._remote.get_object(commit_id)["commit_id"]
            idx = self._commit_ids[commit_id]
        except KeyError:
            raise RepositoryError("Cannot get object with id %s" % commit_id)

        return GitCommit(self, commit_id, idx, pre_load=pre_load)
Пример #30
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.tags = self._get_tags()
        except OSError, e:
            raise RepositoryError(e.strerror)