1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 """
29 This is the documentation generator of the EDNA projet, it relies on EpyDoc, please have a look on
30 U{the epydoc homepage<http://epydoc.sourceforge.net>}
31 """
32
33 __author__ = "Jérôme Kieffer"
34 __contact__ = "Jerome.Kieffer@esrf.eu"
35 __license__ = "GPLv3"
36 __date__ = "2011-04-13"
37 __copyright__ = "2011-ESRF"
38
39
40
41
42
43
44 import sys, os, tempfile
45 cwd = os.getcwd()
46 pyStrProgramPath = os.path.abspath(sys.argv[0])
47 pyStrBinPath = os.path.split(pyStrProgramPath)[0]
48 pyStrKernelPath = os.path.split(pyStrBinPath)[0]
49 pyStrEdnaHomePath = os.path.split(pyStrKernelPath)[0]
50 os.environ["EDNA_HOME"] = pyStrEdnaHomePath
51
52
53
54
55
56
57 strEdnaKernel = os.path.join(pyStrEdnaHomePath, "kernel", "src")
58 sys.path.append(strEdnaKernel)
59 if not "PYTHONPATH" in os.environ:
60 os.environ["PYTHONPATH"] = strEdnaKernel
61 else:
62 os.environ["PYTHONPATH"] += strEdnaKernel
63 os.environ["PYTHONPATH"] += os.pathsep + os.path.join(pyStrEdnaHomePath, "kernel", "tests", "src")
64 os.environ["PYTHONPATH"] += os.pathsep + os.path.join(pyStrEdnaHomePath, "kernel", "tests", "testsuite")
65
66
67 from EDJob import EDJob
68 from EDUtilsParallel import EDUtilsParallel
69 from EDVerbose import EDVerbose
70 from EDFactoryPluginStatic import EDFactoryPluginStatic
71 EDUtilsParallel.initializeNbThread()
72 EDFactoryPluginStatic.loadModule("XSDataDocumentation")
73 from XSDataDocumentation import XSDataString, XSDataFile, XSDataInputEpydoc, XSDataInteger
74 dictJobs = {}
75
76 -def findPlugins(EDNAHome, EDPluginPrefix="EDPlugin", XSDataPrefix="XSData", pythonExtension=".py",):
77 """
78 This function is the walker that goes through all directories in EDNA_HOME directory and searches for EDNA plugins ...
79
80 @param EDNAHome: the path of EDNA_HOME
81 @type EDNAHome: string
82 @param EDPluginPrefix: the start of the name of an EDNA Plugin
83 @type EDPluginPrefix: string
84 @param pythonExtension: the extension of an EDNA plugin, usually .py
85 @type pythonExtension: string
86 @return: to be definied but probably a dictionary with {EDPlugin: path}
87 @rtype: python dictionary
88 """
89 results = {}
90 PythonPath = []
91 for root, dirs, files in os.walk(EDNAHome):
92 if '.svn' in dirs:
93 dirs.remove('.svn')
94 if 'tests' in dirs:
95 dirs.remove('tests')
96 if "template" in dirs:
97 dirs.remove('template')
98 if "src" in dirs:
99 PythonPath.append(os.path.abspath(os.path.join(EDNAHome, root, "src")))
100 if files != []:
101 for oneFile in files:
102 if oneFile.endswith(pythonExtension):
103 if oneFile.find(EDPluginPrefix) == 0 :
104 results[os.path.splitext(oneFile)[0] ] = os.path.split(os.path.abspath(os.path.join(EDNAHome, root)))[0]
105 if oneFile.find(XSDataPrefix) == 0 :
106 PythonPath.append(os.path.abspath(os.path.join(EDNAHome, root)))
107 for mydir in PythonPath:
108 if not mydir in sys.path:
109 sys.path.append(mydir)
110 os.environ["PYTHONPATH"] += ":" + mydir
111 return results
112
113
115 """
116 This function is the walker that goes through all directories in EDNA_HOME directory and searches for EDNA projects or libraries ...
117
118 @param EDNAHome: the path of the EDNA_HOME top directory
119 @type EDNAHome: string
120 @param EDPluginPrefix: the start of the name of an EDNA Plugin
121 @type EDPluginPrefix: string
122 @param pythonExtension: the extension of an EDNA plugin, usually .py
123 @type pythonExtension: string
124 @return: a list of RelativeProjectPath
125 @rtype: python list
126 """
127 pylResults = []
128 for dirname in os.listdir(EDNAHome):
129 if not os.path.isdir(os.path.join(EDNAHome, dirname)):
130 continue
131 elif dirname in ['.svn', 'tests', 'template', "tmp", "temp", ".settings"]:
132 continue
133 elif dirname.find("libraries") == 0:
134 for subdir in os.listdir(os.path.join(EDNAHome, dirname)):
135 if subdir in ['.svn', 'tests', 'template', "tmp", "temp", ".settings"]:
136 continue
137 elif os.path.isdir(os.path.join(EDNAHome, dirname, subdir)):
138 pylResults.append(os.path.join(dirname, subdir))
139 else:
140 pylResults.append(dirname)
141 return pylResults
142
143
144 -def findFile(pluginDir, pythonExtension=".py", excludePrefixes=["XSData", "dna_", "ALJy", "EDJob", "EDParallelExecute", "EDUtilsParallel"]):
145 """
146 This function is the walker that goes through all directories in plugin directory and searches for python source files ...
147
148 @param pluginDir: the path to the plugin
149 @type pluginDir: string
150 @param pythonExtension: the extension of an EDNA plugin, usually .py
151 @type pythonExtension: string
152 @param excludePrefix: prefix that will not be included in code generation, typically the XSData bindings
153 @type excludePrefix: python string
154 @return: list of python files
155 @rtype: python list
156
157 """
158 results = []
159 for root, dirs, files in os.walk(pluginDir):
160 if '.svn' in dirs:
161 dirs.remove('.svn')
162 if files != []:
163 for oneFile in files:
164 if oneFile.endswith(pythonExtension):
165 for oneExt in excludePrefixes:
166 if oneFile.startswith(oneExt):
167 break
168 else:
169 results.append(os.path.join(pluginDir, root, oneFile))
170 return results
171
172 -def rmdir(topdir, bypass=False):
173 """Delete everything reachable from the directory named in "top",
174 assuming there are no symbolic links.
175 CAUTION: This is dangerous! For example, if top == '/', it
176 could delete all your disk files.
177 @param topdir: the directory to remove, the directory will stay there, but emptied.
178 @type topdir: python string
179 @param bypass: bypass the security if True
180 @type bypass: boolean
181 """
182 topdir = os.path.abspath(topdir)
183 if not os.path.isdir(topdir):
184 EDVerbose.screen("The argument topdir= %s is not a directory, giving up" % (topdir))
185 return
186 if ((topdir.find(pyStrEdnaHomePath) != 0) or (pyStrEdnaHomePath == topdir))and not bypass :
187 EDVerbose.screen("This is a dangerous method, lets play only in sub-directories of EDNA_HOME")
188 return
189 for root, dirs, files in os.walk(topdir, topdown=False):
190 if '.svn' in dirs:
191 dirs.remove('.svn')
192 for name in files:
193 os.remove(os.path.join(root, name))
194 for name in dirs:
195 try:
196 os.rmdir(os.path.join(root, name))
197 except OSError:
198 EDVerbose.screen("Error in removing: " + os.path.join(root, name))
199
200
201
202
203
204
205 if __name__ == '__main__':
206 cwd = os.getcwd()
207 workdir = tempfile.mkdtemp("doc", "tmp", os.getenv("HOME"))
208
209
210 os.chdir(workdir)
211 docFormat = "html"
212 CleanAll = False
213 WebSite = False
214 bVerbose = False
215 pathWebDoc = ""
216 for i in sys.argv:
217 if i == "--pdf":
218 docFormat = "pdf "
219 elif i == "--clean":
220 CleanAll = True
221 elif i == "--website":
222 WebSite = True
223 elif i == "-v":
224 bVerbose = True
225 elif os.path.isdir(i):
226 pathWebDoc = i
227
228 if WebSite and pathWebDoc:
229 print "Generating web documentation in ", pathWebDoc
230 rmdir(pathWebDoc, bypass=True)
231 for oneproject in findProjects(pyStrEdnaHomePath):
232 print ("Generating HTML pages for " + oneproject)
233 docPath = os.path.join(pathWebDoc, oneproject)
234 os.makedirs(docPath, int("755", 8))
235 listOfPythonFiles = findFile(os.path.join(pyStrEdnaHomePath, oneproject))
236 listOfPythonFiles.sort()
237 if len(listOfPythonFiles) > 0:
238 epydocJob = EDJob("EDPluginExecEpydocv1_0")
239 dictJobs[oneproject] = epydocJob
240 xsd = XSDataInputEpydoc()
241 xsd.setDocPath(XSDataFile(XSDataString(docPath)))
242 xsd.setProjectName(XSDataString(oneproject))
243 xsd.setDocType(XSDataString(docFormat))
244 if bVerbose:
245 xsd.setVerbosity(XSDataInteger(1))
246 else:
247 xsd.setVerbosity(XSDataInteger(-1))
248 xsd.setSources([XSDataFile(XSDataString(oneFile)) for oneFile in listOfPythonFiles])
249 epydocJob.setDataInput(xsd)
250 epydocJob.execute()
251 else:
252 print ("Error: No python files for project %s" % oneproject)
253
254 else:
255 plugins = findPlugins(pyStrEdnaHomePath)
256 pluginPathProcessed = []
257 for oneplugin in plugins:
258 pluginPath = plugins[oneplugin]
259 if not pluginPath in pluginPathProcessed:
260 pluginPathProcessed.append(pluginPath)
261 docPath = os.path.join(pluginPath, "doc")
262 if not os.path.isdir(docPath):
263 os.mkdir(docPath)
264 if CleanAll:
265 rmdir(docPath)
266 EDVerbose.screen("%40s --> %s" % (oneplugin, plugins[oneplugin]))
267 myPluginPath = os.path.join(pluginPath, "plugins", oneplugin + ".py")
268 listOfPythonFiles = []
269 if os.path.isfile(myPluginPath):
270 listOfPythonFiles = [myPluginPath]
271 for onePyFile in findFile(pluginPath):
272 if not onePyFile in listOfPythonFiles:
273 listOfPythonFiles.append(onePyFile)
274 if len(listOfPythonFiles) > 0:
275 epydocJob = EDJob("EDPluginExecEpydocv1_0")
276 dictJobs[oneplugin] = epydocJob
277 xsd = XSDataInputEpydoc()
278 xsd.setDocPath(XSDataFile(XSDataString(docPath)))
279 xsd.setProjectName(XSDataString(oneplugin))
280 xsd.setDocType(XSDataString(docFormat))
281 if bVerbose:
282 xsd.setVerbosity(XSDataInteger(2))
283 else:
284 xsd.setVerbosity(XSDataInteger(-1))
285 xsd.setSources([XSDataFile(XSDataString(oneFile)) for oneFile in listOfPythonFiles ])
286 epydocJob.setDataInput(xsd)
287 epydocJob.execute()
288 else:
289 print ("Error: No python files for plugin %s" % oneplugin)
290 EDVerbose.screen("Back to main")
291 for jobName in dictJobs:
292 job = dictJobs[jobName]
293 if job.getStatus() in [EDJob.PLUGIN_STATE_RUNNING, EDJob.PLUGIN_STATE_UNITIALIZED]:
294 EDVerbose.screen("Waiting for job %s to finish" % jobName)
295 job.synchronize()
296 EDVerbose.screen("Generation of documentation finished")
297 os.chdir(cwd)
298 EDJob.stats()
299