Blame progit/fork.py

Pierre-Yves Chibon fac0b1
#-*- coding: utf-8 -*-
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
"""
Pierre-Yves Chibon fac0b1
 (c) 2014 - Copyright Red Hat Inc
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
 Authors:
Pierre-Yves Chibon fac0b1
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
"""
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
import flask
Pierre-Yves Chibon fac0b1
import os
Pierre-Yves Chibon fac0b1
from math import ceil
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
import pygit2
Pierre-Yves Chibon fac0b1
from sqlalchemy.exc import SQLAlchemyError
Pierre-Yves Chibon fac0b1
from pygments import highlight
Pierre-Yves Chibon fac0b1
from pygments.lexers import guess_lexer
Pierre-Yves Chibon fac0b1
from pygments.lexers.text import DiffLexer
Pierre-Yves Chibon fac0b1
from pygments.formatters import HtmlFormatter
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon 6bf4e3
import progit.doc_utils
Pierre-Yves Chibon 80bba3
import progit.lib
Pierre-Yves Chibon ac8023
import progit.forms
Pierre-Yves Chibon f39cd3
from progit import APP, SESSION, LOG, __get_file_in_tree
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
### Application
Pierre-Yves Chibon e03e84
@APP.route('/do_fork/<repo>')</repo>
Pierre-Yves Chibon e03e84
@APP.route('/do_fork/<username>/<repo>')</repo></username>
Pierre-Yves Chibon 20ccbb
def fork_project(repo, username=None):
Pierre-Yves Chibon fac0b1
    """ Fork the project specified into the user's namespace
Pierre-Yves Chibon fac0b1
    """
Pierre-Yves Chibon 20ccbb
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon 80bba3
Pierre-Yves Chibon 80bba3
    if repo is None:
Pierre-Yves Chibon fac0b1
        flask.abort(404)
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon 80bba3
    try:
Pierre-Yves Chibon 80bba3
        message = progit.lib.fork_project(
Pierre-Yves Chibon 80bba3
            session=SESSION,
Pierre-Yves Chibon 80bba3
            repo=repo,
Pierre-Yves Chibon 80bba3
            repo_folder=APP.config['GIT_FOLDER'],
Pierre-Yves Chibon 80bba3
            fork_folder=APP.config['FORK_FOLDER'],
Pierre-Yves Chibon 80bba3
            user=flask.g.fas_user.username)
Pierre-Yves Chibon 80bba3
Pierre-Yves Chibon 80bba3
        SESSION.commit()
Pierre-Yves Chibon 80bba3
        flask.flash(message)
Pierre-Yves Chibon 80bba3
        return flask.redirect(
Pierre-Yves Chibon 792a86
            flask.url_for(
Pierre-Yves Chibon 792a86
                'view_fork_repo',
Pierre-Yves Chibon 792a86
                username=flask.g.fas_user.username,
Pierre-Yves Chibon 792a86
                repo=repo.name)
Pierre-Yves Chibon 80bba3
        )
Pierre-Yves Chibon 80bba3
    except progit.exceptions.ProgitException, err:
Pierre-Yves Chibon 80bba3
        flask.flash(str(err), 'error')
Pierre-Yves Chibon 80bba3
    except SQLAlchemyError, err:  # pragma: no cover
Pierre-Yves Chibon 80bba3
        SESSION.rollback()
Pierre-Yves Chibon 80bba3
        flask.flash(str(err), 'error')
Pierre-Yves Chibon 80bba3
Pierre-Yves Chibon 792a86
    return flask.redirect(flask.url_for('view_repo', repo=repo.name))
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon fac0b1
Pierre-Yves Chibon ac8023
@APP.route('/fork/<username>/<repo>/request-pull/new',</repo></username>
Pierre-Yves Chibon 3bb858
           methods=('GET', 'POST'))
Pierre-Yves Chibon ac8023
@APP.route('/fork/<username>/<repo>/request-pull/new/<commitid>',</commitid></repo></username>
Pierre-Yves Chibon ac8023
           methods=('GET', 'POST'))
Pierre-Yves Chibon ac8023
def new_request_pull(username, repo, commitid=None):
Pierre-Yves Chibon 82055c
    """ Request pulling the changes from the fork into the project.
Pierre-Yves Chibon 82055c
    """
Pierre-Yves Chibon 82055c
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon 82055c
    if not repo:
Pierre-Yves Chibon 82055c
        flask.abort(404)
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon ebf29e
    repopath = os.path.join(APP.config['FORK_FOLDER'], repo.path)
Pierre-Yves Chibon 85755c
    repo_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon 82055c
    parentname = os.path.join(APP.config['GIT_FOLDER'], repo.parent.path)
Pierre-Yves Chibon 82055c
    orig_repo = pygit2.Repository(parentname)
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon 82055c
    if commitid is None:
Pierre-Yves Chibon 82055c
        commitid = repo_obj.head.target
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon 82055c
    diff_commits = []
Pierre-Yves Chibon 82055c
    diffs = []
Pierre-Yves Chibon 82055c
    if not repo_obj.is_empty and not orig_repo.is_empty:
Pierre-Yves Chibon 82055c
        orig_commit = orig_repo[orig_repo.head.target]
Pierre-Yves Chibon 82055c
        repo_commit = repo_obj[commitid]
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon 82055c
        for commit in repo_obj.walk(commitid, pygit2.GIT_SORT_TIME):
Pierre-Yves Chibon 82055c
            if commit.oid.hex == orig_commit.oid.hex:
Pierre-Yves Chibon 82055c
                break
Pierre-Yves Chibon 82055c
            diff_commits.append(commit)
Pierre-Yves Chibon 82055c
            diffs.append(
Pierre-Yves Chibon 82055c
                repo_obj.diff(
Pierre-Yves Chibon 82055c
                    repo_obj.revparse_single(commit.parents[0].oid.hex),
Pierre-Yves Chibon 82055c
                    repo_obj.revparse_single(commit.oid.hex)
Pierre-Yves Chibon 82055c
                )
Pierre-Yves Chibon 82055c
            )
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon 82055c
    elif orig_repo.is_empty:
Pierre-Yves Chibon ac8023
        orig_commit = None
Pierre-Yves Chibon 85755c
        repo_commit = repo_obj[repo_obj.head.target]
Pierre-Yves Chibon 85755c
        diff = repo_commit.tree.diff_to_tree(swap=True)
Pierre-Yves Chibon 82055c
    else:
Pierre-Yves Chibon 82055c
        flask.flash(
Pierre-Yves Chibon 82055c
            'Fork is empty, there are no commits to request pulling',
Pierre-Yves Chibon 82055c
            'error')
Pierre-Yves Chibon 82055c
        return flask.redirect(flask.url_for(
Pierre-Yves Chibon 82055c
            'view_fork_repo', username=username, repo=repo.name))
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon 82055c
    html_diffs = []
Pierre-Yves Chibon 82055c
    for diff in diffs:
Pierre-Yves Chibon 82055c
        html_diffs.append(
Pierre-Yves Chibon 82055c
            highlight(
Pierre-Yves Chibon 82055c
                diff.patch,
Pierre-Yves Chibon 82055c
                DiffLexer(),
Pierre-Yves Chibon 82055c
                HtmlFormatter(
Pierre-Yves Chibon 82055c
                    noclasses=True,
Pierre-Yves Chibon 82055c
                    style="tango",)
Pierre-Yves Chibon 82055c
            )
Pierre-Yves Chibon 82055c
        )
Pierre-Yves Chibon 82055c
Pierre-Yves Chibon ac8023
    form = progit.forms.RequestPullForm()
Pierre-Yves Chibon ac8023
    if form.validate_on_submit():
Pierre-Yves Chibon ac8023
        try:
Pierre-Yves Chibon ac8023
            if orig_commit:
Pierre-Yves Chibon ac8023
                orig_commit = orig_commit.oid.hex
Pierre-Yves Chibon ac8023
            message = progit.lib.new_pull_request(
Pierre-Yves Chibon ac8023
                SESSION,
Pierre-Yves Chibon ac8023
                repo=repo.parent,
Pierre-Yves Chibon ac8023
                repo_from=repo,
Pierre-Yves Chibon ac8023
                title=form.title.data,
Pierre-Yves Chibon ac8023
                start_id=orig_commit,
Pierre-Yves Chibon ac8023
                stop_id=repo_commit.oid.hex,
Pierre-Yves Chibon ac8023
                user=flask.g.fas_user.username,
Pierre-Yves Chibon ac8023
            )
Pierre-Yves Chibon ac8023
            SESSION.commit()
Pierre-Yves Chibon ac8023
            flask.flash(message)
Pierre-Yves Chibon ac8023
            return flask.redirect(flask.url_for(
Pierre-Yves Chibon ac8023
                'view_fork_issues', username=username, repo=repo.name))
Pierre-Yves Chibon ac8023
        except progit.exceptions.ProgitException, err:
Pierre-Yves Chibon ac8023
            flask.flash(str(err), 'error')
Pierre-Yves Chibon ac8023
        except SQLAlchemyError, err:  # pragma: no cover
Pierre-Yves Chibon ac8023
            SESSION.rollback()
Pierre-Yves Chibon ac8023
            flask.flash(str(err), 'error')
Pierre-Yves Chibon ac8023
Pierre-Yves Chibon 82055c
    return flask.render_template(
Pierre-Yves Chibon 82055c
        'pull_request.html',
Pierre-Yves Chibon 82055c
        repo=repo,
Pierre-Yves Chibon 82055c
        username=username,
Pierre-Yves Chibon ac8023
        commitid=commitid,
Pierre-Yves Chibon 82055c
        repo_obj=repo_obj,
Pierre-Yves Chibon 82055c
        orig_repo=orig_repo,
Pierre-Yves Chibon 82055c
        diff_commits=diff_commits,
Pierre-Yves Chibon 82055c
        diffs=diffs,
Pierre-Yves Chibon 82055c
        html_diffs=html_diffs,
Pierre-Yves Chibon ac8023
        form=form,
Pierre-Yves Chibon 82055c
    )