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