Mercurial > archived > louis > tools > doxyhook
annotate 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 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/env python |
2 | |
3 # The MIT License | |
4 # | |
5 # Copyright (c) 2010 Louis Opter <kalessin@kalessin.fr> | |
6 # | |
7 # Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 # of this software and associated documentation files (the "Software"), to deal | |
9 # in the Software without restriction, including without limitation the rights | |
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 # copies of the Software, and to permit persons to whom the Software is | |
12 # furnished to do so, subject to the following conditions: | |
13 # | |
14 # The above copyright notice and this permission notice shall be included in | |
15 # all copies or substantial portions of the Software. | |
16 # | |
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 # THE SOFTWARE. | |
24 | |
25 import os | |
26 import re | |
27 import shutil | |
28 import subprocess | |
29 import sys | |
30 import tempfile | |
31 | |
32 from mercurial import ui, hg, commands | |
33 | |
34 OUTPUT = '/var/www/doc/api' | |
35 | |
36 class DoxyfileNotFound(Exception): | |
37 def __str__(self): | |
38 return ('can\'t find a doxyfile to generate the documentation') | |
39 | |
40 class TempDir(object): | |
41 """Wrap tempfile.mkdtemp to use the with statement""" | |
42 | |
43 def __init__(self): | |
44 pass | |
45 | |
46 def __enter__(self): | |
47 self.__path = tempfile.mkdtemp() | |
48 return self.__path | |
49 | |
50 def __exit__(self, exc_type, exc_value, traceback): | |
2
a85cbad8dadb
Uncomment shutil.rmtree in TempDir...
Louis Opter <louis.opter@dotcloud.com>
parents:
1
diff
changeset
|
51 shutil.rmtree(self.__path) |
0 | 52 |
3
3a06b35bd591
Avoid infinite recursion on hook call ("clone bomb")
Louis Opter <louis.opter@dotcloud.com>
parents:
2
diff
changeset
|
53 def clone_repo(sui, source, dest): |
0 | 54 """Clone repo at directory source to directory dest""" |
55 | |
3
3a06b35bd591
Avoid infinite recursion on hook call ("clone bomb")
Louis Opter <louis.opter@dotcloud.com>
parents:
2
diff
changeset
|
56 # We have to use a different ui than the source ui. If you don't take this |
3a06b35bd591
Avoid infinite recursion on hook call ("clone bomb")
Louis Opter <louis.opter@dotcloud.com>
parents:
2
diff
changeset
|
57 # precaution your hook will be called recursively by the clone command, |
3a06b35bd591
Avoid infinite recursion on hook call ("clone bomb")
Louis Opter <louis.opter@dotcloud.com>
parents:
2
diff
changeset
|
58 # leading to a clone bomb. |
3a06b35bd591
Avoid infinite recursion on hook call ("clone bomb")
Louis Opter <louis.opter@dotcloud.com>
parents:
2
diff
changeset
|
59 cui = ui.ui() |
3a06b35bd591
Avoid infinite recursion on hook call ("clone bomb")
Louis Opter <louis.opter@dotcloud.com>
parents:
2
diff
changeset
|
60 commands.clone(cui, source, dest, opts={'uncompressed': True}) |
3a06b35bd591
Avoid infinite recursion on hook call ("clone bomb")
Louis Opter <louis.opter@dotcloud.com>
parents:
2
diff
changeset
|
61 sui.status('doxyhook: working copy created.\n') |
0 | 62 |
63 def gen_doc(clone): | |
64 """ | |
65 Generate the documentation with the first doxyfile found under clone | |
66 directory. | |
67 | |
68 Return the output directory of the doc or None if no doc was generated. | |
69 """ | |
70 | |
71 # Regular expression for a doxygen configuration file: | |
72 doxyre = re.compile('.*[dD]oxyfile$') | |
73 # Regular expression used on a line of the doxygen configuration file to | |
74 # find the output directory: | |
75 outputre = re.compile('OUTPUT_DIRECTORY\\s*=\\s*(.*)$') | |
76 | |
77 files = os.listdir(clone) | |
78 try: | |
79 doxyfile = (f for f in files if not os.path.isdir(f) and doxyre.match(f)).next() | |
80 except StopIteration: | |
81 raise DoxyfileNotFound | |
82 | |
83 with open(os.path.join(clone, doxyfile)) as doxyconf: | |
84 for line in doxyconf: | |
85 output = outputre.match(line) | |
86 if output: | |
87 output = output.group(1) | |
88 break | |
89 | |
90 if output: | |
91 with open(os.devnull, 'w') as ignore: | |
92 oldpwd = os.getcwd() | |
93 # We have to change our directory so the doc is generated at the | |
94 # right place. | |
95 os.chdir(clone) | |
96 subprocess.call(['doxygen', doxyfile], stdout=ignore, stderr=ignore) | |
97 os.chdir(oldpwd) | |
98 # clone will be ignored if output is an absolute path | |
99 html = os.path.join(clone, output, 'html') | |
100 if os.path.isdir(html): | |
101 return html | |
102 | |
103 return None | |
104 | |
105 def move_doc(source, dest): | |
106 """Move the doc from source to dest""" | |
107 | |
1
b6cf3e38343e
Remove old generated files before moving
Louis Opter <louis.opter@dotcloud.com>
parents:
0
diff
changeset
|
108 if os.path.isdir(dest): |
b6cf3e38343e
Remove old generated files before moving
Louis Opter <louis.opter@dotcloud.com>
parents:
0
diff
changeset
|
109 shutil.rmtree(dest) |
0 | 110 shutil.move(source, dest) |
111 | |
112 def hook(ui, repo, hooktype, **kwargs): | |
113 if hooktype == 'changegroup': | |
114 with TempDir() as clone: | |
115 clone_repo(ui, repo.root, clone) | |
116 try: | |
117 output = gen_doc(clone) | |
118 if output: | |
119 ui.status('doxyhook: doc generated.\n') | |
120 move_doc(output, OUTPUT) | |
121 else: | |
122 ui.status('doxyhook: no doc generated.\n') | |
123 except (OSError, DoxyfileNotFound), ex: | |
124 ui.status('doxyhook: %s.\n' % str(ex)) | |
125 else: | |
126 ui.status('doxyhook: is a changegroup hook only.\n') | |
127 | |
128 if __name__ == '__main__': | |
129 if len(sys.argv) != 2: | |
130 print 'Usage: %s mercurial-repo' % os.path.basename(sys.argv[0]) | |
131 sys.exit(1) | |
132 | |
133 ui = ui.ui() | |
134 repo = hg.repository(ui, sys.argv[1]) | |
135 hook(ui, repo, 'changegroup') | |
136 sys.exit(0) |