diff --git a/pagure/docs_server.py b/pagure/docs_server.py new file mode 100644 index 0000000..c7d1f30 --- /dev/null +++ b/pagure/docs_server.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2014-2015 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +import logging +import os + +import flask +import pygit2 + +import pagure.doc_utils +import pagure.exceptions +import pagure.lib +import pagure.forms + +# Create the application. +APP = flask.Flask(__name__) + +# set up FAS +APP.config.from_object('pagure.default_config') + +if 'PAGURE_CONFIG' in os.environ: + APP.config.from_envvar('PAGURE_CONFIG') + +SESSION = pagure.lib.create_session(APP.config['DB_URL']) + +if not APP.debug: + APP.logger.addHandler(pagure.mail_logging.get_mail_handler( + smtp_server=APP.config.get('SMTP_SERVER', '127.0.0.1'), + mail_admin=APP.config.get('MAIL_ADMIN', APP.config['EMAIL_ERROR']) + )) + +# Send classic logs into syslog +handler = logging.StreamHandler() +handler.setLevel(APP.config.get('log_level', 'INFO')) +APP.logger.addHandler(handler) + +LOG = APP.logger + + +def __get_tree(repo_obj, tree, filepath, index=0, extended=False): + ''' Retrieve the entry corresponding to the provided filename in a + given tree. + ''' + filename = filepath[index] + if isinstance(tree, pygit2.Blob): # pragma: no cover + # If we were given a blob, then let's just return it + return (tree, None, None) + + for element in tree: + if element.name == filename or element.name.startswith('index'): + # If we have a folder we must go one level deeper + if element.filemode == 16384: + if (index + 1) == len(filepath): + filepath.append('') + return __get_tree( + repo_obj, repo_obj[element.oid], filepath, + index=index + 1, extended=True) + else: + return (element, tree, False) + + if filename == '': + return (None, tree, extended) + else: + raise pagure.exceptions.FileNotFoundException( + 'File %s not found' % ('/'.join(filepath),)) + + +def __get_tree_and_content(repo_obj, commit, path): + ''' Return the tree and the content of the specified file. ''' + + (blob_or_tree, tree_obj, extended) = __get_tree( + repo_obj, commit.tree, path) + + if blob_or_tree is None: + return (tree_obj, None, False, extended) + + if not repo_obj[blob_or_tree.oid]: + # Not tested and no idea how to test it, but better safe than sorry + flask.abort(404, 'File not found') + + if isinstance(blob_or_tree, pygit2.TreeEntry): # Returned a file + ext = os.path.splitext(blob_or_tree.name)[1] + blob_obj = repo_obj[blob_or_tree.oid] + content, safe = pagure.doc_utils.convert_readme(blob_obj.data, ext) + + tree = sorted(tree_obj, key=lambda x: x.filemode) + return (tree, content, safe, extended) + + +# URLs + + +@APP.route('//') +@APP.route('/') +@APP.route('//') +@APP.route('//') +@APP.route('///') +@APP.route('/fork///') +@APP.route('/fork//') +@APP.route('/fork///') +@APP.route('/fork///') +@APP.route('/fork////') +def view_docs(repo, username=None, branchname=None, filename=None): + """ Display the documentation + """ + + repo = pagure.lib.get_project(SESSION, repo, user=username) + + if not repo: + flask.abort(404, 'Project not found') + + if not repo.settings.get('project_documentation', True): + flask.abort(404, 'No documentation found for this project') + + reponame = os.path.join(APP.config['DOCS_FOLDER'], repo.path) + if not os.path.exists(reponame): + flask.abort(404, 'Documentation not found') + + repo_obj = pygit2.Repository(reponame) + + if branchname in repo_obj.listall_branches(): + branch = repo_obj.lookup_branch(branchname) + commit = branch.get_object() + else: + if not repo_obj.is_empty: + commit = repo_obj[repo_obj.head.target] + else: + commit = None + branchname = 'master' + + content = None + tree = None + safe = False + if not filename: + path = [''] + else: + path = [it for it in filename.split('/') if it] + + if commit: + try: + (tree, content, safe, extended) = __get_tree_and_content( + repo_obj, commit, path) + if extended: + filename += '/' + except pagure.exceptions.FileNotFoundException as err: + flask.flash(err.message, 'error') + + return flask.render_template( + 'docs.html', + select='docs', + repo_obj=repo_obj, + repo=repo, + username=username, + branchname=branchname, + filename=filename, + tree=tree, + content=content, + safe=safe, + )