Blame progit/app.py

Pierre-Yves Chibon 2088eb
#-*- coding: utf-8 -*-
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
"""
Pierre-Yves Chibon 2088eb
 (c) 2014 - Copyright Red Hat Inc
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
 Authors:
Pierre-Yves Chibon 2088eb
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
"""
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
import flask
Pierre-Yves Chibon 2088eb
import os
Pierre-Yves Chibon c55274
import tempfile
Pierre-Yves Chibon 2088eb
from math import ceil
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
import pygit2
Pierre-Yves Chibon 2088eb
from sqlalchemy.exc import SQLAlchemyError
Pierre-Yves Chibon 2088eb
from pygments import highlight
Pierre-Yves Chibon 2088eb
from pygments.lexers import guess_lexer
Pierre-Yves Chibon 2088eb
from pygments.lexers.text import DiffLexer
Pierre-Yves Chibon 2088eb
from pygments.formatters import HtmlFormatter
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 8a621f
import progit.exceptions
Pierre-Yves Chibon 8a621f
import progit.lib
Pierre-Yves Chibon 8a621f
import progit.forms
Pierre-Yves Chibon d8f19f
from progit import APP, SESSION, LOG, __get_file_in_tree
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
### Application
Pierre-Yves Chibon ac8023
def view_repo(repo, username=None):
Pierre-Yves Chibon 2088eb
    """ Front page of a specific repo.
Pierre-Yves Chibon 2088eb
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Mathieu Bridon 998605
Mathieu Bridon 998605
    if repo is None:
Pierre-Yves Chibon 2088eb
        flask.abort(404)
Mathieu Bridon 998605
Pierre-Yves Chibon ac8023
    reponame = os.path.join(APP.config['GIT_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        reponame = os.path.join(APP.config['FORK_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    repo_obj = pygit2.Repository(reponame)
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    cnt = 0
Pierre-Yves Chibon 2088eb
    last_commits = []
Pierre-Yves Chibon 0fa300
    tree = []
Pierre-Yves Chibon 0fa300
    if not repo_obj.is_empty:
Pierre-Yves Chibon cbf031
        for commit in repo_obj.walk(
Pierre-Yves Chibon cbf031
                repo_obj.head.target, pygit2.GIT_SORT_TIME):
Pierre-Yves Chibon 0fa300
            last_commits.append(commit)
Pierre-Yves Chibon 0fa300
            cnt += 1
Pierre-Yves Chibon 0fa300
            if cnt == 10:
Pierre-Yves Chibon 0fa300
                break
Pierre-Yves Chibon 0fa300
        tree = sorted(last_commits[0].tree, key=lambda x: x.filemode)
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 9ddb30
    readme = None
Pierre-Yves Chibon 9ddb30
    for i in tree:
Pierre-Yves Chibon 9ddb30
        name, ext = os.path.splitext(i.name)
Pierre-Yves Chibon 9ddb30
        if name == 'README':
Pierre-Yves Chibon 9ddb30
            content = repo_obj[i.oid].data
Pierre-Yves Chibon 9ddb30
            readme = progit.doc_utils.convert_readme(content, ext)
Pierre-Yves Chibon 9ddb30
Pierre-Yves Chibon ac8023
    diff_commits = []
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        parentname = os.path.join(
Pierre-Yves Chibon ac8023
            APP.config['GIT_FOLDER'], repo.parent.path)
Pierre-Yves Chibon ac8023
        orig_repo = pygit2.Repository(parentname)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
        if not repo_obj.is_empty and not orig_repo.is_empty:
Pierre-Yves Chibon ac8023
            orig_commit = orig_repo[orig_repo.head.target]
Pierre-Yves Chibon ac8023
            repo_commit = repo_obj[repo_obj.head.target]
Pierre-Yves Chibon ac8023
            diff = repo_obj.diff(
Pierre-Yves Chibon ac8023
                repo_obj.revparse_single(orig_commit.oid.hex),
Pierre-Yves Chibon ac8023
                repo_obj.revparse_single(repo_commit.oid.hex))
Pierre-Yves Chibon ac8023
            for commit in repo_obj.walk(
Pierre-Yves Chibon ac8023
                    repo_obj.head.target, pygit2.GIT_SORT_TIME):
Pierre-Yves Chibon ac8023
                if commit.oid.hex == orig_commit.oid.hex:
Pierre-Yves Chibon ac8023
                    break
Pierre-Yves Chibon ac8023
                diff_commits.append(commit.oid.hex)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon 2088eb
    return flask.render_template(
Pierre-Yves Chibon 2088eb
        'repo_info.html',
Pierre-Yves Chibon 150913
        select='overview',
Pierre-Yves Chibon 2088eb
        repo=repo,
Pierre-Yves Chibon 226b9c
        repo_obj=repo_obj,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon 9ddb30
        readme=readme,
Pierre-Yves Chibon f3dba9
        branches=sorted(repo_obj.listall_branches()),
Pierre-Yves Chibon 2088eb
        branchname='master',
Pierre-Yves Chibon 2088eb
        last_commits=last_commits,
Pierre-Yves Chibon 0fa300
        tree=tree,
Pierre-Yves Chibon ac8023
        diff_commits=diff_commits,
Pierre-Yves Chibon 2088eb
    )
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon ac8023
def view_repo_branch(repo, branchname, username=None):
Pierre-Yves Chibon 2088eb
    """ Displays the information about a specific branch.
Pierre-Yves Chibon 2088eb
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Mathieu Bridon bdddc1
Pierre-Yves Chibon ac8023
    if not repo:
Pierre-Yves Chibon 2088eb
        flask.abort(404)
Mathieu Bridon bdddc1
Pierre-Yves Chibon ac8023
    reponame = os.path.join(APP.config['GIT_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        reponame = os.path.join(APP.config['FORK_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    repo_obj = pygit2.Repository(reponame)
Mathieu Bridon bdddc1
Pierre-Yves Chibon 2088eb
    if not branchname in repo_obj.listall_branches():
Pierre-Yves Chibon 2088eb
        flask.abort(404)
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    branch = repo_obj.lookup_branch(branchname)
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    cnt = 0
Pierre-Yves Chibon 2088eb
    last_commits = []
Pierre-Yves Chibon 2088eb
    for commit in repo_obj.walk(branch.get_object().hex, pygit2.GIT_SORT_TIME):
Pierre-Yves Chibon 2088eb
        last_commits.append(commit)
Pierre-Yves Chibon 2088eb
        cnt += 1
Pierre-Yves Chibon 2088eb
        if cnt == 10:
Pierre-Yves Chibon 2088eb
            break
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon ac8023
    diff_commits = []
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        parentname = os.path.join(
Pierre-Yves Chibon ac8023
            APP.config['GIT_FOLDER'], repo.parent.path)
Pierre-Yves Chibon ac8023
        orig_repo = pygit2.Repository(parentname)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
        if not repo_obj.is_empty and not orig_repo.is_empty:
Pierre-Yves Chibon ac8023
            orig_commit = orig_repo[orig_repo.head.target]
Pierre-Yves Chibon ac8023
            repo_commit = repo_obj[branch.get_object().hex]
Pierre-Yves Chibon ac8023
            diff = repo_obj.diff(
Pierre-Yves Chibon ac8023
                repo_obj.revparse_single(orig_commit.oid.hex),
Pierre-Yves Chibon ac8023
                repo_obj.revparse_single(repo_commit.oid.hex))
Pierre-Yves Chibon ac8023
            for commit in repo_obj.walk(
Pierre-Yves Chibon ac8023
                    repo_obj.head.target, pygit2.GIT_SORT_TIME):
Pierre-Yves Chibon ac8023
                if commit.oid.hex == orig_commit.oid.hex:
Pierre-Yves Chibon ac8023
                    break
Pierre-Yves Chibon ac8023
                diff_commits.append(commit.oid.hex)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon 2088eb
    return flask.render_template(
Pierre-Yves Chibon 2088eb
        'repo_info.html',
Pierre-Yves Chibon 150913
        select='overview',
Pierre-Yves Chibon 2088eb
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon 18d24c
        branches=sorted(repo_obj.listall_branches()),
Pierre-Yves Chibon 2088eb
        branchname=branchname,
Pierre-Yves Chibon 2088eb
        last_commits=last_commits,
Pierre-Yves Chibon 2088eb
        tree=sorted(last_commits[0].tree, key=lambda x: x.filemode),
Pierre-Yves Chibon ac8023
        diff_commits=diff_commits,
Pierre-Yves Chibon 2088eb
    )
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 6428d8
Pierre-Yves Chibon ac8023
def view_log(repo, branchname=None, username=None):
Pierre-Yves Chibon 2088eb
    """ Displays the logs of the specified repo.
Pierre-Yves Chibon 2088eb
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Mathieu Bridon ba640f
Pierre-Yves Chibon ac8023
    if not repo:
Pierre-Yves Chibon 2088eb
        flask.abort(404)
Mathieu Bridon ba640f
Pierre-Yves Chibon ac8023
    reponame = os.path.join(APP.config['GIT_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        reponame = os.path.join(APP.config['FORK_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    repo_obj = pygit2.Repository(reponame)
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon b0c4da
    if branchname and not branchname in repo_obj.listall_branches():
Pierre-Yves Chibon b0c4da
        flask.abort(404)
Pierre-Yves Chibon b0c4da
Pierre-Yves Chibon ac8023
    if branchname:
Pierre-Yves Chibon ac8023
        branch = repo_obj.lookup_branch(branchname)
Pierre-Yves Chibon ac8023
    else:
Pierre-Yves Chibon ac8023
        branch = repo_obj.lookup_branch('master')
Pierre-Yves Chibon b0c4da
Pierre-Yves Chibon 2088eb
    try:
Pierre-Yves Chibon 2088eb
        page = int(flask.request.args.get('page', 1))
Pierre-Yves Chibon 2088eb
    except ValueError:
Pierre-Yves Chibon 2088eb
        page = 1
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    limit = APP.config['ITEM_PER_PAGE']
Pierre-Yves Chibon 2088eb
    start = limit * (page - 1)
Pierre-Yves Chibon 2088eb
    end = limit * page
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    n_commits = 0
Pierre-Yves Chibon 2088eb
    last_commits = []
Pierre-Yves Chibon 2088eb
    for commit in repo_obj.walk(
Pierre-Yves Chibon b0c4da
            branch.get_object().hex, pygit2.GIT_SORT_TIME):
Pierre-Yves Chibon 2088eb
        if n_commits >= start and n_commits <= end:
Pierre-Yves Chibon 2088eb
            last_commits.append(commit)
Pierre-Yves Chibon 2088eb
        n_commits += 1
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    total_page = int(ceil(n_commits / float(limit)))
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon ac8023
    diff_commits = []
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        parentname = os.path.join(
Pierre-Yves Chibon ac8023
            APP.config['GIT_FOLDER'], repo.parent.path)
Pierre-Yves Chibon ac8023
        orig_repo = pygit2.Repository(parentname)
Pierre-Yves Chibon ac8023
        if not repo_obj.is_empty and not orig_repo.is_empty:
Pierre-Yves Chibon ac8023
            orig_commit = orig_repo[orig_repo.head.target]
Pierre-Yves Chibon ac8023
            repo_commit = repo_obj[branch.get_object().hex]
Pierre-Yves Chibon ac8023
            diff = repo_obj.diff(
Pierre-Yves Chibon ac8023
                repo_obj.revparse_single(orig_commit.oid.hex),
Pierre-Yves Chibon ac8023
                repo_obj.revparse_single(repo_commit.oid.hex))
Pierre-Yves Chibon ac8023
            for commit in repo_obj.walk(
Pierre-Yves Chibon ac8023
                    repo_obj.head.target, pygit2.GIT_SORT_TIME):
Pierre-Yves Chibon ac8023
                if commit.oid.hex == orig_commit.oid.hex:
Pierre-Yves Chibon ac8023
                    break
Pierre-Yves Chibon ac8023
                diff_commits.append(commit.oid.hex)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon bd2213
    origin = 'view_log'
Pierre-Yves Chibon bd2213
    if username:
Pierre-Yves Chibon bd2213
        origin = 'view_fork_log'
Pierre-Yves Chibon bd2213
Pierre-Yves Chibon 2088eb
    return flask.render_template(
Pierre-Yves Chibon 2088eb
        'repo_info.html',
Pierre-Yves Chibon 150913
        select='logs',
Pierre-Yves Chibon bd2213
        origin=origin,
Pierre-Yves Chibon 2088eb
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon 18d24c
        branches=sorted(repo_obj.listall_branches()),
Pierre-Yves Chibon 2088eb
        branchname=branchname,
Pierre-Yves Chibon 2088eb
        last_commits=last_commits,
Pierre-Yves Chibon ac8023
        diff_commits=diff_commits,
Pierre-Yves Chibon 2088eb
        page=page,
Pierre-Yves Chibon 2088eb
        total_page=total_page,
Pierre-Yves Chibon 2088eb
    )
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon ac8023
def view_file(repo, identifier, filename, username=None):
Pierre-Yves Chibon 2088eb
    """ Displays the content of a file or a tree for the specified repo.
Pierre-Yves Chibon 2088eb
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Mathieu Bridon 4c73b0
Pierre-Yves Chibon ac8023
    if not repo:
Pierre-Yves Chibon 5a3b73
        flask.abort(404)
Mathieu Bridon 4c73b0
Pierre-Yves Chibon ac8023
    reponame = os.path.join(APP.config['GIT_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        reponame = os.path.join(APP.config['FORK_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    repo_obj = pygit2.Repository(reponame)
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    if identifier in repo_obj.listall_branches():
Pierre-Yves Chibon 2088eb
        branchname = identifier
Pierre-Yves Chibon 2088eb
        branch = repo_obj.lookup_branch(identifier)
Pierre-Yves Chibon 2088eb
        commit = branch.get_object()
Pierre-Yves Chibon 2088eb
    else:
Pierre-Yves Chibon 2088eb
        try:
Pierre-Yves Chibon 2d4003
            commit = repo_obj.get(identifier)
Pierre-Yves Chibon 2d4003
            branchname = identifier
Pierre-Yves Chibon 2088eb
        except ValueError:
Pierre-Yves Chibon 2088eb
            # If it's not a commit id then it's part of the filename
Pierre-Yves Chibon 2088eb
            commit = repo_obj[repo_obj.head.target]
Pierre-Yves Chibon 6428d8
            branchname = 'master'
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon d8f19f
    content = __get_file_in_tree(repo_obj, commit.tree, filename.split('/'))
Pierre-Yves Chibon 2088eb
    if not content:
Pierre-Yves Chibon 2088eb
        flask.abort(404, 'File not found')
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    content = repo_obj[content.oid]
Pierre-Yves Chibon 2088eb
    if isinstance(content, pygit2.Blob):
Pierre-Yves Chibon 2088eb
        content = highlight(
Pierre-Yves Chibon 2088eb
            content.data,
Pierre-Yves Chibon 2088eb
            guess_lexer(content.data),
Pierre-Yves Chibon 2088eb
            HtmlFormatter(
Pierre-Yves Chibon 2088eb
                noclasses=True,
Pierre-Yves Chibon 2088eb
                style="tango",)
Pierre-Yves Chibon 2088eb
        )
Pierre-Yves Chibon 2088eb
        output_type = 'file'
Pierre-Yves Chibon 2088eb
    else:
Pierre-Yves Chibon 6428d8
        content = sorted(content, key=lambda x: x.filemode)
Pierre-Yves Chibon 2088eb
        output_type = 'tree'
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    return flask.render_template(
Pierre-Yves Chibon 2088eb
        'file.html',
Pierre-Yves Chibon 150913
        select='tree',
Pierre-Yves Chibon 2088eb
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon 2088eb
        branchname=branchname,
Pierre-Yves Chibon 2088eb
        filename=filename,
Pierre-Yves Chibon 2088eb
        content=content,
Pierre-Yves Chibon 2088eb
        output_type=output_type,
Pierre-Yves Chibon 2088eb
    )
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 84f83a
Pierre-Yves Chibon ac8023
def view_commit(repo, commitid, username=None):
Pierre-Yves Chibon 2088eb
    """ Render a commit in a repo
Pierre-Yves Chibon 2088eb
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Mathieu Bridon eaccc4
Pierre-Yves Chibon ac8023
    if not repo:
Pierre-Yves Chibon 2088eb
        flask.abort(404)
Mathieu Bridon eaccc4
Pierre-Yves Chibon ac8023
    reponame = os.path.join(APP.config['GIT_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        reponame = os.path.join(APP.config['FORK_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    repo_obj = pygit2.Repository(reponame)
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    try:
Pierre-Yves Chibon 2088eb
        commit = repo_obj.get(commitid)
Pierre-Yves Chibon 2088eb
    except ValueError:
Pierre-Yves Chibon 2088eb
        flask.abort(404)
Pierre-Yves Chibon 84f83a
Pierre-Yves Chibon 84f83a
    if commit.parents:
Pierre-Yves Chibon 84f83a
        diff = commit.tree.diff_to_tree()
Pierre-Yves Chibon 84f83a
Pierre-Yves Chibon 84f83a
        parent = repo_obj.revparse_single('%s^' % commitid)
Pierre-Yves Chibon 84f83a
        diff = repo_obj.diff(parent, commit)
Pierre-Yves Chibon 84f83a
    else:
Pierre-Yves Chibon 84f83a
        # First commit in the repo
Pierre-Yves Chibon 84f83a
        diff = commit.tree.diff_to_tree(swap=True)
Pierre-Yves Chibon 84f83a
Pierre-Yves Chibon 2088eb
    html_diff = highlight(
Pierre-Yves Chibon 2088eb
        diff.patch,
Pierre-Yves Chibon 2088eb
        DiffLexer(),
Pierre-Yves Chibon 2088eb
        HtmlFormatter(
Pierre-Yves Chibon 2088eb
            noclasses=True,
Pierre-Yves Chibon 2088eb
            style="tango",)
Pierre-Yves Chibon 2088eb
    )
Pierre-Yves Chibon 2088eb
Pierre-Yves Chibon 2088eb
    return flask.render_template(
Pierre-Yves Chibon 2088eb
        'commit.html',
Pierre-Yves Chibon 150913
        select='logs',
Pierre-Yves Chibon 2088eb
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon 2088eb
        commitid=commitid,
Pierre-Yves Chibon 2088eb
        commit=commit,
Pierre-Yves Chibon 2088eb
        diff=diff,
Pierre-Yves Chibon 2088eb
        html_diff=html_diff,
Pierre-Yves Chibon 2088eb
    )
Pierre-Yves Chibon 12e862
Pierre-Yves Chibon 12e862
Pierre-Yves Chibon ac8023
def view_tree(repo, identifier=None, username=None):
Pierre-Yves Chibon 12e862
    """ Render the tree of the repo
Pierre-Yves Chibon 12e862
    """
Mathieu Bridon 6dd1b4
    repo = progit.lib.get_project(SESSION, repo)
Mathieu Bridon 6dd1b4
Mathieu Bridon 6dd1b4
    if repo is None:
Pierre-Yves Chibon 12e862
        flask.abort(404)
Mathieu Bridon 6dd1b4
Pierre-Yves Chibon ac8023
    reponame = os.path.join(APP.config['GIT_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    if repo.is_fork:
Pierre-Yves Chibon ac8023
        reponame = os.path.join(APP.config['FORK_FOLDER'], repo.path)
Pierre-Yves Chibon ac8023
    repo_obj = pygit2.Repository(reponame)
Pierre-Yves Chibon 12e862
Pierre-Yves Chibon 12e862
    if identifier in repo_obj.listall_branches():
Pierre-Yves Chibon 12e862
        branchname = identifier
Pierre-Yves Chibon 12e862
        branch = repo_obj.lookup_branch(identifier)
Pierre-Yves Chibon 12e862
        commit = branch.get_object()
Pierre-Yves Chibon 12e862
    else:
Pierre-Yves Chibon 12e862
        try:
Pierre-Yves Chibon 12e862
            commit = repo_obj.get(identifier)
Pierre-Yves Chibon 12e862
            branchname = identifier
Pierre-Yves Chibon 12e862
        except (ValueError, TypeError):
Pierre-Yves Chibon 12e862
            # If it's not a commit id then it's part of the filename
Pierre-Yves Chibon 12e862
            commit = repo_obj[repo_obj.head.target]
Pierre-Yves Chibon 2f9532
            branchname = 'master'
Pierre-Yves Chibon 12e862
Pierre-Yves Chibon 6428d8
    content = sorted(commit.tree, key=lambda x: x.filemode)
Pierre-Yves Chibon 12e862
    output_type = 'tree'
Pierre-Yves Chibon 12e862
Pierre-Yves Chibon 12e862
    return flask.render_template(
Pierre-Yves Chibon 12e862
        'file.html',
Pierre-Yves Chibon 150913
        select='tree',
Pierre-Yves Chibon 12e862
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon 12e862
        branchname=branchname,
Pierre-Yves Chibon 12e862
        filename='',
Pierre-Yves Chibon 12e862
        content=content,
Pierre-Yves Chibon 12e862
        output_type=output_type,
Pierre-Yves Chibon 12e862
    )
Pierre-Yves Chibon eb2817
Pierre-Yves Chibon eb2817
Pierre-Yves Chibon ac8023
def view_issues(repo, username=None):
Pierre-Yves Chibon eb2817
    """ List all issues associated to a repo
Pierre-Yves Chibon eb2817
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon eb2817
Pierre-Yves Chibon eb2817
    if repo is None:
Pierre-Yves Chibon eb2817
        flask.abort(404)
Pierre-Yves Chibon eb2817
Pierre-Yves Chibon 455999
    issues = progit.lib.get_issues(SESSION, repo, status='Open')
Pierre-Yves Chibon eb2817
Pierre-Yves Chibon eb2817
    return flask.render_template(
Pierre-Yves Chibon eb2817
        'issues.html',
Pierre-Yves Chibon eb2817
        select='issues',
Pierre-Yves Chibon eb2817
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon eb2817
        issues=issues,
Pierre-Yves Chibon eb2817
    )
Pierre-Yves Chibon a204a8
Pierre-Yves Chibon a204a8
Pierre-Yves Chibon ac8023
def new_issue(repo, username=None):
Pierre-Yves Chibon a204a8
    """ Create a new issue
Pierre-Yves Chibon a204a8
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon a204a8
Pierre-Yves Chibon a204a8
    if repo is None:
Pierre-Yves Chibon a204a8
        flask.abort(404, 'Project not found')
Pierre-Yves Chibon a204a8
Pierre-Yves Chibon a204a8
    form = progit.forms.IssueForm()
Pierre-Yves Chibon a204a8
    if form.validate_on_submit():
Pierre-Yves Chibon a204a8
        title = form.title.data
Pierre-Yves Chibon a204a8
        content = form.content.data
Pierre-Yves Chibon a204a8
Pierre-Yves Chibon a204a8
        try:
Pierre-Yves Chibon a204a8
            message = progit.lib.new_issue(
Pierre-Yves Chibon a204a8
                SESSION,
Pierre-Yves Chibon a204a8
                repo=repo,
Pierre-Yves Chibon a204a8
                title=title,
Pierre-Yves Chibon a204a8
                content=content,
Pierre-Yves Chibon a204a8
                user=flask.g.fas_user.username,
Pierre-Yves Chibon a204a8
            )
Pierre-Yves Chibon a204a8
            SESSION.commit()
Pierre-Yves Chibon a204a8
            flask.flash(message)
Pierre-Yves Chibon a204a8
            return flask.redirect(flask.url_for(
Pierre-Yves Chibon ac8023
                'view_fork_issues', username=username, repo=repo.name))
Pierre-Yves Chibon a204a8
        except progit.exceptions.ProgitException, err:
Pierre-Yves Chibon a204a8
            flask.flash(str(err), 'error')
Pierre-Yves Chibon a204a8
        except SQLAlchemyError, err:  # pragma: no cover
Pierre-Yves Chibon a204a8
            SESSION.rollback()
Pierre-Yves Chibon a204a8
            flask.flash(str(err), 'error')
Pierre-Yves Chibon a204a8
Pierre-Yves Chibon a204a8
    return flask.render_template(
Pierre-Yves Chibon a204a8
        'new_issue.html',
Pierre-Yves Chibon a204a8
        select='issues',
Pierre-Yves Chibon a204a8
        form=form,
Pierre-Yves Chibon a204a8
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon a204a8
    )
Pierre-Yves Chibon 8f1224
Pierre-Yves Chibon 8f1224
Pierre-Yves Chibon ac8023
def view_issue(repo, issueid, username=None):
Pierre-Yves Chibon 8f1224
    """ List all issues associated to a repo
Pierre-Yves Chibon 8f1224
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon 8f1224
Pierre-Yves Chibon 8f1224
    if repo is None:
Pierre-Yves Chibon 8f1224
        flask.abort(404, 'Project not found')
Pierre-Yves Chibon 8f1224
Pierre-Yves Chibon 8f1224
    issue = progit.lib.get_issue(SESSION, issueid)
Pierre-Yves Chibon 8f1224
Pierre-Yves Chibon 8f1224
    if issue is None:
Pierre-Yves Chibon 8f1224
        flask.abort(404, 'Issue not found')
Pierre-Yves Chibon 8f1224
Pierre-Yves Chibon 8f1224
    return flask.render_template(
Pierre-Yves Chibon 8f1224
        'issue.html',
Pierre-Yves Chibon 8f1224
        select='issues',
Pierre-Yves Chibon 8f1224
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon 8f1224
        issue=issue,
Pierre-Yves Chibon 8f1224
    )
Pierre-Yves Chibon 542ff6
Pierre-Yves Chibon f4d831
Pierre-Yves Chibon ac8023
def edit_issue(repo, issueid, username=None):
Pierre-Yves Chibon 542ff6
    """ Edit the specified issue
Pierre-Yves Chibon 542ff6
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon 542ff6
Pierre-Yves Chibon 542ff6
    if repo is None:
Pierre-Yves Chibon 542ff6
        flask.abort(404, 'Project not found')
Pierre-Yves Chibon 542ff6
Pierre-Yves Chibon 542ff6
    issue = progit.lib.get_issue(SESSION, issueid)
Pierre-Yves Chibon 542ff6
Pierre-Yves Chibon 542ff6
    if issue is None:
Pierre-Yves Chibon 542ff6
        flask.abort(404, 'Issue not found')
Pierre-Yves Chibon 542ff6
Pierre-Yves Chibon 9dbe63
    status = progit.lib.get_issue_statuses(SESSION)
Pierre-Yves Chibon 9dbe63
    form = progit.forms.IssueForm(status=status)
Pierre-Yves Chibon 542ff6
    if form.validate_on_submit():
Pierre-Yves Chibon 542ff6
        title = form.title.data
Pierre-Yves Chibon 542ff6
        content = form.content.data
Pierre-Yves Chibon 9dbe63
        status = form.status.data
Pierre-Yves Chibon 542ff6
Pierre-Yves Chibon 542ff6
        try:
Pierre-Yves Chibon 542ff6
            message = progit.lib.edit_issue(
Pierre-Yves Chibon 542ff6
                SESSION,
Pierre-Yves Chibon 542ff6
                issue=issue,
Pierre-Yves Chibon 542ff6
                title=title,
Pierre-Yves Chibon 542ff6
                content=content,
Pierre-Yves Chibon 9dbe63
                status=status,
Pierre-Yves Chibon 542ff6
            )
Pierre-Yves Chibon 542ff6
            SESSION.commit()
Pierre-Yves Chibon 542ff6
            flask.flash(message)
Pierre-Yves Chibon 9dbe63
            url = flask.url_for('view_issues', repo=repo.name)
Pierre-Yves Chibon 9dbe63
            if username:
Pierre-Yves Chibon 9dbe63
                url = flask.url_for(
Pierre-Yves Chibon 9dbe63
                    'view_fork_issues', username=username, repo=repo.name)
Pierre-Yves Chibon 9dbe63
            return flask.redirect(url)
Pierre-Yves Chibon 542ff6
        except progit.exceptions.ProgitException, err:
Pierre-Yves Chibon 542ff6
            flask.flash(str(err), 'error')
Pierre-Yves Chibon 542ff6
        except SQLAlchemyError, err:  # pragma: no cover
Pierre-Yves Chibon 542ff6
            SESSION.rollback()
Pierre-Yves Chibon 542ff6
            flask.flash(str(err), 'error')
Pierre-Yves Chibon 542ff6
    elif flask.request.method == 'GET':
Pierre-Yves Chibon 542ff6
        form.title.data = issue.title
Pierre-Yves Chibon 542ff6
        form.content.data = issue.content
Pierre-Yves Chibon 9dbe63
        form.status.data = issue.status
Pierre-Yves Chibon 542ff6
Pierre-Yves Chibon 542ff6
    return flask.render_template(
Pierre-Yves Chibon 542ff6
        'new_issue.html',
Pierre-Yves Chibon 542ff6
        select='issues',
Pierre-Yves Chibon 542ff6
        type='edit',
Pierre-Yves Chibon 542ff6
        form=form,
Pierre-Yves Chibon 542ff6
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username,
Pierre-Yves Chibon 542ff6
        issue=issue,
Pierre-Yves Chibon 542ff6
    )
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon c30d42
def request_pulls(repo, username=None):
Pierre-Yves Chibon c30d42
    """ Returns the list of pull-requests opened on a project.
Pierre-Yves Chibon c30d42
    """
Pierre-Yves Chibon c30d42
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon c30d42
Pierre-Yves Chibon c30d42
    if not repo:
Pierre-Yves Chibon c30d42
        flask.abort(404, 'Project not found')
Pierre-Yves Chibon c30d42
Pierre-Yves Chibon c30d42
    requests = progit.lib.get_pull_requests(
Pierre-Yves Chibon c30d42
        SESSION, project_id=repo.id, status=True)
Pierre-Yves Chibon c30d42
Pierre-Yves Chibon c30d42
    return flask.render_template(
Pierre-Yves Chibon c30d42
        'requests.html',
Pierre-Yves Chibon c30d42
        select='requests',
Pierre-Yves Chibon c30d42
        repo=repo,
Pierre-Yves Chibon c30d42
        username=username,
Pierre-Yves Chibon c30d42
        requests=requests,
Pierre-Yves Chibon c30d42
    )
Pierre-Yves Chibon c30d42
Pierre-Yves Chibon c30d42
Pierre-Yves Chibon 40f54b
def request_pull(repo, requestid, username=None):
Pierre-Yves Chibon ac8023
    """ Request pulling the changes from the fork into the project.
Pierre-Yves Chibon ac8023
    """
Pierre-Yves Chibon ac8023
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    if not repo:
Pierre-Yves Chibon ac8023
        flask.abort(404, 'Project not found')
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    request = progit.lib.get_pull_request(
Pierre-Yves Chibon ac8023
        SESSION, project_id=repo.id, requestid=requestid)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    if not request:
Pierre-Yves Chibon ac8023
        flask.abort(404, 'Pull-request not found')
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    repopath = os.path.join(
Pierre-Yves Chibon ac8023
        APP.config['FORK_FOLDER'], request.repo_from.path)
Pierre-Yves Chibon ac8023
    repo_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    parentname = os.path.join(
Pierre-Yves Chibon ac8023
        APP.config['GIT_FOLDER'], request.repo.path)
Pierre-Yves Chibon ac8023
    orig_repo = pygit2.Repository(parentname)
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    diff_commits = []
Pierre-Yves Chibon ac8023
    diffs = []
Pierre-Yves Chibon ac8023
    repo_commit = repo_obj[request.stop_id]
Pierre-Yves Chibon ac8023
    if not repo_obj.is_empty and not orig_repo.is_empty:
Pierre-Yves Chibon ac8023
        orig_commit = orig_repo[request.start_id]
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
        for commit in repo_obj.walk(request.stop_id, pygit2.GIT_SORT_TIME):
Pierre-Yves Chibon ac8023
            if commit.oid.hex == orig_commit.oid.hex:
Pierre-Yves Chibon ac8023
                break
Pierre-Yves Chibon ac8023
            diff_commits.append(commit)
Pierre-Yves Chibon ac8023
            diffs.append(
Pierre-Yves Chibon ac8023
                repo_obj.diff(
Pierre-Yves Chibon ac8023
                    repo_obj.revparse_single(commit.parents[0].oid.hex),
Pierre-Yves Chibon ac8023
                    repo_obj.revparse_single(commit.oid.hex)
Pierre-Yves Chibon ac8023
                )
Pierre-Yves Chibon ac8023
            )
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    elif orig_repo.is_empty:
Pierre-Yves Chibon ac8023
        orig_commit = None
Pierre-Yves Chibon ac8023
        diff = repo_commit.tree.diff_to_tree(swap=True)
Pierre-Yves Chibon ac8023
    else:
Pierre-Yves Chibon ac8023
        flask.flash(
Pierre-Yves Chibon ac8023
            'Fork is empty, there are no commits to request pulling',
Pierre-Yves Chibon ac8023
            'error')
Pierre-Yves Chibon ac8023
        return flask.redirect(flask.url_for(
Pierre-Yves Chibon ac8023
            'view_fork_repo', username=username, repo=repo.name))
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    html_diffs = []
Pierre-Yves Chibon ac8023
    for diff in diffs:
Pierre-Yves Chibon ac8023
        html_diffs.append(
Pierre-Yves Chibon ac8023
            highlight(
Pierre-Yves Chibon ac8023
                diff.patch,
Pierre-Yves Chibon ac8023
                DiffLexer(),
Pierre-Yves Chibon ac8023
                HtmlFormatter(
Pierre-Yves Chibon ac8023
                    noclasses=True,
Pierre-Yves Chibon ac8023
                    style="tango",)
Pierre-Yves Chibon ac8023
            )
Pierre-Yves Chibon ac8023
        )
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon ac8023
    return flask.render_template(
Pierre-Yves Chibon ac8023
        'pull_request.html',
Pierre-Yves Chibon c30d42
        select='requests',
Pierre-Yves Chibon ac8023
        repo=repo,
Pierre-Yves Chibon ac8023
        username=username or request.user,
Pierre-Yves Chibon ac8023
        request=request,
Pierre-Yves Chibon ac8023
        repo_obj=repo_obj,
Pierre-Yves Chibon ac8023
        orig_repo=orig_repo,
Pierre-Yves Chibon ac8023
        diff_commits=diff_commits,
Pierre-Yves Chibon ac8023
        diffs=diffs,
Pierre-Yves Chibon ac8023
        html_diffs=html_diffs,
Pierre-Yves Chibon ac8023
    )
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
def merge_request_pull(repo, requestid, username=None):
Pierre-Yves Chibon c55274
    """ Merge a request pulling the changes from the fork into the project.
Pierre-Yves Chibon c55274
    """
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    if not repo:
Pierre-Yves Chibon c55274
        flask.abort(404, 'Project not found')
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    request = progit.lib.get_pull_request(
Pierre-Yves Chibon c55274
        SESSION, project_id=repo.id, requestid=requestid)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    if not request:
Pierre-Yves Chibon c55274
        flask.abort(404, 'Pull-request not found')
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    error_output = flask.url_for(
Pierre-Yves Chibon c55274
        'request_pull', repo=repo.name, requestid=requestid)
Pierre-Yves Chibon c55274
    if username:
Pierre-Yves Chibon c55274
        error_output = flask.url_for(
Pierre-Yves Chibon 792a86
            'fork_request_pull',
Pierre-Yves Chibon 792a86
            repo=repo.name,
Pierre-Yves Chibon 792a86
            requestid=requestid,
Pierre-Yves Chibon 792a86
            username=username)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    # Get the fork
Pierre-Yves Chibon c55274
    repopath = os.path.join(
Pierre-Yves Chibon c55274
        APP.config['FORK_FOLDER'], request.repo_from.path)
Pierre-Yves Chibon c55274
    fork_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    # Get the original repo
Pierre-Yves Chibon c55274
    parentpath = os.path.join(APP.config['GIT_FOLDER'], request.repo.path)
Pierre-Yves Chibon c55274
    orig_repo = pygit2.Repository(parentpath)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    if orig_repo.get(request.stop_id, None):
Pierre-Yves Chibon c55274
        flask.flash('These chanages have already been merged.', 'error')
Pierre-Yves Chibon c55274
        # Update status
Pierre-Yves Chibon c55274
        progit.lib.close_pull_request(SESSION, request)
Pierre-Yves Chibon fb9e55
        SESSION.commit()
Pierre-Yves Chibon c55274
        return flask.redirect(error_output)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    # Clone the original repo into a temp folder
Pierre-Yves Chibon c55274
    newpath = tempfile.mkdtemp()
Pierre-Yves Chibon c55274
    new_repo = pygit2.clone_repository(parentpath, newpath)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    repo_commit = fork_obj[request.stop_id]
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    ori_remote = new_repo.remotes[0]
Pierre-Yves Chibon c55274
    # Add the fork as remote repo
Pierre-Yves Chibon c55274
    reponame = '%s_%s' % (request.user, repo.name)
Pierre-Yves Chibon c55274
    remote = new_repo.create_remote(reponame, repopath)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    # Fetch the commits
Pierre-Yves Chibon c55274
    remote.fetch()
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    merge = new_repo.merge(repo_commit.oid)
Pierre-Yves Chibon c55274
    master_ref = new_repo.lookup_reference('HEAD').resolve()
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    if merge.is_fastforward:
Pierre-Yves Chibon c55274
        master_ref.target = merge.fastforward_oid
Pierre-Yves Chibon c55274
        refname = '%s:%s' % (master_ref.name, master_ref.name)
Pierre-Yves Chibon c55274
        ori_remote.push(refname)
Pierre-Yves Chibon c55274
        flask.flash('Changes merged!')
Pierre-Yves Chibon c55274
    else:
Pierre-Yves Chibon c55274
        flask.flash(
Pierre-Yves Chibon c55274
            'This merge is not fast-forward and cannot be applied via '
Pierre-Yves Chibon c55274
            'progit', 'error')
Pierre-Yves Chibon c55274
        flask.redirect(error_output)
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    # Update status
Pierre-Yves Chibon c55274
    progit.lib.close_pull_request(SESSION, request)
Pierre-Yves Chibon fb9e55
    SESSION.commit()
Pierre-Yves Chibon c55274
Pierre-Yves Chibon c55274
    return flask.redirect(flask.url_for('view_repo', repo=repo.name))
Pierre-Yves Chibon c1135c
Pierre-Yves Chibon c1135c
Pierre-Yves Chibon c1135c
def view_forks(repo, username=None):
Pierre-Yves Chibon c1135c
    """ Return the list of forks of a project.
Pierre-Yves Chibon c1135c
    """
Pierre-Yves Chibon c1135c
Pierre-Yves Chibon c1135c
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon c1135c
Pierre-Yves Chibon c1135c
    if not repo:
Pierre-Yves Chibon c1135c
        flask.abort(404, 'Project not found')
Pierre-Yves Chibon c1135c
Pierre-Yves Chibon c1135c
    return flask.render_template(
Pierre-Yves Chibon c1135c
        'forks.html',
Pierre-Yves Chibon c1135c
        select='forks',
Pierre-Yves Chibon c1135c
        repo=repo,
Pierre-Yves Chibon c1135c
    )