Mercurial > archived > louis > tools > doxyhook
view doxyhook.py @ 3:3a06b35bd591 default tip
Avoid infinite recursion on hook call ("clone bomb")
author | Louis Opter <louis.opter@dotcloud.com> |
---|---|
date | Thu, 25 Mar 2010 20:09:55 +0100 |
parents | a85cbad8dadb |
children |
line wrap: on
line source
#!/usr/bin/env python # The MIT License # # Copyright (c) 2010 Louis Opter <kalessin@kalessin.fr> # # 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): shutil.rmtree(self.__path) def clone_repo(sui, source, dest): """Clone repo at directory source to directory dest""" # We have to use a different ui than the source ui. If you don't take this # precaution your hook will be called recursively by the clone command, # leading to a clone bomb. cui = ui.ui() commands.clone(cui, source, dest, opts={'uncompressed': True}) sui.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""" if os.path.isdir(dest): shutil.rmtree(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)