# HG changeset patch # User Louis Opter # Date 1269538002 -3600 # Node ID 939b2b9901f38cabcbeca83cdcdc7747263b31d1 Initial import diff -r 000000000000 -r 939b2b9901f3 doxyhook.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doxyhook.py Thu Mar 25 18:26:42 2010 +0100 @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +# The MIT License +# +# Copyright (c) 2010 Louis Opter +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import os +import re +import shutil +import subprocess +import sys +import tempfile + +from mercurial import ui, hg, commands + +OUTPUT = '/var/www/doc/api' + +class DoxyfileNotFound(Exception): + def __str__(self): + return ('can\'t find a doxyfile to generate the documentation') + +class TempDir(object): + """Wrap tempfile.mkdtemp to use the with statement""" + + def __init__(self): + pass + + def __enter__(self): + self.__path = tempfile.mkdtemp() + return self.__path + + def __exit__(self, exc_type, exc_value, traceback): + pass +#shutil.rmtree(self.__path) + +def clone_repo(ui, source, dest): + """Clone repo at directory source to directory dest""" + + commands.clone(ui, source, dest, opts={'uncompressed': True}) + ui.status('doxyhook: working copy created.\n') + +def gen_doc(clone): + """ + Generate the documentation with the first doxyfile found under clone + directory. + + Return the output directory of the doc or None if no doc was generated. + """ + + # Regular expression for a doxygen configuration file: + doxyre = re.compile('.*[dD]oxyfile$') + # Regular expression used on a line of the doxygen configuration file to + # find the output directory: + outputre = re.compile('OUTPUT_DIRECTORY\\s*=\\s*(.*)$') + + files = os.listdir(clone) + try: + doxyfile = (f for f in files if not os.path.isdir(f) and doxyre.match(f)).next() + except StopIteration: + raise DoxyfileNotFound + + with open(os.path.join(clone, doxyfile)) as doxyconf: + for line in doxyconf: + output = outputre.match(line) + if output: + output = output.group(1) + break + + if output: + with open(os.devnull, 'w') as ignore: + oldpwd = os.getcwd() + # We have to change our directory so the doc is generated at the + # right place. + os.chdir(clone) + subprocess.call(['doxygen', doxyfile], stdout=ignore, stderr=ignore) + os.chdir(oldpwd) + # clone will be ignored if output is an absolute path + html = os.path.join(clone, output, 'html') + if os.path.isdir(html): + return html + + return None + +def move_doc(source, dest): + """Move the doc from source to dest""" + + shutil.move(source, dest) + +def hook(ui, repo, hooktype, **kwargs): + if hooktype == 'changegroup': + with TempDir() as clone: + clone_repo(ui, repo.root, clone) + try: + output = gen_doc(clone) + if output: + ui.status('doxyhook: doc generated.\n') + move_doc(output, OUTPUT) + else: + ui.status('doxyhook: no doc generated.\n') + except (OSError, DoxyfileNotFound), ex: + ui.status('doxyhook: %s.\n' % str(ex)) + else: + ui.status('doxyhook: is a changegroup hook only.\n') + +if __name__ == '__main__': + if len(sys.argv) != 2: + print 'Usage: %s mercurial-repo' % os.path.basename(sys.argv[0]) + sys.exit(1) + + ui = ui.ui() + repo = hg.repository(ui, sys.argv[1]) + hook(ui, repo, 'changegroup') + sys.exit(0)