Exemplo n.º 1
0
    def _rpc_call(self, action, environ, **rpc_args):
        """
        Call the specified RPC Method
        """
        raw_response = ''
        try:
            raw_response = getattr(self, action)(**rpc_args)
            if isinstance(raw_response, HTTPError):
                self._error = str(raw_response)
        except JSONRPCError as e:
            self._error = safe_str(e)
        except Exception as e:
            log.error(
                'Encountered unhandled exception: %s',
                traceback.format_exc(),
            )
            json_exc = JSONRPCError('Internal server error')
            self._error = safe_str(json_exc)

        if self._error is not None:
            raw_response = None

        response = dict(id=self._req_id,
                        result=raw_response,
                        error=self._error)
        try:
            return json.dumps(response)
        except TypeError as e:
            log.error('API FAILED. Error encoding response: %s', e)
            return json.dumps(
                dict(id=self._req_id,
                     result=None,
                     error="Error encoding response"))
Exemplo n.º 2
0
    def _dispatch_call(self):
        """
        Implement dispatch interface specified by WSGIController
        """
        raw_response = ''
        try:
            raw_response = self._inspect_call(self._func)
            if isinstance(raw_response, HTTPError):
                self._error = str(raw_response)
        except JSONRPCError as e:
            self._error = safe_str(e)
        except Exception as e:
            log.error('Encountered unhandled exception: %s',
                      traceback.format_exc(),)
            json_exc = JSONRPCError('Internal server error')
            self._error = safe_str(json_exc)

        if self._error is not None:
            raw_response = None

        response = dict(id=self._req_id, result=raw_response, error=self._error)
        try:
            return json.dumps(response)
        except TypeError as e:
            log.error('API FAILED. Error encoding response: %s', e)
            return json.dumps(
                dict(
                    id=self._req_id,
                    result=None,
                    error="Error encoding response"
                )
            )
Exemplo n.º 3
0
    def _rpc_call(self, action, environ, **rpc_args):
        """
        Call the specified RPC Method
        """
        raw_response = ''
        try:
            raw_response = getattr(self, action)(**rpc_args)
            if isinstance(raw_response, HTTPError):
                self._error = str(raw_response)
        except JSONRPCError as e:
            self._error = safe_str(e)
        except Exception as e:
            log.error('Encountered unhandled exception: %s',
                      traceback.format_exc(),)
            json_exc = JSONRPCError('Internal server error')
            self._error = safe_str(json_exc)

        if self._error is not None:
            raw_response = None

        response = dict(id=self._req_id, result=raw_response, error=self._error)
        try:
            return json.dumps(response)
        except TypeError as e:
            log.error('API FAILED. Error encoding response: %s', e)
            return json.dumps(
                dict(
                    id=self._req_id,
                    result=None,
                    error="Error encoding response"
                )
            )
Exemplo n.º 4
0
    def statistics(self, repo_name):
        if c.db_repo.enable_statistics:
            c.show_stats = True
            c.no_data_msg = _('No data ready yet')
        else:
            c.show_stats = False
            c.no_data_msg = _('Statistics are disabled for this repository')

        td = date.today() + timedelta(days=1)
        td_1m = td - timedelta(days=calendar.mdays[td.month])
        td_1y = td - timedelta(days=365)

        ts_min_m = mktime(td_1m.timetuple())
        ts_min_y = mktime(td_1y.timetuple())
        ts_max_y = mktime(td.timetuple())
        c.ts_min = ts_min_m
        c.ts_max = ts_max_y

        stats = self.sa.query(Statistics) \
            .filter(Statistics.repository == c.db_repo) \
            .scalar()
        c.stats_percentage = 0
        if stats and stats.languages:
            c.no_data = False is c.db_repo.enable_statistics
            lang_stats_d = json.loads(stats.languages)
            c.commit_data = stats.commit_activity
            c.overview_data = stats.commit_activity_combined

            lang_stats = ((x, {"count": y,
                               "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
                          for x, y in lang_stats_d.items())

            c.trending_languages = json.dumps(
                sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
            )
            last_rev = stats.stat_on_revision + 1
            c.repo_last_rev = c.db_repo_scm_instance.count() \
                if c.db_repo_scm_instance.revisions else 0
            if last_rev == 0 or c.repo_last_rev == 0:
                pass
            else:
                c.stats_percentage = '%.2f' % ((float((last_rev)) /
                                                c.repo_last_rev) * 100)
        else:
            c.commit_data = json.dumps({})
            c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
            c.trending_languages = json.dumps({})
            c.no_data = True

        recurse_limit = 500  # don't recurse more than 500 times when parsing
        run_task(get_commits_stats, c.db_repo.repo_name, ts_min_y,
                 ts_max_y, recurse_limit)
        return render('summary/statistics.html')
Exemplo n.º 5
0
    def statistics(self, repo_name):
        if c.db_repo.enable_statistics:
            c.show_stats = True
            c.no_data_msg = _('No data ready yet')
        else:
            c.show_stats = False
            c.no_data_msg = _('Statistics are disabled for this repository')

        td = date.today() + timedelta(days=1)
        td_1m = td - timedelta(days=calendar.mdays[td.month])
        td_1y = td - timedelta(days=365)

        ts_min_m = mktime(td_1m.timetuple())
        ts_min_y = mktime(td_1y.timetuple())
        ts_max_y = mktime(td.timetuple())
        c.ts_min = ts_min_m
        c.ts_max = ts_max_y

        stats = self.sa.query(Statistics)\
            .filter(Statistics.repository == c.db_repo)\
            .scalar()
        if stats and stats.languages:
            c.no_data = False is c.db_repo.enable_statistics
            lang_stats_d = json.loads(stats.languages)
            c.commit_data = stats.commit_activity
            c.overview_data = stats.commit_activity_combined

            lang_stats = ((x, {
                "count": y,
                "desc": LANGUAGES_EXTENSIONS_MAP.get(x)
            }) for x, y in lang_stats_d.items())

            c.trending_languages = json.dumps(
                sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10])
            last_rev = stats.stat_on_revision + 1
            c.repo_last_rev = c.db_repo_scm_instance.count()\
                if c.db_repo_scm_instance.revisions else 0
            if last_rev == 0 or c.repo_last_rev == 0:
                pass
            else:
                c.stats_percentage = '%.2f' % ((float(
                    (last_rev)) / c.repo_last_rev) * 100)
        else:
            c.commit_data = json.dumps({})
            c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
            c.trending_languages = json.dumps({})
            c.no_data = True

        recurse_limit = 500  # don't recurse more than 500 times when parsing
        run_task(get_commits_stats, c.db_repo.repo_name, ts_min_y, ts_max_y,
                 recurse_limit)
        return render('summary/statistics.html')
Exemplo n.º 6
0
    def index(self, repo_name):
        _load_changelog_summary()

        username = ''
        if self.authuser.username != User.DEFAULT_USER:
            username = safe_str(self.authuser.username)

        _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
        if '{repo}' in _def_clone_uri:
            _def_clone_uri_by_id = _def_clone_uri.replace(
                '{repo}', '_{repoid}')
        elif '{repoid}' in _def_clone_uri:
            _def_clone_uri_by_id = _def_clone_uri.replace(
                '_{repoid}', '{repo}')

        c.clone_repo_url = c.db_repo.clone_url(user=username,
                                               uri_tmpl=_def_clone_uri)
        c.clone_repo_url_id = c.db_repo.clone_url(
            user=username, uri_tmpl=_def_clone_uri_by_id)

        if c.db_repo.enable_statistics:
            c.show_stats = True
        else:
            c.show_stats = False

        stats = self.sa.query(Statistics)\
            .filter(Statistics.repository == c.db_repo)\
            .scalar()

        c.stats_percentage = 0

        if stats and stats.languages:
            c.no_data = False is c.db_repo.enable_statistics
            lang_stats_d = json.loads(stats.languages)

            lang_stats = ((x, {
                "count": y,
                "desc": LANGUAGES_EXTENSIONS_MAP.get(x)
            }) for x, y in lang_stats_d.items())

            c.trending_languages = json.dumps(
                sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10])
        else:
            c.no_data = True
            c.trending_languages = json.dumps([])

        c.enable_downloads = c.db_repo.enable_downloads
        c.readme_data, c.readme_file = \
            self.__get_readme_data(c.db_repo)
        return render('summary/summary.html')
Exemplo n.º 7
0
    def index(self, repo_name):
        _load_changelog_summary()

        if self.authuser.is_default_user:
            username = ''
        else:
            username = safe_str(self.authuser.username)

        _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
        if '{repo}' in _def_clone_uri:
            _def_clone_uri_by_id = _def_clone_uri.replace('{repo}', '_{repoid}')
        elif '{repoid}' in _def_clone_uri:
            _def_clone_uri_by_id = _def_clone_uri.replace('_{repoid}', '{repo}')

        c.clone_repo_url = c.db_repo.clone_url(user=username,
                                                uri_tmpl=_def_clone_uri)
        c.clone_repo_url_id = c.db_repo.clone_url(user=username,
                                                uri_tmpl=_def_clone_uri_by_id)

        if c.db_repo.enable_statistics:
            c.show_stats = True
        else:
            c.show_stats = False

        stats = self.sa.query(Statistics) \
            .filter(Statistics.repository == c.db_repo) \
            .scalar()

        c.stats_percentage = 0

        if stats and stats.languages:
            c.no_data = False is c.db_repo.enable_statistics
            lang_stats_d = json.loads(stats.languages)

            lang_stats = ((x, {"count": y,
                               "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
                          for x, y in lang_stats_d.items())

            c.trending_languages = json.dumps(
                sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
            )
        else:
            c.no_data = True
            c.trending_languages = json.dumps([])

        c.enable_downloads = c.db_repo.enable_downloads
        c.readme_data, c.readme_file = \
            self.__get_readme_data(c.db_repo)
        return render('summary/summary.html')
Exemplo n.º 8
0
    def show(self, group_name):
        """GET /repo_groups/group_name: Show a specific item"""
        # url('repos_group', group_name=GROUP_NAME)
        c.active = 'settings'

        c.group = c.repo_group = RepoGroupModel()._get_repo_group(group_name)
        c.group_repos = c.group.repositories.all()

        #overwrite our cached list with current filter
        c.repo_cnt = 0

        groups = RepoGroup.query().order_by(RepoGroup.group_name)\
            .filter(RepoGroup.group_parent_id == c.group.group_id).all()
        c.groups = self.scm_model.get_repo_groups(groups)

        c.repos_list = Repository.query()\
                        .filter(Repository.group_id == c.group.group_id)\
                        .order_by(func.lower(Repository.repo_name))\
                        .all()

        repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
                                                   admin=False)
        #json used to render the grid
        c.data = json.dumps(repos_data)

        return render('admin/repo_groups/repo_group_show.html')
Exemplo n.º 9
0
 def user_auth(self, username, password):
     """Authenticate a user against crowd. Returns brief information about
     the user."""
     url = ("%s/rest/usermanagement/%s/authentication?username=%s"
            % (self._uri, self._version, urllib2.quote(username)))
     body = json.dumps({"value": password})
     return self._request(url, body)
Exemplo n.º 10
0
 def user_auth(self, username, password):
     """Authenticate a user against crowd. Returns brief information about
     the user."""
     url = ("%s/rest/usermanagement/%s/authentication?username=%s"
            % (self._uri, self._version, urllib2.quote(username)))
     body = json.dumps({"value": password})
     return self._request(url, body)
Exemplo n.º 11
0
    def show(self, group_name):
        """GET /repo_groups/group_name: Show a specific item"""
        # url('repos_group', group_name=GROUP_NAME)
        c.active = 'settings'

        c.group = c.repo_group = RepoGroupModel()._get_repo_group(group_name)
        c.group_repos = c.group.repositories.all()

        #overwrite our cached list with current filter
        c.repo_cnt = 0

        groups = RepoGroup.query().order_by(RepoGroup.group_name)\
            .filter(RepoGroup.group_parent_id == c.group.group_id).all()
        c.groups = self.scm_model.get_repo_groups(groups)

        c.repos_list = Repository.query()\
                        .filter(Repository.group_id == c.group.group_id)\
                        .order_by(func.lower(Repository.repo_name))\
                        .all()

        repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
                                                   admin=False)
        #json used to render the grid
        c.data = json.dumps(repos_data)

        return render('admin/repo_groups/repo_group_show.html')
Exemplo n.º 12
0
    def index(self, format='html'):
        """GET /users: All items in the collection"""
        # url('users')

        c.users_list = User.query().order_by(User.username)\
                        .filter(User.username != User.DEFAULT_USER)\
                        .order_by(func.lower(User.username))\
                        .all()

        users_data = []
        total_records = len(c.users_list)
        _tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        grav_tmpl = '<div class="gravatar">%s</div>'

        username = lambda user_id, username: (template.get_def(
            "user_name").render(user_id, username, _=_, h=h, c=c))

        user_actions = lambda user_id, username: (template.get_def(
            "user_actions").render(user_id, username, _=_, h=h, c=c))

        for user in c.users_list:
            users_data.append({
                "gravatar":
                grav_tmpl % h.gravatar(user.email, size=20),
                "raw_name":
                user.username,
                "username":
                username(user.user_id, user.username),
                "firstname":
                user.name,
                "lastname":
                user.lastname,
                "last_login":
                h.fmt_date(user.last_login),
                "last_login_raw":
                datetime_to_time(user.last_login),
                "active":
                h.boolicon(user.active),
                "admin":
                h.boolicon(user.admin),
                "extern_type":
                user.extern_type,
                "extern_name":
                user.extern_name,
                "action":
                user_actions(user.user_id, user.username),
            })

        c.data = json.dumps({
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": users_data
        })

        return render('admin/users/users.html')
Exemplo n.º 13
0
 def get_users_js(self):
     users = self.sa.query(User).filter(User.active == True).all()
     return json.dumps([{
         'id': u.user_id,
         'fname': u.name,
         'lname': u.lastname,
         'nname': u.username,
         'gravatar_lnk': h.gravatar_url(u.email, size=28),
         'gravatar_size': 14,
     } for u in users])
Exemplo n.º 14
0
    def index(self, format='html'):
        """GET /repo_groups: All items in the collection"""
        # url('repos_groups')
        _list = RepoGroup.query()\
                    .order_by(func.lower(RepoGroup.group_name))\
                    .all()
        group_iter = RepoGroupList(_list, perm_set=['group.admin'])
        repo_groups_data = []
        total_records = len(group_iter)
        _tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        repo_group_name = lambda repo_group_name, children_groups: (
            template.get_def("repo_group_name").render(
                repo_group_name, children_groups, _=_, h=h, c=c))
        repo_group_actions = lambda repo_group_id, repo_group_name, gr_count: (
            template.get_def("repo_group_actions").render(repo_group_id,
                                                          repo_group_name,
                                                          gr_count,
                                                          _=_,
                                                          h=h,
                                                          c=c,
                                                          ungettext=ungettext))

        for repo_gr in group_iter:
            children_groups = map(
                h.safe_unicode,
                itertools.chain((g.name for g in repo_gr.parents),
                                (x.name for x in [repo_gr])))
            repo_count = repo_gr.repositories.count()
            repo_groups_data.append({
                "raw_name":
                repo_gr.group_name,
                "group_name":
                repo_group_name(repo_gr.group_name, children_groups),
                "desc":
                repo_gr.group_description,
                "repos":
                repo_count,
                "owner":
                h.person(repo_gr.user),
                "action":
                repo_group_actions(repo_gr.group_id, repo_gr.group_name,
                                   repo_count)
            })

        c.data = json.dumps({
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": repo_groups_data
        })

        return render('admin/repo_groups/repo_groups.html')
Exemplo n.º 15
0
 def get_users_js(self):
     users = self.sa.query(User).filter(User.active == True).all()
     return json.dumps([
         {
             'id': u.user_id,
             'fname': u.name,
             'lname': u.lastname,
             'nname': u.username,
             'gravatar_lnk': h.gravatar_url(u.email, size=28),
             'gravatar_size': 14,
         } for u in users]
     )
Exemplo n.º 16
0
 def get_user_groups_js(self):
     user_groups = self.sa.query(UserGroup) \
         .filter(UserGroup.users_group_active == True) \
         .options(subqueryload(UserGroup.members)) \
         .all()
     user_groups = UserGroupList(
         user_groups,
         perm_set=['usergroup.read', 'usergroup.write', 'usergroup.admin'])
     return json.dumps([{
         'id': gr.users_group_id,
         'grname': gr.users_group_name,
         'grmembers': len(gr.members),
     } for gr in user_groups])
Exemplo n.º 17
0
def jsonrpc_error(message, retid=None, code=None):
    """
    Generate a Response object with a JSON-RPC error body

    :param code:
    :param retid:
    :param message:
    """
    from pylons.controllers.util import Response
    return Response(body=json.dumps(dict(id=retid, result=None,
                                         error=message)),
                    status=code,
                    content_type='application/json')
Exemplo n.º 18
0
def jsonrpc_error(message, retid=None, code=None):
    """
    Generate a Response object with a JSON-RPC error body

    :param code:
    :param retid:
    :param message:
    """
    from pylons.controllers.util import Response
    return Response(
        body=json.dumps(dict(id=retid, result=None, error=message)),
        status=code,
        content_type='application/json'
    )
Exemplo n.º 19
0
    def index(self, format='html'):
        """GET /users: All items in the collection"""
        # url('users')

        c.users_list = User.query().order_by(User.username) \
                        .filter(User.username != User.DEFAULT_USER) \
                        .order_by(func.lower(User.username)) \
                        .all()

        users_data = []
        total_records = len(c.users_list)
        _tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        grav_tmpl = '<div class="gravatar">%s</div>'

        username = lambda user_id, username: (
                template.get_def("user_name")
                .render(user_id, username, _=_, h=h, c=c))

        user_actions = lambda user_id, username: (
                template.get_def("user_actions")
                .render(user_id, username, _=_, h=h, c=c))

        for user in c.users_list:
            users_data.append({
                "gravatar": grav_tmpl % h.gravatar(user.email, size=20),
                "raw_name": user.username,
                "username": username(user.user_id, user.username),
                "firstname": h.escape(user.name),
                "lastname": h.escape(user.lastname),
                "last_login": h.fmt_date(user.last_login),
                "last_login_raw": datetime_to_time(user.last_login),
                "active": h.boolicon(user.active),
                "admin": h.boolicon(user.admin),
                "extern_type": user.extern_type,
                "extern_name": user.extern_name,
                "action": user_actions(user.user_id, user.username),
            })

        c.data = json.dumps({
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": users_data
        })

        return render('admin/users/users.html')
Exemplo n.º 20
0
    def index(self, format='html'):
        """GET /repos: All items in the collection"""
        # url('repos')
        _list = Repository.query()\
                        .order_by(func.lower(Repository.repo_name))\
                        .all()

        c.repos_list = RepoList(_list, perm_set=['repository.admin'])
        repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
                                                   admin=True,
                                                   super_user_actions=True)
        #json used to render the grid
        c.data = json.dumps(repos_data)

        return render('admin/repos/repos.html')
Exemplo n.º 21
0
 def get_user_groups_js(self):
     user_groups = self.sa.query(UserGroup) \
         .filter(UserGroup.users_group_active == True) \
         .options(subqueryload(UserGroup.members)) \
         .all()
     user_groups = UserGroupList(user_groups, perm_set=['usergroup.read',
                                                        'usergroup.write',
                                                        'usergroup.admin'])
     return json.dumps([
         {
             'id': gr.users_group_id,
             'grname': gr.users_group_name,
             'grmembers': len(gr.members),
         } for gr in user_groups]
     )
Exemplo n.º 22
0
    def index(self, format='html'):
        """GET /repos: All items in the collection"""
        # url('repos')
        _list = Repository.query()\
                        .order_by(func.lower(Repository.repo_name))\
                        .all()

        c.repos_list = RepoList(_list, perm_set=['repository.admin'])
        repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
                                                   admin=True,
                                                   super_user_actions=True)
        #json used to render the grid
        c.data = json.dumps(repos_data)

        return render('admin/repos/repos.html')
Exemplo n.º 23
0
    def index(self):
        c.groups = self.scm_model.get_repo_groups()
        c.group = None

        c.repos_list = Repository.query()\
                        .filter(Repository.group_id == None)\
                        .order_by(func.lower(Repository.repo_name))\
                        .all()

        repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
                                                   admin=False)
        #json used to render the grid
        c.data = json.dumps(repos_data)

        return render('/index.html')
Exemplo n.º 24
0
    def index(self, format='html'):
        """GET /users_groups: All items in the collection"""
        # url('users_groups')
        _list = UserGroup.query()\
                        .order_by(func.lower(UserGroup.users_group_name))\
                        .all()
        group_iter = UserGroupList(_list, perm_set=['usergroup.admin'])
        user_groups_data = []
        total_records = len(group_iter)
        _tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        user_group_name = lambda user_group_id, user_group_name: (
            template.get_def("user_group_name").render(
                user_group_id, user_group_name, _=_, h=h, c=c))
        user_group_actions = lambda user_group_id, user_group_name: (
            template.get_def("user_group_actions").render(
                user_group_id, user_group_name, _=_, h=h, c=c))
        for user_gr in group_iter:

            user_groups_data.append({
                "raw_name":
                user_gr.users_group_name,
                "group_name":
                user_group_name(user_gr.users_group_id,
                                user_gr.users_group_name),
                "desc":
                user_gr.user_group_description,
                "members":
                len(user_gr.members),
                "active":
                h.boolicon(user_gr.users_group_active),
                "owner":
                h.person(user_gr.user.username),
                "action":
                user_group_actions(user_gr.users_group_id,
                                   user_gr.users_group_name)
            })

        c.data = json.dumps({
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": user_groups_data
        })

        return render('admin/user_groups/user_groups.html')
Exemplo n.º 25
0
 def _store_metadata(self, repo, gist_id, gist_access_id, user_id, gist_type,
                     gist_expires):
     """
     store metadata inside the gist, this can be later used for imports
     or gist identification
     """
     metadata = {
         'metadata_version': '1',
         'gist_db_id': gist_id,
         'gist_access_id': gist_access_id,
         'gist_owner_id': user_id,
         'gist_type': gist_type,
         'gist_expires': gist_expires,
         'gist_updated': time.time(),
     }
     with open(os.path.join(repo.path, '.hg', GIST_METADATA_FILE), 'wb') as f:
         f.write(json.dumps(metadata))
Exemplo n.º 26
0
 def _store_metadata(self, repo, gist_id, gist_access_id, user_id, gist_type,
                     gist_expires):
     """
     store metadata inside the gist, this can be later used for imports
     or gist identification
     """
     metadata = {
         'metadata_version': '1',
         'gist_db_id': gist_id,
         'gist_access_id': gist_access_id,
         'gist_owner_id': user_id,
         'gist_type': gist_type,
         'gist_expires': gist_expires,
         'gist_updated': time.time(),
     }
     with open(os.path.join(repo.path, '.hg', GIST_METADATA_FILE), 'wb') as f:
         f.write(json.dumps(metadata))
Exemplo n.º 27
0
    def index(self, format='html'):
        """GET /repo_groups: All items in the collection"""
        # url('repos_groups')
        _list = RepoGroup.query()\
                    .order_by(func.lower(RepoGroup.group_name))\
                    .all()
        group_iter = RepoGroupList(_list, perm_set=['group.admin'])
        repo_groups_data = []
        total_records = len(group_iter)
        _tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        repo_group_name = lambda repo_group_name, children_groups: (
            template.get_def("repo_group_name")
            .render(repo_group_name, children_groups, _=_, h=h, c=c)
        )
        repo_group_actions = lambda repo_group_id, repo_group_name, gr_count: (
            template.get_def("repo_group_actions")
            .render(repo_group_id, repo_group_name, gr_count, _=_, h=h, c=c,
                    ungettext=ungettext)
        )

        for repo_gr in group_iter:
            children_groups = map(h.safe_unicode,
                itertools.chain((g.name for g in repo_gr.parents),
                                (x.name for x in [repo_gr])))
            repo_count = repo_gr.repositories.count()
            repo_groups_data.append({
                "raw_name": repo_gr.group_name,
                "group_name": repo_group_name(repo_gr.group_name, children_groups),
                "desc": h.escape(repo_gr.group_description),
                "repos": repo_count,
                "owner": h.person(repo_gr.user),
                "action": repo_group_actions(repo_gr.group_id, repo_gr.group_name,
                                             repo_count)
            })

        c.data = json.dumps({
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": repo_groups_data
        })

        return render('admin/repo_groups/repo_groups.html')
Exemplo n.º 28
0
def api_call(apikey, apihost, method=None, **kw):
    import random
    import urllib2
    import pprint
    """
    Api_call wrapper for RhodeCode.

    :param apikey:
    :param apihost:
    :param format: formatting, pretty means prints and pprint of json
     json returns unparsed json
    :param method:
    :returns: json response from server
    """
    def _build_data(random_id):
        """
        Builds API data with given random ID

        :param random_id:
        """
        return {
            "id": random_id,
            "api_key": apikey,
            "method": method,
            "args": kw
        }

    if not method:
        raise Exception('please specify method name !')

    id_ = random.randrange(1, 9999)
    req = urllib2.Request('%s/_admin/api' % apihost,
                          data=json.dumps(_build_data(id_)),
                          headers={'content-type': 'text/plain'})
    ret = urllib2.urlopen(req)
    raw_json = ret.read()
    json_data = json.loads(raw_json)
    id_ret = json_data['id']
    if id_ret == id_:
        return json_data

    else:
        _formatted_json = pprint.pformat(json_data)
        raise Exception('something went wrong. '
                        'ID mismatch got %s, expected %s | %s' %
                        (id_ret, id_, _formatted_json))
Exemplo n.º 29
0
    def _load_my_repos_data(self, watched=False):
        if watched:
            admin = False
            repos_list = [x.follows_repository for x in
                          Session().query(UserFollowing).filter(
                              UserFollowing.user_id ==
                              self.authuser.user_id).all()]
        else:
            admin = True
            repos_list = Session().query(Repository) \
                         .filter(Repository.user_id ==
                                 self.authuser.user_id) \
                         .order_by(func.lower(Repository.repo_name)).all()

        repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
                                                   admin=admin)
        #json used to render the grid
        return json.dumps(repos_data)
Exemplo n.º 30
0
    def _load_my_repos_data(self, watched=False):
        if watched:
            admin = False
            repos_list = [
                x.follows_repository
                for x in Session().query(UserFollowing).filter(
                    UserFollowing.user_id == self.authuser.user_id).all()
            ]
        else:
            admin = True
            repos_list = Session().query(Repository)\
                         .filter(Repository.user_id ==
                                 self.authuser.user_id)\
                         .order_by(func.lower(Repository.repo_name)).all()

        repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
                                                   admin=admin)
        #json used to render the grid
        return json.dumps(repos_data)
Exemplo n.º 31
0
def api_call(apikey, apihost, method=None, **kw):
    """
    Api_call wrapper for Kallithea.

    :param apikey:
    :param apihost:
    :param format: formatting, pretty means prints and pprint of json
     json returns unparsed json
    :param method:
    :returns: json response from server
    """
    def _build_data(random_id):
        """
        Builds API data with given random ID

        :param random_id:
        """
        return {
            "id": random_id,
            "api_key": apikey,
            "method": method,
            "args": kw
        }

    if not method:
        raise Exception('please specify method name !')
    apihost = apihost.rstrip('/')
    id_ = random.randrange(1, 9999)
    req = urllib2.Request('%s/_admin/api' % apihost,
                      data=json.dumps(_build_data(id_)),
                      headers={'content-type': 'text/plain'})
    ret = urllib2.urlopen(req)
    raw_json = ret.read()
    json_data = json.loads(raw_json)
    id_ret = json_data['id']
    if id_ret == id_:
        return json_data

    else:
        _formatted_json = pprint.pformat(json_data)
        raise Exception('something went wrong. '
                        'ID mismatch got %s, expected %s | %s' % (
                                            id_ret, id_, _formatted_json))
Exemplo n.º 32
0
    def index(self, format='html'):
        """GET /users_groups: All items in the collection"""
        # url('users_groups')
        _list = UserGroup.query()\
                        .order_by(func.lower(UserGroup.users_group_name))\
                        .all()
        group_iter = UserGroupList(_list, perm_set=['usergroup.admin'])
        user_groups_data = []
        total_records = len(group_iter)
        _tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        user_group_name = lambda user_group_id, user_group_name: (
            template.get_def("user_group_name")
            .render(user_group_id, user_group_name, _=_, h=h, c=c)
        )
        user_group_actions = lambda user_group_id, user_group_name: (
            template.get_def("user_group_actions")
            .render(user_group_id, user_group_name, _=_, h=h, c=c)
        )
        for user_gr in group_iter:

            user_groups_data.append({
                "raw_name": user_gr.users_group_name,
                "group_name": user_group_name(user_gr.users_group_id,
                                              user_gr.users_group_name),
                "desc": user_gr.user_group_description,
                "members": len(user_gr.members),
                "active": h.boolicon(user_gr.users_group_active),
                "owner": h.person(user_gr.user.username),
                "action": user_group_actions(user_gr.users_group_id, user_gr.users_group_name)
            })

        c.data = json.dumps({
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": user_groups_data
        })

        return render('admin/user_groups/user_groups.html')
Exemplo n.º 33
0
def jsonify(func, *args, **kwargs):
    """Action decorator that formats output for JSON

    Given a function that will return content, this decorator will turn
    the result into JSON, with a content-type of 'application/json' and
    output it.

    """
    from pylons.decorators.util import get_pylons
    from kallithea.lib.compat import json
    pylons = get_pylons(args)
    pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
    data = func(*args, **kwargs)
    if isinstance(data, (list, tuple)):
        msg = "JSON responses with Array envelopes are susceptible to " \
              "cross-site data leak attacks, see " \
              "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
        warnings.warn(msg, Warning, 2)
        log.warning(msg)
    log.debug("Returning JSON wrapped action output")
    return json.dumps(data, encoding='utf-8')
Exemplo n.º 34
0
def jsonify(func, *args, **kwargs):
    """Action decorator that formats output for JSON

    Given a function that will return content, this decorator will turn
    the result into JSON, with a content-type of 'application/json' and
    output it.

    """
    from pylons.decorators.util import get_pylons
    from kallithea.lib.compat import json
    pylons = get_pylons(args)
    pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
    data = func(*args, **kwargs)
    if isinstance(data, (list, tuple)):
        msg = "JSON responses with Array envelopes are susceptible to " \
              "cross-site data leak attacks, see " \
              "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
        warnings.warn(msg, Warning, 2)
        log.warning(msg)
    log.debug("Returning JSON wrapped action output")
    return json.dumps(data, encoding='utf-8')
Exemplo n.º 35
0
def jsonify(func, *args, **kwargs):
    """Action decorator that formats output for JSON

    Given a function that will return content, this decorator will turn
    the result into JSON, with a content-type of 'application/json' and
    output it.
    """
    response.headers['Content-Type'] = 'application/json; charset=utf-8'
    data = func(*args, **kwargs)
    if isinstance(data, (list, tuple)):
        # A JSON list response is syntactically valid JavaScript and can be
        # loaded and executed as JavaScript by a malicious third-party site
        # using <script>, which can lead to cross-site data leaks.
        # JSON responses should therefore be scalars or objects (i.e. Python
        # dicts), because a JSON object is a syntax error if intepreted as JS.
        msg = "JSON responses with Array envelopes are susceptible to " \
              "cross-site data leak attacks, see " \
              "https://web.archive.org/web/20120519231904/http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
        warnings.warn(msg, Warning, 2)
        log.warning(msg)
    log.debug("Returning JSON wrapped action output")
    return json.dumps(data, encoding='utf-8')
Exemplo n.º 36
0
    def post(self, method, args):
        """Send a generic API post to Kallithea.

        This will generate the UUID for validation check after the
        response is returned. Handle errors and get the result back.
        """
        uid = str(uuid.uuid1())
        data = self.get_api_data(uid, method, args)

        data = json.dumps(data)
        headers = {'content-type': 'text/plain'}
        req = urllib2.Request(self.url, data, headers)

        response = urllib2.urlopen(req)
        response = json.load(response)

        if uid != response["id"]:
            raise InvalidResponseIDError("UUID does not match.")

        if response["error"] is not None:
            raise ResponseError(response["error"])

        return response["result"]
Exemplo n.º 37
0
    def post(self, method, args):
        """Send a generic API post to Kallithea.

        This will generate the UUID for validation check after the
        response is returned. Handle errors and get the result back.
        """
        uid = str(uuid.uuid1())
        data = self.get_api_data(uid, method, args)

        data = json.dumps(data)
        headers = {'content-type': 'text/plain'}
        req = urllib2.Request(self.url, data, headers)

        response = urllib2.urlopen(req)
        response = json.load(response)

        if uid != response["id"]:
            raise InvalidResponseIDError("UUID does not match.")

        if response["error"] is not None:
            raise ResponseError(response["error"])

        return response["result"]
Exemplo n.º 38
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:
            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.changeset_comment_id, st.comment)
                                for st in ChangesetStatusModel()
                                .get_statuses(c.db_repo.repo_id,
                                              changeset.raw_id, with_revisions=True)
                                if st.changeset_comment_id is not None)

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

            c.changes[changeset.raw_id] = []

            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)
            cs_changes = OrderedDict()
            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']
                    fid = h.FID(changeset.raw_id, f['filename'])
                    diff = diff_processor.as_html(enable_comments=enable_comments,
                                                  parsed_lines=[f])
                    cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'],
                                       diff, st]
            else:
                # downloads/raw we only need RAW diff nothing else
                diff = diff_processor.as_raw()
                cs_changes[''] = [None, None, None, None, diff, None]
            c.changes[changeset.raw_id] = cs_changes

        #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 = json.dumps(graph_data(c.db_repo_scm_instance, revs))
                return render('changeset/changeset_range.html')
Exemplo n.º 39
0
        except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
            log.error(traceback.format_exc())
            h.flash(safe_str(e), category='error')
            return redirect(url('changelog_home', repo_name=c.repo_name))

        c.branch_name = branch_name
        c.branch_filters = [('', _('None'))] + \
            [(k, k) for k in c.db_repo_scm_instance.branches.keys()]
        if c.db_repo_scm_instance.closed_branches:
            prefix = _('(closed)') + ' '
            c.branch_filters += [('-', '-')] + \
                [(k, prefix + k) for k in c.db_repo_scm_instance.closed_branches.keys()]
        revs = []
        if not f_path:
            revs = [x.revision for x in c.pagination]
        c.jsdata = json.dumps(graph_data(c.db_repo_scm_instance, revs))

        c.revision = revision  # requested revision ref
        c.first_revision = c.pagination[0]  # pagination is never empty here!
        return render('changelog/changelog.html')

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                   'repository.admin')
    def changelog_details(self, cs):
        if request.environ.get('HTTP_X_PARTIAL_XHR'):
            c.cs = c.db_repo_scm_instance.get_changeset(cs)
            return render('changelog/changelog_details.html')
        raise HTTPNotFound()

    @LoginRequired()
Exemplo n.º 40
0
def get_commits_stats(repo_name, ts_min_y, ts_max_y, recurse_limit=100):
    log = get_logger(get_commits_stats)
    DBS = get_session()
    lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, ts_max_y)
    lockkey_path = config['app_conf']['cache_dir']

    log.info('running task with lockkey %s' % lockkey)

    try:
        lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))

        # for js data compatibility cleans the key for person from '
        akc = lambda k: person(k).replace('"', "")

        co_day_auth_aggr = {}
        commits_by_day_aggregate = {}
        repo = Repository.get_by_repo_name(repo_name)
        if repo is None:
            return True

        repo = repo.scm_instance
        repo_size = repo.count()
        # return if repo have no revisions
        if repo_size < 1:
            lock.release()
            return True

        skip_date_limit = True
        parse_limit = int(config['app_conf'].get('commit_parse_limit'))
        last_rev = None
        last_cs = None
        timegetter = itemgetter('time')

        dbrepo = DBS.query(Repository)\
            .filter(Repository.repo_name == repo_name).scalar()
        cur_stats = DBS.query(Statistics)\
            .filter(Statistics.repository == dbrepo).scalar()

        if cur_stats is not None:
            last_rev = cur_stats.stat_on_revision

        if last_rev == repo.get_changeset().revision and repo_size > 1:
            # pass silently without any work if we're not on first revision or
            # current state of parsing revision(from db marker) is the
            # last revision
            lock.release()
            return True

        if cur_stats:
            commits_by_day_aggregate = OrderedDict(
                json.loads(cur_stats.commit_activity_combined))
            co_day_auth_aggr = json.loads(cur_stats.commit_activity)

        log.debug('starting parsing %s' % parse_limit)
        lmktime = mktime

        last_rev = last_rev + 1 if last_rev >= 0 else 0
        log.debug('Getting revisions from %s to %s' %
                  (last_rev, last_rev + parse_limit))
        for cs in repo[last_rev:last_rev + parse_limit]:
            log.debug('parsing %s' % cs)
            last_cs = cs  # remember last parsed changeset
            k = lmktime([
                cs.date.timetuple()[0],
                cs.date.timetuple()[1],
                cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0
            ])

            if akc(cs.author) in co_day_auth_aggr:
                try:
                    l = [
                        timegetter(x)
                        for x in co_day_auth_aggr[akc(cs.author)]['data']
                    ]
                    time_pos = l.index(k)
                except ValueError:
                    time_pos = None

                if time_pos >= 0 and time_pos is not None:

                    datadict = \
                        co_day_auth_aggr[akc(cs.author)]['data'][time_pos]

                    datadict["commits"] += 1
                    datadict["added"] += len(cs.added)
                    datadict["changed"] += len(cs.changed)
                    datadict["removed"] += len(cs.removed)

                else:
                    if k >= ts_min_y and k <= ts_max_y or skip_date_limit:

                        datadict = {
                            "time": k,
                            "commits": 1,
                            "added": len(cs.added),
                            "changed": len(cs.changed),
                            "removed": len(cs.removed),
                        }
                        co_day_auth_aggr[akc(cs.author)]['data']\
                            .append(datadict)

            else:
                if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
                    co_day_auth_aggr[akc(cs.author)] = {
                        "label":
                        akc(cs.author),
                        "data": [{
                            "time": k,
                            "commits": 1,
                            "added": len(cs.added),
                            "changed": len(cs.changed),
                            "removed": len(cs.removed),
                        }],
                        "schema": ["commits"],
                    }

            #gather all data by day
            if k in commits_by_day_aggregate:
                commits_by_day_aggregate[k] += 1
            else:
                commits_by_day_aggregate[k] = 1

        overview_data = sorted(commits_by_day_aggregate.items(),
                               key=itemgetter(0))

        if not co_day_auth_aggr:
            co_day_auth_aggr[akc(repo.contact)] = {
                "label": akc(repo.contact),
                "data": [0, 1],
                "schema": ["commits"],
            }

        stats = cur_stats if cur_stats else Statistics()
        stats.commit_activity = json.dumps(co_day_auth_aggr)
        stats.commit_activity_combined = json.dumps(overview_data)

        log.debug('last revision %s' % last_rev)
        leftovers = len(repo.revisions[last_rev:])
        log.debug('revisions to parse %s' % leftovers)

        if last_rev == 0 or leftovers < parse_limit:
            log.debug('getting code trending stats')
            stats.languages = json.dumps(__get_codes_stats(repo_name))

        try:
            stats.repository = dbrepo
            stats.stat_on_revision = last_cs.revision if last_cs else 0
            DBS.add(stats)
            DBS.commit()
        except:
            log.error(traceback.format_exc())
            DBS.rollback()
            lock.release()
            return False

        # final release
        lock.release()

        # execute another task if celery is enabled
        if len(repo.revisions) > 1 and CELERY_ON and recurse_limit > 0:
            recurse_limit -= 1
            run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y,
                     recurse_limit)
        if recurse_limit <= 0:
            log.debug('Breaking recursive mode due to reach of recurse limit')
        return True
    except LockHeld:
        log.info('LockHeld')
        return 'Task with key %s already running' % lockkey
Exemplo n.º 41
0
    def index(self):
        # Return a rendered template
        p = safe_int(request.GET.get('page', 1), 1)
        c.user = User.get(self.authuser.user_id)
        c.following = self.sa.query(UserFollowing) \
            .filter(UserFollowing.user_id == self.authuser.user_id) \
            .options(joinedload(UserFollowing.follows_repository)) \
            .all()

        journal = self._get_journal_data(c.following)

        def url_generator(**kw):
            return url.current(filter=c.search_term, **kw)

        c.journal_pager = Page(journal, page=p, items_per_page=20, url=url_generator)
        c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)

        if request.environ.get('HTTP_X_PARTIAL_XHR'):
            return render('journal/journal_data.html')

        repos_list = Session().query(Repository) \
                     .filter(Repository.user_id ==
                             self.authuser.user_id) \
                     .order_by(func.lower(Repository.repo_name)).all()

        repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
                                                   admin=True)
        #json used to render the grid
        c.data = json.dumps(repos_data)

        watched_repos_data = []

        ## watched repos
        _render = RepoModel._render_datatable

        def quick_menu(repo_name):
            return _render('quick_menu', repo_name)

        def repo_lnk(name, rtype, rstate, private, fork_of):
            return _render('repo_name', name, rtype, rstate, private, fork_of,
                           short_name=False, admin=False)

        def last_rev(repo_name, cs_cache):
            return _render('revision', repo_name, cs_cache.get('revision'),
                           cs_cache.get('raw_id'), cs_cache.get('author'),
                           cs_cache.get('message'))

        def desc(desc):
            from pylons import tmpl_context as c
            return h.urlify_text(desc, truncate=60, stylize=c.visual.stylify_metatags)

        def repo_actions(repo_name):
            return _render('repo_actions', repo_name)

        def owner_actions(user_id, username):
            return _render('user_name', user_id, username)

        def toogle_follow(repo_id):
            return  _render('toggle_follow', repo_id)

        for entry in c.following:
            repo = entry.follows_repository
            cs_cache = repo.changeset_cache
            row = {
                "menu": quick_menu(repo.repo_name),
                "raw_name": repo.repo_name.lower(),
                "name": repo_lnk(repo.repo_name, repo.repo_type,
                                 repo.repo_state, repo.private, repo.fork),
                "last_changeset": last_rev(repo.repo_name, cs_cache),
                "last_rev_raw": cs_cache.get('revision'),
                "action": toogle_follow(repo.repo_id)
            }

            watched_repos_data.append(row)

        c.watched_data = json.dumps({
            "totalRecords": len(c.following),
            "startIndex": 0,
            "sort": "name",
            "dir": "asc",
            "records": watched_repos_data
        })
        return render('journal/journal.html')
Exemplo n.º 42
0
    def compare(self, repo_name, org_ref_type, org_ref_name, other_ref_type,
                other_ref_name):
        org_repo = c.db_repo.repo_name
        other_repo = request.GET.get('other_repo', org_repo)
        # If merge is True:
        #   Show what org would get if merged with other:
        #   List changesets that are ancestors of other but not of org.
        #   New changesets in org is thus ignored.
        #   Diff will be from common ancestor, and merges of org to other will thus be ignored.
        # If merge is False:
        #   Make a raw diff from org to other, no matter if related or not.
        #   Changesets in one and not in the other will be ignored
        merge = bool(request.GET.get('merge'))
        # fulldiff disables cut_off_limit
        c.fulldiff = request.GET.get('fulldiff')
        # partial uses compare_cs.html template directly
        partial = request.environ.get('HTTP_X_PARTIAL_XHR')
        # as_form puts hidden input field with changeset revisions
        c.as_form = partial and request.GET.get('as_form')
        # swap url for compare_diff page - never partial and never as_form
        c.swap_url = h.url('compare_url',
                           repo_name=other_repo,
                           org_ref_type=other_ref_type,
                           org_ref_name=other_ref_name,
                           other_repo=org_repo,
                           other_ref_type=org_ref_type,
                           other_ref_name=org_ref_name,
                           merge=merge or '')

        # set callbacks for generating markup for icons
        c.ignorews_url = _ignorews_url
        c.context_url = _context_url
        ignore_whitespace = request.GET.get('ignorews') == '1'
        line_context = request.GET.get('context', 3)

        org_repo = Repository.get_by_repo_name(org_repo)
        other_repo = Repository.get_by_repo_name(other_repo)

        if org_repo is None:
            msg = 'Could not find org repo %s' % org_repo
            log.error(msg)
            h.flash(msg, category='error')
            return redirect(url('compare_home', repo_name=c.repo_name))

        if other_repo is None:
            msg = 'Could not find other repo %s' % other_repo
            log.error(msg)
            h.flash(msg, category='error')
            return redirect(url('compare_home', repo_name=c.repo_name))

        if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
            msg = 'compare of two different kind of remote repos not available'
            log.error(msg)
            h.flash(msg, category='error')
            return redirect(url('compare_home', repo_name=c.repo_name))

        c.a_rev = self._get_ref_rev(org_repo,
                                    org_ref_type,
                                    org_ref_name,
                                    returnempty=True)
        c.cs_rev = self._get_ref_rev(other_repo, other_ref_type,
                                     other_ref_name)

        c.compare_home = False
        c.a_repo = org_repo
        c.a_ref_name = org_ref_name
        c.a_ref_type = org_ref_type
        c.cs_repo = other_repo
        c.cs_ref_name = other_ref_name
        c.cs_ref_type = other_ref_type

        c.cs_ranges, c.cs_ranges_org, c.ancestor = self._get_changesets(
            org_repo.scm_instance.alias, org_repo.scm_instance, c.a_rev,
            other_repo.scm_instance, c.cs_rev)
        raw_ids = [x.raw_id for x in c.cs_ranges]
        c.cs_comments = other_repo.get_comments(raw_ids)
        c.statuses = other_repo.statuses(raw_ids)

        revs = [ctx.revision for ctx in reversed(c.cs_ranges)]
        c.jsdata = json.dumps(graph_data(c.cs_repo.scm_instance, revs))

        if partial:
            return render('compare/compare_cs.html')
        if merge and c.ancestor:
            # case we want a simple diff without incoming changesets,
            # previewing what will be merged.
            # Make the diff on the other repo (which is known to have other_rev)
            log.debug('Using ancestor %s as rev1 instead of %s' %
                      (c.ancestor, c.a_rev))
            rev1 = c.ancestor
            org_repo = other_repo
        else:  # comparing tips, not necessarily linearly related
            if merge:
                log.error('Unable to find ancestor revision')
            if org_repo != other_repo:
                # TODO: we could do this by using hg unionrepo
                log.error('cannot compare across repos %s and %s', org_repo,
                          other_repo)
                h.flash(_(
                    'Cannot compare repositories without using common ancestor'
                ),
                        category='error')
                raise HTTPBadRequest
            rev1 = c.a_rev

        diff_limit = self.cut_off_limit if not c.fulldiff else None

        log.debug('running diff between %s and %s in %s' %
                  (rev1, c.cs_rev, org_repo.scm_instance.path))
        txtdiff = org_repo.scm_instance.get_diff(
            rev1=rev1,
            rev2=c.cs_rev,
            ignore_whitespace=ignore_whitespace,
            context=line_context)

        diff_processor = diffs.DiffProcessor(txtdiff or '',
                                             format='gitdiff',
                                             diff_limit=diff_limit)
        _parsed = diff_processor.prepare()

        c.limited_diff = False
        if isinstance(_parsed, LimitedDiffContainer):
            c.limited_diff = True

        c.files = []
        c.changes = {}
        c.lines_added = 0
        c.lines_deleted = 0
        for f in _parsed:
            st = f['stats']
            if not st['binary']:
                c.lines_added += st['added']
                c.lines_deleted += st['deleted']
            fid = h.FID('', f['filename'])
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
            htmldiff = diff_processor.as_html(enable_comments=False,
                                              parsed_lines=[f])
            c.changes[fid] = [f['operation'], f['filename'], htmldiff]

        return render('compare/compare_diff.html')
Exemplo n.º 43
0
            if isinstance(raw_response, HTTPError):
                self._error = str(raw_response)
        except JSONRPCError, e:
            self._error = safe_str(e)
        except Exception, e:
            log.error('Encountered unhandled exception: %s'
                      % (traceback.format_exc(),))
            json_exc = JSONRPCError('Internal server error')
            self._error = safe_str(json_exc)

        if self._error is not None:
            raw_response = None

        response = dict(id=self._req_id, result=raw_response, error=self._error)
        try:
            return json.dumps(response)
        except TypeError, e:
            log.error('API FAILED. Error encoding response: %s' % e)
            return json.dumps(
                dict(
                    id=self._req_id,
                    result=None,
                    error="Error encoding response"
                )
            )

    def _find_method(self):
        """
        Return method named by `self._req_method` in controller if able
        """
        log.debug('Trying to find JSON-RPC method: %s' % (self._req_method,))
Exemplo n.º 44
0
    def show(self, repo_name, pull_request_id, extra=None):
        repo_model = RepoModel()
        c.users_array = repo_model.get_users_js()
        c.user_groups_array = repo_model.get_user_groups_js()
        c.pull_request = PullRequest.get_or_404(pull_request_id)
        c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
        cc_model = ChangesetCommentsModel()
        cs_model = ChangesetStatusModel()

        # pull_requests repo_name we opened it against
        # ie. other_repo must match
        if repo_name != c.pull_request.other_repo.repo_name:
            raise HTTPNotFound

        # load compare data into template context
        c.cs_repo = c.pull_request.org_repo
        (c.cs_ref_type,
         c.cs_ref_name,
         c.cs_rev) = c.pull_request.org_ref.split(':')

        c.a_repo = c.pull_request.other_repo
        (c.a_ref_type,
         c.a_ref_name,
         c.a_rev) = c.pull_request.other_ref.split(':') # other_rev is ancestor

        org_scm_instance = c.cs_repo.scm_instance # property with expensive cache invalidation check!!!
        c.cs_repo = c.cs_repo
        try:
            c.cs_ranges = [org_scm_instance.get_changeset(x)
                           for x in c.pull_request.revisions]
        except ChangesetDoesNotExistError:
            c.cs_ranges = []
        c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ...
        revs = [ctx.revision for ctx in reversed(c.cs_ranges)]
        c.jsdata = json.dumps(graph_data(org_scm_instance, revs))

        c.is_range = False
        if c.a_ref_type == 'rev': # this looks like a free range where target is ancestor
            cs_a = org_scm_instance.get_changeset(c.a_rev)
            root_parents = c.cs_ranges[0].parents
            c.is_range = cs_a in root_parents
            #c.merge_root = len(root_parents) > 1 # a range starting with a merge might deserve a warning

        avail_revs = set()
        avail_show = []
        c.cs_branch_name = c.cs_ref_name
        other_scm_instance = c.a_repo.scm_instance
        c.update_msg = ""
        c.update_msg_other = ""
        try:
            if org_scm_instance.alias == 'hg' and c.a_ref_name != 'ancestor':
                if c.cs_ref_type != 'branch':
                    c.cs_branch_name = org_scm_instance.get_changeset(c.cs_ref_name).branch # use ref_type ?
                c.a_branch_name = c.a_ref_name
                if c.a_ref_type != 'branch':
                    try:
                        c.a_branch_name = other_scm_instance.get_changeset(c.a_ref_name).branch # use ref_type ?
                    except EmptyRepositoryError:
                        c.a_branch_name = 'null' # not a branch name ... but close enough
                # candidates: descendants of old head that are on the right branch
                #             and not are the old head itself ...
                #             and nothing at all if old head is a descendant of target ref name
                if not c.is_range and other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, c.a_branch_name):
                    c.update_msg = _('This pull request has already been merged to %s.') % c.a_branch_name
                elif c.pull_request.is_closed():
                    c.update_msg = _('This pull request has been closed and can not be updated.')
                else: # look for descendants of PR head on source branch in org repo
                    avail_revs = org_scm_instance._repo.revs('%s:: & branch(%s)',
                                                             revs[0], c.cs_branch_name)
                    if len(avail_revs) > 1: # more than just revs[0]
                        # also show changesets that not are descendants but would be merged in
                        targethead = other_scm_instance.get_changeset(c.a_branch_name).raw_id
                        if org_scm_instance.path != other_scm_instance.path:
                            # Note: org_scm_instance.path must come first so all
                            # valid revision numbers are 100% org_scm compatible
                            # - both for avail_revs and for revset results
                            hgrepo = unionrepo.unionrepository(org_scm_instance.baseui,
                                                               org_scm_instance.path,
                                                               other_scm_instance.path)
                        else:
                            hgrepo = org_scm_instance._repo
                        show = set(hgrepo.revs('::%ld & !::parents(%s) & !::%s',
                                               avail_revs, revs[0], targethead))
                        c.update_msg = _('The following changes are available on %s:') % c.cs_branch_name
                    else:
                        show = set()
                        avail_revs = set() # drop revs[0]
                        c.update_msg = _('No changesets found for updating this pull request.')

                    # TODO: handle branch heads that not are tip-most
                    brevs = org_scm_instance._repo.revs('%s - %ld - %s', c.cs_branch_name, avail_revs, revs[0])
                    if brevs:
                        # also show changesets that are on branch but neither ancestors nor descendants
                        show.update(org_scm_instance._repo.revs('::%ld - ::%ld - ::%s', brevs, avail_revs, c.a_branch_name))
                        show.add(revs[0]) # make sure graph shows this so we can see how they relate
                        c.update_msg_other = _('Note: Branch %s has another head: %s.') % (c.cs_branch_name,
                            h.short_id(org_scm_instance.get_changeset((max(brevs))).raw_id))

                    avail_show = sorted(show, reverse=True)

            elif org_scm_instance.alias == 'git':
                c.cs_repo.scm_instance.get_changeset(c.cs_rev) # check it exists - raise ChangesetDoesNotExistError if not
                c.update_msg = _("Git pull requests don't support updates yet.")
        except ChangesetDoesNotExistError:
            c.update_msg = _('Error: revision %s was not found. Please create a new pull request!') % c.cs_rev

        c.avail_revs = avail_revs
        c.avail_cs = [org_scm_instance.get_changeset(r) for r in avail_show]
        c.avail_jsdata = json.dumps(graph_data(org_scm_instance, avail_show))

        raw_ids = [x.raw_id for x in c.cs_ranges]
        c.cs_comments = c.cs_repo.get_comments(raw_ids)
        c.statuses = c.cs_repo.statuses(raw_ids)

        ignore_whitespace = request.GET.get('ignorews') == '1'
        line_context = request.GET.get('context', 3)
        c.ignorews_url = _ignorews_url
        c.context_url = _context_url
        c.fulldiff = request.GET.get('fulldiff')
        diff_limit = self.cut_off_limit if not c.fulldiff else None

        # we swap org/other ref since we run a simple diff on one repo
        log.debug('running diff between %s and %s in %s',
                  c.a_rev, c.cs_rev, org_scm_instance.path)
        try:
            txtdiff = org_scm_instance.get_diff(rev1=safe_str(c.a_rev), rev2=safe_str(c.cs_rev),
                                                ignore_whitespace=ignore_whitespace,
                                                context=line_context)
        except ChangesetDoesNotExistError:
            txtdiff =  _("The diff can't be shown - the PR revisions could not be found.")
        diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
                                             diff_limit=diff_limit)
        _parsed = diff_processor.prepare()

        c.limited_diff = False
        if isinstance(_parsed, LimitedDiffContainer):
            c.limited_diff = True

        c.files = []
        c.changes = {}
        c.lines_added = 0
        c.lines_deleted = 0

        for f in _parsed:
            st = f['stats']
            c.lines_added += st['added']
            c.lines_deleted += st['deleted']
            fid = h.FID('', f['filename'])
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
            htmldiff = diff_processor.as_html(enable_comments=True,
                                              parsed_lines=[f])
            c.changes[fid] = [f['operation'], f['filename'], htmldiff]

        # inline comments
        c.inline_cnt = 0
        c.inline_comments = cc_model.get_inline_comments(
                                c.db_repo.repo_id,
                                pull_request=pull_request_id)
        # count inline comments
        for __, lines in c.inline_comments:
            for comments in lines.values():
                c.inline_cnt += len(comments)
        # comments
        c.comments = cc_model.get_comments(c.db_repo.repo_id,
                                           pull_request=pull_request_id)

        # (badly named) pull-request status calculation based on reviewer votes
        (c.pull_request_reviewers,
         c.pull_request_pending_reviewers,
         c.current_voting_result,
         ) = cs_model.calculate_pull_request_result(c.pull_request)
        c.changeset_statuses = ChangesetStatus.STATUSES

        c.as_form = False
        c.ancestor = None # there is one - but right here we don't know which
        return render('/pullrequests/pullrequest_show.html')
Exemplo n.º 45
0
def get_commits_stats(repo_name, ts_min_y, ts_max_y, recurse_limit=100):
    log = get_logger(get_commits_stats)
    DBS = get_session()
    lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
                            ts_max_y)
    lockkey_path = config['app_conf']['cache_dir']

    log.info('running task with lockkey %s', lockkey)

    try:
        lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))

        # for js data compatibility cleans the key for person from '
        akc = lambda k: person(k).replace('"', "")

        co_day_auth_aggr = {}
        commits_by_day_aggregate = {}
        repo = Repository.get_by_repo_name(repo_name)
        if repo is None:
            return True

        repo = repo.scm_instance
        repo_size = repo.count()
        # return if repo have no revisions
        if repo_size < 1:
            lock.release()
            return True

        skip_date_limit = True
        parse_limit = int(config['app_conf'].get('commit_parse_limit'))
        last_rev = None
        last_cs = None
        timegetter = itemgetter('time')

        dbrepo = DBS.query(Repository) \
            .filter(Repository.repo_name == repo_name).scalar()
        cur_stats = DBS.query(Statistics) \
            .filter(Statistics.repository == dbrepo).scalar()

        if cur_stats is not None:
            last_rev = cur_stats.stat_on_revision

        if last_rev == repo.get_changeset().revision and repo_size > 1:
            # pass silently without any work if we're not on first revision or
            # current state of parsing revision(from db marker) is the
            # last revision
            lock.release()
            return True

        if cur_stats:
            commits_by_day_aggregate = OrderedDict(json.loads(
                                        cur_stats.commit_activity_combined))
            co_day_auth_aggr = json.loads(cur_stats.commit_activity)

        log.debug('starting parsing %s', parse_limit)
        lmktime = mktime

        last_rev = last_rev + 1 if last_rev >= 0 else 0
        log.debug('Getting revisions from %s to %s',
             last_rev, last_rev + parse_limit
        )
        for cs in repo[last_rev:last_rev + parse_limit]:
            log.debug('parsing %s', cs)
            last_cs = cs  # remember last parsed changeset
            k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
                          cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])

            if akc(cs.author) in co_day_auth_aggr:
                try:
                    l = [timegetter(x) for x in
                         co_day_auth_aggr[akc(cs.author)]['data']]
                    time_pos = l.index(k)
                except ValueError:
                    time_pos = None

                if time_pos >= 0 and time_pos is not None:

                    datadict = \
                        co_day_auth_aggr[akc(cs.author)]['data'][time_pos]

                    datadict["commits"] += 1
                    datadict["added"] += len(cs.added)
                    datadict["changed"] += len(cs.changed)
                    datadict["removed"] += len(cs.removed)

                else:
                    if k >= ts_min_y and k <= ts_max_y or skip_date_limit:

                        datadict = {"time": k,
                                    "commits": 1,
                                    "added": len(cs.added),
                                    "changed": len(cs.changed),
                                    "removed": len(cs.removed),
                                   }
                        co_day_auth_aggr[akc(cs.author)]['data'] \
                            .append(datadict)

            else:
                if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
                    co_day_auth_aggr[akc(cs.author)] = {
                                        "label": akc(cs.author),
                                        "data": [{"time":k,
                                                 "commits":1,
                                                 "added":len(cs.added),
                                                 "changed":len(cs.changed),
                                                 "removed":len(cs.removed),
                                                 }],
                                        "schema": ["commits"],
                                        }

            #gather all data by day
            if k in commits_by_day_aggregate:
                commits_by_day_aggregate[k] += 1
            else:
                commits_by_day_aggregate[k] = 1

        overview_data = sorted(commits_by_day_aggregate.items(),
                               key=itemgetter(0))

        if not co_day_auth_aggr:
            co_day_auth_aggr[akc(repo.contact)] = {
                "label": akc(repo.contact),
                "data": [0, 1],
                "schema": ["commits"],
            }

        stats = cur_stats if cur_stats else Statistics()
        stats.commit_activity = json.dumps(co_day_auth_aggr)
        stats.commit_activity_combined = json.dumps(overview_data)

        log.debug('last revision %s', last_rev)
        leftovers = len(repo.revisions[last_rev:])
        log.debug('revisions to parse %s', leftovers)

        if last_rev == 0 or leftovers < parse_limit:
            log.debug('getting code trending stats')
            stats.languages = json.dumps(__get_codes_stats(repo_name))

        try:
            stats.repository = dbrepo
            stats.stat_on_revision = last_cs.revision if last_cs else 0
            DBS.add(stats)
            DBS.commit()
        except:
            log.error(traceback.format_exc())
            DBS.rollback()
            lock.release()
            return False

        # final release
        lock.release()

        # execute another task if celery is enabled
        if len(repo.revisions) > 1 and CELERY_ON and recurse_limit > 0:
            recurse_limit -= 1
            run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y,
                     recurse_limit)
        if recurse_limit <= 0:
            log.debug('Breaking recursive mode due to reach of recurse limit')
        return True
    except LockHeld:
        log.info('LockHeld')
        return 'Task with key %s already running' % lockkey
Exemplo n.º 46
0
    def index(self, repo_name, revision=None, f_path=None):
        # Fix URL after page size form submission via GET
        # TODO: Somehow just don't send this extra junk in the GET URL
        if request.GET.get('set'):
            request.GET.pop('set', None)
            if revision is None:
                raise HTTPFound(location=url('changelog_home', repo_name=repo_name, **request.GET))
            raise HTTPFound(location=url('changelog_file_home', repo_name=repo_name, revision=revision, f_path=f_path, **request.GET))

        limit = 2000
        default = 100
        if request.GET.get('size'):
            c.size = max(min(safe_int(request.GET.get('size')), limit), 1)
            session['changelog_size'] = c.size
            session.save()
        else:
            c.size = int(session.get('changelog_size', default))
        # min size must be 1
        c.size = max(c.size, 1)
        p = safe_int(request.GET.get('page', 1), 1)
        branch_name = request.GET.get('branch', None)
        if (branch_name and
            branch_name not in c.db_repo_scm_instance.branches and
            branch_name not in c.db_repo_scm_instance.closed_branches and
            not revision):
            raise HTTPFound(location=url('changelog_file_home', repo_name=c.repo_name,
                                    revision=branch_name, f_path=f_path or ''))

        if revision == 'tip':
            revision = None

        c.changelog_for_path = f_path
        try:

            if f_path:
                log.debug('generating changelog for path %s', f_path)
                # get the history for the file !
                tip_cs = c.db_repo_scm_instance.get_changeset()
                try:
                    collection = tip_cs.get_file_history(f_path)
                except (NodeDoesNotExistError, ChangesetError):
                    #this node is not present at tip !
                    try:
                        cs = self.__get_cs(revision, repo_name)
                        collection = cs.get_file_history(f_path)
                    except RepositoryError as e:
                        h.flash(safe_str(e), category='warning')
                        raise HTTPFound(location=h.url('changelog_home', repo_name=repo_name))
                collection = list(reversed(collection))
            else:
                collection = c.db_repo_scm_instance.get_changesets(start=0, end=revision,
                                                        branch_name=branch_name)
            c.total_cs = len(collection)

            c.pagination = RepoPage(collection, page=p, item_count=c.total_cs,
                                    items_per_page=c.size, branch=branch_name,)

            page_revisions = [x.raw_id for x in c.pagination]
            c.comments = c.db_repo.get_comments(page_revisions)
            c.statuses = c.db_repo.statuses(page_revisions)
        except EmptyRepositoryError as e:
            h.flash(safe_str(e), category='warning')
            raise HTTPFound(location=url('summary_home', repo_name=c.repo_name))
        except (RepositoryError, ChangesetDoesNotExistError, Exception) as e:
            log.error(traceback.format_exc())
            h.flash(safe_str(e), category='error')
            raise HTTPFound(location=url('changelog_home', repo_name=c.repo_name))

        c.branch_name = branch_name
        c.branch_filters = [('', _('None'))] + \
            [(k, k) for k in c.db_repo_scm_instance.branches.keys()]
        if c.db_repo_scm_instance.closed_branches:
            prefix = _('(closed)') + ' '
            c.branch_filters += [('-', '-')] + \
                [(k, prefix + k) for k in c.db_repo_scm_instance.closed_branches.keys()]
        revs = []
        if not f_path:
            revs = [x.revision for x in c.pagination]
        c.jsdata = json.dumps(graph_data(c.db_repo_scm_instance, revs))

        c.revision = revision # requested revision ref
        c.first_revision = c.pagination[0] # pagination is never empty here!
        return render('changelog/changelog.html')
Exemplo n.º 47
0
    def compare(self, repo_name, org_ref_type, org_ref_name, other_ref_type, other_ref_name):
        org_ref_name = org_ref_name.strip()
        other_ref_name = other_ref_name.strip()

        org_repo = c.db_repo.repo_name
        other_repo = request.GET.get('other_repo', org_repo)
        # If merge is True:
        #   Show what org would get if merged with other:
        #   List changesets that are ancestors of other but not of org.
        #   New changesets in org is thus ignored.
        #   Diff will be from common ancestor, and merges of org to other will thus be ignored.
        # If merge is False:
        #   Make a raw diff from org to other, no matter if related or not.
        #   Changesets in one and not in the other will be ignored
        merge = bool(request.GET.get('merge'))
        # fulldiff disables cut_off_limit
        c.fulldiff = request.GET.get('fulldiff')
        # partial uses compare_cs.html template directly
        partial = request.environ.get('HTTP_X_PARTIAL_XHR')
        # as_form puts hidden input field with changeset revisions
        c.as_form = partial and request.GET.get('as_form')
        # swap url for compare_diff page - never partial and never as_form
        c.swap_url = h.url('compare_url',
            repo_name=other_repo,
            org_ref_type=other_ref_type, org_ref_name=other_ref_name,
            other_repo=org_repo,
            other_ref_type=org_ref_type, other_ref_name=org_ref_name,
            merge=merge or '')

        # set callbacks for generating markup for icons
        c.ignorews_url = _ignorews_url
        c.context_url = _context_url
        ignore_whitespace = request.GET.get('ignorews') == '1'
        line_context = request.GET.get('context', 3)

        org_repo = Repository.get_by_repo_name(org_repo)
        other_repo = Repository.get_by_repo_name(other_repo)

        if org_repo is None:
            msg = 'Could not find org repo %s' % org_repo
            log.error(msg)
            h.flash(msg, category='error')
            raise HTTPFound(location=url('compare_home', repo_name=c.repo_name))

        if other_repo is None:
            msg = 'Could not find other repo %s' % other_repo
            log.error(msg)
            h.flash(msg, category='error')
            raise HTTPFound(location=url('compare_home', repo_name=c.repo_name))

        if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
            msg = 'compare of two different kind of remote repos not available'
            log.error(msg)
            h.flash(msg, category='error')
            raise HTTPFound(location=url('compare_home', repo_name=c.repo_name))

        c.a_rev = self._get_ref_rev(org_repo, org_ref_type, org_ref_name,
            returnempty=True)
        c.cs_rev = self._get_ref_rev(other_repo, other_ref_type, other_ref_name)

        c.compare_home = False
        c.a_repo = org_repo
        c.a_ref_name = org_ref_name
        c.a_ref_type = org_ref_type
        c.cs_repo = other_repo
        c.cs_ref_name = other_ref_name
        c.cs_ref_type = other_ref_type

        c.cs_ranges, c.cs_ranges_org, c.ancestor = self._get_changesets(
            org_repo.scm_instance.alias, org_repo.scm_instance, c.a_rev,
            other_repo.scm_instance, c.cs_rev)
        raw_ids = [x.raw_id for x in c.cs_ranges]
        c.cs_comments = other_repo.get_comments(raw_ids)
        c.statuses = other_repo.statuses(raw_ids)

        revs = [ctx.revision for ctx in reversed(c.cs_ranges)]
        c.jsdata = json.dumps(graph_data(c.cs_repo.scm_instance, revs))

        if partial:
            return render('compare/compare_cs.html')
        if merge and c.ancestor:
            # case we want a simple diff without incoming changesets,
            # previewing what will be merged.
            # Make the diff on the other repo (which is known to have other_rev)
            log.debug('Using ancestor %s as rev1 instead of %s',
                      c.ancestor, c.a_rev)
            rev1 = c.ancestor
            org_repo = other_repo
        else: # comparing tips, not necessarily linearly related
            if merge:
                log.error('Unable to find ancestor revision')
            if org_repo != other_repo:
                # TODO: we could do this by using hg unionrepo
                log.error('cannot compare across repos %s and %s', org_repo, other_repo)
                h.flash(_('Cannot compare repositories without using common ancestor'), category='error')
                raise HTTPBadRequest
            rev1 = c.a_rev

        diff_limit = self.cut_off_limit if not c.fulldiff else None

        log.debug('running diff between %s and %s in %s',
                  rev1, c.cs_rev, org_repo.scm_instance.path)
        txtdiff = org_repo.scm_instance.get_diff(rev1=rev1, rev2=c.cs_rev,
                                      ignore_whitespace=ignore_whitespace,
                                      context=line_context)

        diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
                                             diff_limit=diff_limit)
        _parsed = diff_processor.prepare()

        c.limited_diff = False
        if isinstance(_parsed, LimitedDiffContainer):
            c.limited_diff = True

        c.files = []
        c.changes = {}
        c.lines_added = 0
        c.lines_deleted = 0
        for f in _parsed:
            st = f['stats']
            if not st['binary']:
                c.lines_added += st['added']
                c.lines_deleted += st['deleted']
            fid = h.FID('', f['filename'])
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
            htmldiff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
            c.changes[fid] = [f['operation'], f['filename'], htmldiff]

        return render('compare/compare_diff.html')
Exemplo n.º 48
0
    def index(self):
        # Return a rendered template
        p = safe_int(request.GET.get('page', 1), 1)
        c.user = User.get(self.authuser.user_id)
        c.following = self.sa.query(UserFollowing)\
            .filter(UserFollowing.user_id == self.authuser.user_id)\
            .options(joinedload(UserFollowing.follows_repository))\
            .all()

        journal = self._get_journal_data(c.following)

        def url_generator(**kw):
            return url.current(filter=c.search_term, **kw)

        c.journal_pager = Page(journal,
                               page=p,
                               items_per_page=20,
                               url=url_generator)
        c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)

        if request.environ.get('HTTP_X_PARTIAL_XHR'):
            return render('journal/journal_data.html')

        repos_list = Session().query(Repository)\
                     .filter(Repository.user_id ==
                             self.authuser.user_id)\
                     .order_by(func.lower(Repository.repo_name)).all()

        repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
                                                   admin=True)
        #json used to render the grid
        c.data = json.dumps(repos_data)

        watched_repos_data = []

        ## watched repos
        _render = RepoModel._render_datatable

        def quick_menu(repo_name):
            return _render('quick_menu', repo_name)

        def repo_lnk(name, rtype, rstate, private, fork_of):
            return _render('repo_name',
                           name,
                           rtype,
                           rstate,
                           private,
                           fork_of,
                           short_name=False,
                           admin=False)

        def last_rev(repo_name, cs_cache):
            return _render('revision', repo_name, cs_cache.get('revision'),
                           cs_cache.get('raw_id'), cs_cache.get('author'),
                           cs_cache.get('message'))

        def desc(desc):
            from pylons import tmpl_context as c
            if c.visual.stylify_metatags:
                return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
            else:
                return h.urlify_text(h.truncate(desc, 60))

        def repo_actions(repo_name):
            return _render('repo_actions', repo_name)

        def owner_actions(user_id, username):
            return _render('user_name', user_id, username)

        def toogle_follow(repo_id):
            return _render('toggle_follow', repo_id)

        for entry in c.following:
            repo = entry.follows_repository
            cs_cache = repo.changeset_cache
            row = {
                "menu":
                quick_menu(repo.repo_name),
                "raw_name":
                repo.repo_name.lower(),
                "name":
                repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state,
                         repo.private, repo.fork),
                "last_changeset":
                last_rev(repo.repo_name, cs_cache),
                "last_rev_raw":
                cs_cache.get('revision'),
                "action":
                toogle_follow(repo.repo_id)
            }

            watched_repos_data.append(row)

        c.watched_data = json.dumps({
            "totalRecords": len(c.following),
            "startIndex": 0,
            "sort": "name",
            "dir": "asc",
            "records": watched_repos_data
        })
        return render('journal/journal.html')
Exemplo n.º 49
0
    def show(self, repo_name, pull_request_id, extra=None):
        repo_model = RepoModel()
        c.users_array = repo_model.get_users_js()
        c.user_groups_array = repo_model.get_user_groups_js()
        c.pull_request = PullRequest.get_or_404(pull_request_id)
        c.allowed_to_change_status = self._get_is_allowed_change_status(
            c.pull_request)
        cc_model = ChangesetCommentsModel()
        cs_model = ChangesetStatusModel()

        # pull_requests repo_name we opened it against
        # ie. other_repo must match
        if repo_name != c.pull_request.other_repo.repo_name:
            raise HTTPNotFound

        # load compare data into template context
        c.cs_repo = c.pull_request.org_repo
        (c.cs_ref_type, c.cs_ref_name,
         c.cs_rev) = c.pull_request.org_ref.split(':')

        c.a_repo = c.pull_request.other_repo
        (c.a_ref_type, c.a_ref_name, c.a_rev) = c.pull_request.other_ref.split(
            ':')  # other_rev is ancestor

        org_scm_instance = c.cs_repo.scm_instance  # property with expensive cache invalidation check!!!
        c.cs_repo = c.cs_repo
        c.cs_ranges = [
            org_scm_instance.get_changeset(x) for x in c.pull_request.revisions
        ]
        c.cs_ranges_org = None  # not stored and not important and moving target - could be calculated ...
        revs = [ctx.revision for ctx in reversed(c.cs_ranges)]
        c.jsdata = json.dumps(graph_data(org_scm_instance, revs))

        avail_revs = set()
        avail_show = []
        c.cs_branch_name = c.cs_ref_name
        other_scm_instance = c.a_repo.scm_instance
        c.update_msg = ""
        c.update_msg_other = ""
        if org_scm_instance.alias == 'hg' and c.a_ref_name != 'ancestor':
            if c.cs_ref_type != 'branch':
                c.cs_branch_name = org_scm_instance.get_changeset(
                    c.cs_ref_name).branch  # use ref_type ?
            c.a_branch_name = c.a_ref_name
            if c.a_ref_type != 'branch':
                try:
                    c.a_branch_name = other_scm_instance.get_changeset(
                        c.a_ref_name).branch  # use ref_type ?
                except EmptyRepositoryError:
                    c.a_branch_name = 'null'  # not a branch name ... but close enough
            # candidates: descendants of old head that are on the right branch
            #             and not are the old head itself ...
            #             and nothing at all if old head is a descendant of target ref name
            if other_scm_instance._repo.revs('present(%s)::&%s',
                                             c.cs_ranges[-1].raw_id,
                                             c.a_branch_name):
                c.update_msg = _(
                    'This pull request has already been merged to %s.'
                ) % c.a_branch_name
            elif c.pull_request.is_closed():
                c.update_msg = _(
                    'This pull request has been closed and can not be updated.'
                )
            else:  # look for descendants of PR head on source branch in org repo
                avail_revs = org_scm_instance._repo.revs(
                    '%s:: & branch(%s)', revs[0], c.cs_branch_name)
                if len(avail_revs) > 1:  # more than just revs[0]
                    # also show changesets that not are descendants but would be merged in
                    targethead = other_scm_instance.get_changeset(
                        c.a_branch_name).raw_id
                    if org_scm_instance.path != other_scm_instance.path:
                        # Note: org_scm_instance.path must come first so all
                        # valid revision numbers are 100% org_scm compatible
                        # - both for avail_revs and for revset results
                        hgrepo = unionrepo.unionrepository(
                            org_scm_instance.baseui, org_scm_instance.path,
                            other_scm_instance.path)
                    else:
                        hgrepo = org_scm_instance._repo
                    show = set(
                        hgrepo.revs('::%ld & !::%s & !::%s', avail_revs,
                                    revs[0], targethead))
                    c.update_msg = _(
                        'This pull request can be updated with changes on %s:'
                    ) % c.cs_branch_name
                else:
                    show = set()
                    c.update_msg = _(
                        'No changesets found for updating this pull request.')

                # TODO: handle branch heads that not are tip-most
                brevs = org_scm_instance._repo.revs('%s - %ld',
                                                    c.cs_branch_name,
                                                    avail_revs)
                if brevs:
                    # also show changesets that are on branch but neither ancestors nor descendants
                    show.update(
                        org_scm_instance._repo.revs('::%ld - ::%ld - ::%s',
                                                    brevs, avail_revs,
                                                    c.a_branch_name))
                    show.add(
                        revs[0]
                    )  # make sure graph shows this so we can see how they relate
                    c.update_msg_other = _(
                        'Note: Branch %s has another head: %s.') % (
                            c.cs_branch_name,
                            h.short_id(
                                org_scm_instance.get_changeset(
                                    (max(brevs))).raw_id))

                avail_show = sorted(show, reverse=True)

        elif org_scm_instance.alias == 'git':
            c.update_msg = _("Git pull requests don't support updates yet.")

        c.avail_revs = avail_revs
        c.avail_cs = [org_scm_instance.get_changeset(r) for r in avail_show]
        c.avail_jsdata = json.dumps(graph_data(org_scm_instance, avail_show))

        raw_ids = [x.raw_id for x in c.cs_ranges]
        c.cs_comments = c.cs_repo.get_comments(raw_ids)
        c.statuses = c.cs_repo.statuses(raw_ids)

        ignore_whitespace = request.GET.get('ignorews') == '1'
        line_context = request.GET.get('context', 3)
        c.ignorews_url = _ignorews_url
        c.context_url = _context_url
        c.fulldiff = request.GET.get('fulldiff')
        diff_limit = self.cut_off_limit if not c.fulldiff else None

        # we swap org/other ref since we run a simple diff on one repo
        log.debug('running diff between %s and %s in %s' %
                  (c.a_rev, c.cs_rev, org_scm_instance.path))
        txtdiff = org_scm_instance.get_diff(
            rev1=safe_str(c.a_rev),
            rev2=safe_str(c.cs_rev),
            ignore_whitespace=ignore_whitespace,
            context=line_context)

        diff_processor = diffs.DiffProcessor(txtdiff or '',
                                             format='gitdiff',
                                             diff_limit=diff_limit)
        _parsed = diff_processor.prepare()

        c.limited_diff = False
        if isinstance(_parsed, LimitedDiffContainer):
            c.limited_diff = True

        c.files = []
        c.changes = {}
        c.lines_added = 0
        c.lines_deleted = 0

        for f in _parsed:
            st = f['stats']
            c.lines_added += st['added']
            c.lines_deleted += st['deleted']
            fid = h.FID('', f['filename'])
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
            htmldiff = diff_processor.as_html(enable_comments=True,
                                              parsed_lines=[f])
            c.changes[fid] = [f['operation'], f['filename'], htmldiff]

        # inline comments
        c.inline_cnt = 0
        c.inline_comments = cc_model.get_inline_comments(
            c.db_repo.repo_id, pull_request=pull_request_id)
        # count inline comments
        for __, lines in c.inline_comments:
            for comments in lines.values():
                c.inline_cnt += len(comments)
        # comments
        c.comments = cc_model.get_comments(c.db_repo.repo_id,
                                           pull_request=pull_request_id)

        # (badly named) pull-request status calculation based on reviewer votes
        (
            c.pull_request_reviewers,
            c.pull_request_pending_reviewers,
            c.current_voting_result,
        ) = cs_model.calculate_pull_request_result(c.pull_request)
        c.changeset_statuses = ChangesetStatus.STATUSES

        c.as_form = False
        c.ancestor = None  # there is one - but right here we don't know which
        return render('/pullrequests/pullrequest_show.html')
Exemplo n.º 50
0
        except JSONRPCError, e:
            self._error = safe_str(e)
        except Exception, e:
            log.error('Encountered unhandled exception: %s' %
                      (traceback.format_exc(), ))
            json_exc = JSONRPCError('Internal server error')
            self._error = safe_str(json_exc)

        if self._error is not None:
            raw_response = None

        response = dict(id=self._req_id,
                        result=raw_response,
                        error=self._error)
        try:
            return json.dumps(response)
        except TypeError, e:
            log.error('API FAILED. Error encoding response: %s' % e)
            return json.dumps(
                dict(id=self._req_id,
                     result=None,
                     error="Error encoding response"))

    def _find_method(self):
        """
        Return method named by `self._req_method` in controller if able
        """
        log.debug('Trying to find JSON-RPC method: %s' % (self._req_method, ))
        if self._req_method.startswith('_'):
            raise AttributeError("Method not allowed")
Exemplo n.º 51
0
def _set_extras(extras):
    # RC_SCM_DATA can probably be removed in the future, but for compatibility now...
    os.environ['KALLITHEA_EXTRAS'] = os.environ['RC_SCM_DATA'] = json.dumps(extras)
Exemplo n.º 52
0
class ChangesetController(BaseRepoController):
    def __before__(self):
        super(ChangesetController, self).__before__()
        c.affected_files_cut_off = 60

    def __load_data(self):
        repo_model = RepoModel()
        c.users_array = repo_model.get_users_js()
        c.user_groups_array = repo_model.get_user_groups_js()

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

        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:
            inlines = []
            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.changeset_comment_id, st.comment
                ) for st in ChangesetStatusModel().get_statuses(
                    c.db_repo.repo_id, changeset.raw_id, with_revisions=True))

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

            c.changes[changeset.raw_id] = []

            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 = 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)
            cs_changes = OrderedDict()
            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']
                    fid = h.FID(changeset.raw_id, f['filename'])
                    diff = diff_processor.as_html(
                        enable_comments=enable_comments, parsed_lines=[f])
                    cs_changes[fid] = [
                        cs1, cs2, f['operation'], f['filename'], diff, st
                    ]
            else:
                # downloads/raw we only need RAW diff nothing else
                diff = diff_processor.as_raw()
                cs_changes[''] = [None, None, None, None, diff, None]
            c.changes[changeset.raw_id] = cs_changes

        #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 = json.dumps(graph_data(c.db_repo_scm_instance, revs))
                return render('changeset/changeset_range.html')
Exemplo n.º 53
0
        except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
            log.error(traceback.format_exc())
            h.flash(safe_str(e), category='error')
            return redirect(url('changelog_home', repo_name=c.repo_name))

        c.branch_name = branch_name
        c.branch_filters = [('', _('None'))] + \
            [(k, k) for k in c.db_repo_scm_instance.branches.keys()]
        if c.db_repo_scm_instance.closed_branches:
            prefix = _('(closed)') + ' '
            c.branch_filters += [('-', '-')] + \
                [(k, prefix + k) for k in c.db_repo_scm_instance.closed_branches.keys()]
        revs = []
        if not f_path:
            revs = [x.revision for x in c.pagination]
        c.jsdata = json.dumps(graph_data(c.db_repo_scm_instance, revs))

        c.revision = revision # requested revision ref
        c.first_revision = c.pagination[0] # pagination is never empty here!
        return render('changelog/changelog.html')

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                   'repository.admin')
    def changelog_details(self, cs):
        if request.environ.get('HTTP_X_PARTIAL_XHR'):
            c.cs = c.db_repo_scm_instance.get_changeset(cs)
            return render('changelog/changelog_details.html')
        raise HTTPNotFound()

    @LoginRequired()