Blame progit/ui/docs.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
"""
Pierre-Yves Chibon ddede6
 (c) 2014 - Copyright Red Hat Inc
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
 Authors:
Pierre-Yves Chibon ddede6
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
"""
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
import flask
Pierre-Yves Chibon ddede6
import os
Pierre-Yves Chibon ddede6
from math import ceil
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
import pygit2
Pierre-Yves Chibon ddede6
from sqlalchemy.exc import SQLAlchemyError
Pierre-Yves Chibon ddede6
from pygments import highlight
Pierre-Yves Chibon ddede6
from pygments.lexers import guess_lexer
Pierre-Yves Chibon ddede6
from pygments.lexers.text import DiffLexer
Pierre-Yves Chibon ddede6
from pygments.formatters import HtmlFormatter
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
import progit.doc_utils
Pierre-Yves Chibon 822345
import progit.exceptions
Pierre-Yves Chibon ddede6
import progit.lib
Pierre-Yves Chibon ddede6
import progit.forms
Pierre-Yves Chibon ddede6
from progit import APP, SESSION, LOG, cla_required
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
def __get_tree(repo_obj, tree, filepath, startswith=False):
Pierre-Yves Chibon ddede6
    ''' Retrieve the entry corresponding to the provided filename in a
Pierre-Yves Chibon ddede6
    given tree.
Pierre-Yves Chibon ddede6
    '''
Pierre-Yves Chibon ddede6
    filename = filepath[0]
Pierre-Yves Chibon ddede6
    if isinstance(tree, pygit2.Blob):
Pierre-Yves Chibon ddede6
        return (tree, None)
Pierre-Yves Chibon ddede6
    cnt = 0
Pierre-Yves Chibon ddede6
    for el in tree:
Pierre-Yves Chibon ddede6
        cnt += 1
Pierre-Yves Chibon ddede6
        ok = False
Pierre-Yves Chibon d6aad2
        if el.name.startswith(filename):
Pierre-Yves Chibon ddede6
            ok = True
Pierre-Yves Chibon ddede6
        if el.name == filename:
Pierre-Yves Chibon ddede6
            ok = True
Pierre-Yves Chibon 822345
        if ok and len(filepath) == 1:
Pierre-Yves Chibon 822345
            return (el, tree)
Pierre-Yves Chibon 822345
        elif ok:
Pierre-Yves Chibon 822345
            return __get_tree(
Pierre-Yves Chibon d6aad2
                repo_obj, repo_obj[el.oid], filepath[1:],
Pierre-Yves Chibon d6aad2
                startswith=startswith)
Pierre-Yves Chibon 822345
Pierre-Yves Chibon 822345
    if len(filepath) == 1:
Pierre-Yves Chibon 3b01c0
        return None, tree
Pierre-Yves Chibon 822345
    else:
Pierre-Yves Chibon 822345
        return __get_tree(
Pierre-Yves Chibon d6aad2
            repo_obj, repo_obj[tree.oid], filepath[1:],
Pierre-Yves Chibon d6aad2
            startswith=startswith)
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
def __get_tree_and_content(repo_obj, commit, path, startswith):
Pierre-Yves Chibon ddede6
    ''' Return the tree and the content of the specified file. '''
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon 3b01c0
    (blob_or_tree, tree_obj) = __get_tree(
Pierre-Yves Chibon 3b01c0
        repo_obj, commit.tree, path, startswith=startswith)
Pierre-Yves Chibon 3b01c0
Pierre-Yves Chibon 3b01c0
    if blob_or_tree is None:
Pierre-Yves Chibon 3b01c0
        return tree_obj, None
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
    if not repo_obj[blob_or_tree.oid]:
Pierre-Yves Chibon ddede6
        flask.abort(404, 'File not found')
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
    blob_or_tree_obj = repo_obj[blob_or_tree.oid]
Pierre-Yves Chibon ddede6
    blob = repo_obj[blob_or_tree.oid]
Pierre-Yves Chibon 822345
Pierre-Yves Chibon 822345
    content = None
Pierre-Yves Chibon ddede6
    if isinstance(blob, pygit2.Blob):  # Returned a file
Pierre-Yves Chibon ddede6
        name, ext = os.path.splitext(blob_or_tree.name)
Pierre-Yves Chibon ddede6
        content = progit.doc_utils.convert_readme(blob_or_tree_obj.data, ext)
Pierre-Yves Chibon ddede6
    else:  # Returned a tree
Pierre-Yves Chibon 1d2e52
        raise progit.exceptions.FileNotFoundException('File not found')
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
    tree = sorted(tree_obj, key=lambda x: x.filemode)
Pierre-Yves Chibon ddede6
    return (tree, content)
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon e04c77
# URLs
Pierre-Yves Chibon c4da03
Pierre-Yves Chibon c4da03
Pierre-Yves Chibon c4da03
@APP.route('/<repo>/docs')</repo>
Pierre-Yves Chibon c4da03
@APP.route('/<repo>/docs/<path:filename>')</path:filename></repo>
Pierre-Yves Chibon c4da03
@APP.route('/<repo>/docs/<branchname>')</branchname></repo>
Pierre-Yves Chibon c4da03
@APP.route('/<repo>/docs/<branchname>/<path:filename>')</path:filename></branchname></repo>
Pierre-Yves Chibon c4da03
@APP.route('/fork/<username>/<repo>/docs')</repo></username>
Pierre-Yves Chibon c4da03
@APP.route('/fork/<username>/<repo>/docs/<path:filename>')</path:filename></repo></username>
Pierre-Yves Chibon c4da03
@APP.route('/fork/<username>/<repo>/docs/<branchname>')</branchname></repo></username>
Pierre-Yves Chibon c4da03
@APP.route('/fork/<username>/<repo>/docs/<branchname>/<path:filename>')</path:filename></branchname></repo></username>
Pierre-Yves Chibon 4b7a7d
def view_docs(repo, username=None, branchname=None, filename=None):
Pierre-Yves Chibon c4da03
    """ Display the documentation
Pierre-Yves Chibon ddede6
    """
Pierre-Yves Chibon c4da03
    status = flask.request.args.get('status', None)
Pierre-Yves Chibon c4da03
Pierre-Yves Chibon ddede6
    repo = progit.lib.get_project(SESSION, repo, user=username)
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
    if not repo:
Pierre-Yves Chibon ddede6
        flask.abort(404, 'Project not found')
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon 4b7a7d
    if not repo.project_docs:
Pierre-Yves Chibon c2f4ca
        flask.abort(404, 'No documentation found for this project')
Pierre-Yves Chibon c2f4ca
Pierre-Yves Chibon 4b7a7d
    reponame = os.path.join(APP.config['DOCS_FOLDER'], repo.path)
Pierre-Yves Chibon a386bc
    if not os.path.exists(reponame):
Pierre-Yves Chibon a386bc
        flask.flash(
Pierre-Yves Chibon 4b7a7d
            'No docs repository could be found, please contact an admin',
Pierre-Yves Chibon a386bc
            'error')
Pierre-Yves Chibon a386bc
        return flask.redirect(flask.url_for(
Pierre-Yves Chibon a386bc
            'view_repo', repo=repo.name, username=username))
Pierre-Yves Chibon a386bc
Pierre-Yves Chibon ddede6
    repo_obj = pygit2.Repository(reponame)
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
    if branchname in repo_obj.listall_branches():
Pierre-Yves Chibon ddede6
        branch = repo_obj.lookup_branch(branchname)
Pierre-Yves Chibon ddede6
        commit = branch.get_object()
Pierre-Yves Chibon ddede6
    else:
Pierre-Yves Chibon ddede6
        if not repo_obj.is_empty:
Pierre-Yves Chibon ddede6
            commit = repo_obj[repo_obj.head.target]
Pierre-Yves Chibon ddede6
        else:
Pierre-Yves Chibon ddede6
            commit = None
Pierre-Yves Chibon ddede6
        branchname = 'master'
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
    content = None
Pierre-Yves Chibon 0c352b
    tree = None
Pierre-Yves Chibon ddede6
    startswith = False
Pierre-Yves Chibon ddede6
    if not filename:
Pierre-Yves Chibon ddede6
        path = ['index']
Pierre-Yves Chibon ddede6
        startswith = True
Pierre-Yves Chibon ddede6
    else:
Pierre-Yves Chibon ddede6
        path = filename.split('/')
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
    if commit:
Pierre-Yves Chibon 822345
        try:
Pierre-Yves Chibon 822345
            (tree, content) = __get_tree_and_content(
Pierre-Yves Chibon 822345
                repo_obj, commit, path, startswith)
Pierre-Yves Chibon 822345
        except progit.exceptions.FileNotFoundException:
Pierre-Yves Chibon 822345
            if not path[0].startswith('index'):
Pierre-Yves Chibon 822345
                path.append('index')
Pierre-Yves Chibon 822345
                filename = filename + '/'
Pierre-Yves Chibon 3b01c0
Pierre-Yves Chibon 013e6f
        (tree, content) = __get_tree_and_content(
Pierre-Yves Chibon d6aad2
            repo_obj, commit, path, startswith=True)
Pierre-Yves Chibon ddede6
Pierre-Yves Chibon ddede6
    return flask.render_template(
Pierre-Yves Chibon 4b7a7d
        'docs.html',
Pierre-Yves Chibon 75a541
        select='docs',
Pierre-Yves Chibon c1f7d5
        repo_obj=repo_obj,
Pierre-Yves Chibon ddede6
        repo=repo,
Pierre-Yves Chibon ddede6
        username=username,
Pierre-Yves Chibon ddede6
        branchname=branchname,
Pierre-Yves Chibon ddede6
        filename=filename,
Pierre-Yves Chibon ddede6
        tree=tree,
Pierre-Yves Chibon ddede6
        content=content,
Pierre-Yves Chibon ddede6
    )