]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py
BaseTools: Fix a typo in ini.py
[mirror_edk2.git] / BaseTools / Scripts / PackageDocumentTools / packagedoc_cli.py
CommitLineData
7ccc9c95
YZ
1## @file\r
2# This module provide command line entry for generating package document!\r
3#\r
4# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
5#\r
6# This program and the accompanying materials are licensed and made available\r
7# under the terms and conditions of the BSD License which accompanies this\r
8# distribution. The full text of the license may be found at\r
9# http://opensource.org/licenses/bsd-license.php\r
10#\r
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13#\r
14\r
15import os, sys, logging, traceback, subprocess\r
16from optparse import OptionParser\r
17\r
18import plugins.EdkPlugins.edk2.model.baseobject as baseobject\r
19import plugins.EdkPlugins.edk2.model.doxygengen as doxygengen\r
20\r
21gArchMarcoDict = {'ALL' : 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER',\r
22 'IA32_MSFT': 'MDE_CPU_IA32 _MSC_EXTENSIONS',\r
23 'IA32_GNU' : 'MDE_CPU_IA32 __GNUC__',\r
24 'X64_MSFT' : 'MDE_CPU_X64 _MSC_EXTENSIONS ASM_PFX= OPTIONAL= ',\r
25 'X64_GNU' : 'MDE_CPU_X64 __GNUC__ ASM_PFX= OPTIONAL= ',\r
26 'IPF_MSFT' : 'MDE_CPU_IPF _MSC_EXTENSIONS ASM_PFX= OPTIONAL= ',\r
27 'IPF_GNU' : 'MDE_CPU_IPF __GNUC__ ASM_PFX= OPTIONAL= ',\r
28 'EBC_INTEL': 'MDE_CPU_EBC __INTEL_COMPILER ASM_PFX= OPTIONAL= '}\r
29\r
30def parseCmdArgs():\r
31 parser = OptionParser(version="Package Document Generation Tools - Version 0.1")\r
32 parser.add_option('-w', '--workspace', action='store', type='string', dest='WorkspacePath',\r
33 help='Specify workspace absolute path. For example: c:\\tianocore')\r
34 parser.add_option('-p', '--decfile', action='store', dest='PackagePath',\r
35 help='Specify the absolute path for package DEC file. For example: c:\\tianocore\\MdePkg\\MdePkg.dec')\r
36 parser.add_option('-x', '--doxygen', action='store', dest='DoxygenPath',\r
37 help='Specify the absolute path of doxygen tools installation. For example: C:\\Program Files\\doxygen\bin\doxygen.exe')\r
38 parser.add_option('-o', '--output', action='store', dest='OutputPath',\r
39 help='Specify the document output path. For example: c:\\docoutput')\r
40 parser.add_option('-a', '--arch', action='store', dest='Arch', choices=gArchMarcoDict.keys(),\r
41 help='Specify the architecture used in preprocess package\'s source. For example: -a IA32_MSFT')\r
42 parser.add_option('-m', '--mode', action='store', dest='DocumentMode', choices=['CHM', 'HTML'],\r
43 help='Specify the document mode from : CHM or HTML')\r
44 parser.add_option('-i', '--includeonly', action='store_true', dest='IncludeOnly',\r
45 help='Only generate document for package\'s public interfaces produced by include folder. ')\r
46 parser.add_option('-c', '--htmlworkshop', dest='HtmlWorkshopPath',\r
47 help='Specify the absolute path for Microsoft HTML Workshop\'s hhc.exe file. For example: C:\\Program Files\\HTML Help Workshop\\hhc.exe')\r
48 (options, args) = parser.parse_args()\r
49\r
50 # validate the options\r
51 errors = []\r
4231a819 52 if options.WorkspacePath is None:\r
7ccc9c95
YZ
53 errors.append('- Please specify workspace path via option -w!')\r
54 elif not os.path.exists(options.WorkspacePath):\r
55 errors.append("- Invalid workspace path %s! The workspace path should be exist in absolute path!" % options.WorkspacePath)\r
56\r
4231a819 57 if options.PackagePath is None:\r
7ccc9c95
YZ
58 errors.append('- Please specify package DEC file path via option -p!')\r
59 elif not os.path.exists(options.PackagePath):\r
60 errors.append("- Invalid package's DEC file path %s! The DEC path should be exist in absolute path!" % options.PackagePath)\r
61\r
62 default = "C:\\Program Files\\doxygen\\bin\\doxygen.exe"\r
4231a819 63 if options.DoxygenPath is None:\r
7ccc9c95
YZ
64 if os.path.exists(default):\r
65 print "Warning: Assume doxygen tool is installed at %s. If not, please specify via -x" % default\r
66 options.DoxygenPath = default\r
67 else:\r
68 errors.append('- Please specify the path of doxygen tool installation via option -x! or install it in default path %s' % default)\r
69 elif not os.path.exists(options.DoxygenPath):\r
70 errors.append("- Invalid doxygen tool path %s! The doxygen tool path should be exist in absolute path!" % options.DoxygenPath)\r
71\r
4231a819 72 if options.OutputPath is not None:\r
7ccc9c95
YZ
73 if not os.path.exists(options.OutputPath):\r
74 # create output\r
75 try:\r
76 os.makedirs(options.OutputPath)\r
77 except:\r
78 errors.append('- Fail to create the output directory %s' % options.OutputPath)\r
79 else:\r
4231a819 80 if options.PackagePath is not None and os.path.exists(options.PackagePath):\r
7ccc9c95
YZ
81 dirpath = os.path.dirname(options.PackagePath)\r
82 default = os.path.join (dirpath, "Document")\r
83 print 'Warning: Assume document output at %s. If not, please specify via option -o' % default\r
84 options.OutputPath = default\r
85 if not os.path.exists(default):\r
86 try:\r
87 os.makedirs(default)\r
88 except:\r
89 errors.append('- Fail to create default output directory %s! Please specify document output diretory via option -o' % default)\r
90 else:\r
91 errors.append('- Please specify document output path via option -o!')\r
92\r
4231a819 93 if options.Arch is None:\r
7ccc9c95
YZ
94 options.Arch = 'ALL'\r
95 print "Warning: Assume arch is \"ALL\". If not, specify via -a"\r
96\r
4231a819 97 if options.DocumentMode is None:\r
7ccc9c95
YZ
98 options.DocumentMode = "HTML"\r
99 print "Warning: Assume document mode is \"HTML\". If not, specify via -m"\r
100\r
4231a819 101 if options.IncludeOnly is None:\r
7ccc9c95
YZ
102 options.IncludeOnly = False\r
103 print "Warning: Assume generate package document for all package\'s source including publich interfaces and implementation libraries and modules."\r
104\r
105 if options.DocumentMode.lower() == 'chm':\r
106 default = "C:\\Program Files\\HTML Help Workshop\\hhc.exe"\r
4231a819 107 if options.HtmlWorkshopPath is None:\r
7ccc9c95
YZ
108 if os.path.exists(default):\r
109 print 'Warning: Assume the installation path of Microsoft HTML Workshop is %s. If not, specify via option -c.' % default\r
110 options.HtmlWorkshopPath = default\r
111 else:\r
112 errors.append('- Please specify the installation path of Microsoft HTML Workshop via option -c!')\r
113 elif not os.path.exists(options.HtmlWorkshopPath):\r
114 errors.append('- The installation path of Microsoft HTML Workshop %s does not exists. ' % options.HtmlWorkshopPath)\r
115\r
116 if len(errors) != 0:\r
117 print '\n'\r
118 parser.error('Fail to start due to following reasons: \n%s' %'\n'.join(errors))\r
119 return (options.WorkspacePath, options.PackagePath, options.DoxygenPath, options.OutputPath,\r
120 options.Arch, options.DocumentMode, options.IncludeOnly, options.HtmlWorkshopPath)\r
121\r
122def createPackageObject(wsPath, pkgPath):\r
123 try:\r
124 pkgObj = baseobject.Package(None, wsPath)\r
125 pkgObj.Load(pkgPath)\r
126 except:\r
127 logging.getLogger().error ('Fail to create package object!')\r
128 return None\r
129\r
130 return pkgObj\r
131\r
132def callbackLogMessage(msg, level):\r
133 print msg.strip()\r
134\r
135def callbackCreateDoxygenProcess(doxPath, configPath):\r
136 if sys.platform == 'win32':\r
137 cmd = '"%s" %s' % (doxPath, configPath)\r
138 else:\r
139 cmd = '%s %s' % (doxPath, configPath)\r
140 print cmd\r
141 subprocess.call(cmd, shell=True)\r
142\r
143\r
144def DocumentFixup(outPath, arch):\r
145 # find BASE_LIBRARY_JUMP_BUFFER structure reference page\r
146\r
147 print '\n >>> Start fixup document \n'\r
148\r
149 for root, dirs, files in os.walk(outPath):\r
150 for dir in dirs:\r
151 if dir.lower() in ['.svn', '_svn', 'cvs']:\r
152 dirs.remove(dir)\r
153 for file in files:\r
154 if not file.lower().endswith('.html'): continue\r
155 fullpath = os.path.join(outPath, root, file)\r
156 try:\r
157 f = open(fullpath, 'r')\r
158 text = f.read()\r
159 f.close()\r
160 except:\r
161 logging.getLogger().error('\nFail to open file %s\n' % fullpath)\r
162 continue\r
163 if arch.lower() == 'all':\r
164 if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1:\r
165 FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text)\r
166 if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1:\r
167 FixPageBaseLib(fullpath, text)\r
168 if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1:\r
169 FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text)\r
170 if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1:\r
171 FixPageUefiDriverEntryPoint(fullpath, text)\r
172 if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1:\r
173 FixPageUefiApplicationEntryPoint(fullpath, text)\r
174\r
175 print ' >>> Finish all document fixing up! \n'\r
176\r
177def FixPageBaseLib(path, text):\r
178 print ' >>> Fixup BaseLib file page at file %s \n' % path\r
179 lines = text.split('\n')\r
180 lastBaseJumpIndex = -1\r
181 lastIdtGateDescriptor = -1\r
182 for index in range(len(lines) - 1, -1, -1):\r
183 line = lines[index]\r
184 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4 </td>':\r
185 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4&nbsp;[IA32] </td>'\r
186 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10 </td>':\r
187 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF] </td>'\r
188 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;8 </td>':\r
189 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;9&nbsp;[EBC, x64] </td>'\r
190 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4') != -1:\r
191 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4',\r
192 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4&nbsp;[IA32]')\r
193 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10') != -1:\r
194 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10',\r
195 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF]')\r
196 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8') != -1:\r
197 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8',\r
198 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8&nbsp;[x64, EBC]')\r
199 if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1:\r
200 if lastBaseJumpIndex != -1:\r
201 del lines[lastBaseJumpIndex]\r
202 lastBaseJumpIndex = index\r
203 if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1:\r
204 if lastIdtGateDescriptor != -1:\r
205 del lines[lastIdtGateDescriptor]\r
206 lastIdtGateDescriptor = index\r
207 try:\r
208 f = open(path, 'w')\r
209 f.write('\n'.join(lines))\r
210 f.close()\r
211 except:\r
212 logging.getLogger().error(" <<< Fail to fixup file %s\n" % path)\r
213 return\r
214 print " <<< Finish to fixup file %s\n" % path\r
215\r
216def FixPageIA32_IDT_GATE_DESCRIPTOR(path, text):\r
217 print ' >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path\r
218 lines = text.split('\n')\r
219 for index in range(len(lines) - 1, -1, -1):\r
220 line = lines[index].strip()\r
221 if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1:\r
222 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')\r
223 if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1:\r
224 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')\r
225 try:\r
226 f = open(path, 'w')\r
227 f.write('\n'.join(lines))\r
228 f.close()\r
229 except:\r
230 logging.getLogger().error(" <<< Fail to fixup file %s\n" % path)\r
231 return\r
232 print " <<< Finish to fixup file %s\n" % path\r
233\r
234def FixPageBASE_LIBRARY_JUMP_BUFFER(path, text):\r
235 print ' >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path\r
236 lines = text.split('\n')\r
237 bInDetail = True\r
238 bNeedRemove = False\r
239 for index in range(len(lines) - 1, -1, -1):\r
240 line = lines[index]\r
241 if line.find('Detailed Description') != -1:\r
242 bInDetail = False\r
243 if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'):\r
244 lines[index] = "IA32/IPF/X64/" + line\r
245 bNeedRemove = True\r
246 if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \\r
247 line.startswith('IA32 context buffer used by'):\r
248 if bNeedRemove:\r
249 lines.remove(line)\r
250 if line.find('>R0</a>') != -1 and not bInDetail:\r
251 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>':\r
252 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>')\r
253 if line.find('>Rbx</a>') != -1 and not bInDetail:\r
254 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>':\r
255 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')\r
256 if line.find('>F2</a>') != -1 and not bInDetail:\r
257 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>':\r
258 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>')\r
259 if line.find('>Ebx</a>') != -1 and not bInDetail:\r
260 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>':\r
261 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')\r
262 try:\r
263 f = open(path, 'w')\r
264 f.write('\n'.join(lines))\r
265 f.close()\r
266 except:\r
267 logging.getLogger().error(" <<< Fail to fixup file %s" % path)\r
268 return\r
269 print " <<< Finish to fixup file %s\n" % path\r
270\r
271def FixPageUefiDriverEntryPoint(path, text):\r
272 print ' >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path\r
273 lines = text.split('\n')\r
274 bInModuleEntry = False\r
275 bInEfiMain = False\r
276 ModuleEntryDlCount = 0\r
277 ModuleEntryDelStart = 0\r
278 ModuleEntryDelEnd = 0\r
279 EfiMainDlCount = 0\r
280 EfiMainDelStart = 0\r
281 EfiMainDelEnd = 0\r
282\r
283 for index in range(len(lines)):\r
284 line = lines[index].strip()\r
285 if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:\r
286 bInModuleEntry = True\r
287 if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:\r
288 bInEfiMain = True\r
289 if line.startswith('<p>References <a'):\r
290 if bInModuleEntry:\r
291 ModuleEntryDelEnd = index - 1\r
292 bInModuleEntry = False\r
293 elif bInEfiMain:\r
294 EfiMainDelEnd = index - 1\r
295 bInEfiMain = False\r
296 if bInModuleEntry:\r
297 if line.startswith('</dl>'):\r
298 ModuleEntryDlCount = ModuleEntryDlCount + 1\r
299 if ModuleEntryDlCount == 1:\r
300 ModuleEntryDelStart = index + 1\r
301 if bInEfiMain:\r
302 if line.startswith('</dl>'):\r
303 EfiMainDlCount = EfiMainDlCount + 1\r
304 if EfiMainDlCount == 1:\r
305 EfiMainDelStart = index + 1\r
306\r
307 if EfiMainDelEnd > EfiMainDelStart:\r
308 for index in range(EfiMainDelEnd, EfiMainDelStart, -1):\r
309 del lines[index]\r
310 if ModuleEntryDelEnd > ModuleEntryDelStart:\r
311 for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):\r
312 del lines[index]\r
313\r
314 try:\r
315 f = open(path, 'w')\r
316 f.write('\n'.join(lines))\r
317 f.close()\r
318 except:\r
319 logging.getLogger().error(" <<< Fail to fixup file %s" % path)\r
320 return\r
321 print " <<< Finish to fixup file %s\n" % path\r
322\r
323\r
324def FixPageUefiApplicationEntryPoint(path, text):\r
325 print ' >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path\r
326 lines = text.split('\n')\r
327 bInModuleEntry = False\r
328 bInEfiMain = False\r
329 ModuleEntryDlCount = 0\r
330 ModuleEntryDelStart = 0\r
331 ModuleEntryDelEnd = 0\r
332 EfiMainDlCount = 0\r
333 EfiMainDelStart = 0\r
334 EfiMainDelEnd = 0\r
335\r
336 for index in range(len(lines)):\r
337 line = lines[index].strip()\r
338 if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:\r
339 bInModuleEntry = True\r
340 if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:\r
341 bInEfiMain = True\r
342 if line.startswith('<p>References <a'):\r
343 if bInModuleEntry:\r
344 ModuleEntryDelEnd = index - 1\r
345 bInModuleEntry = False\r
346 elif bInEfiMain:\r
347 EfiMainDelEnd = index - 1\r
348 bInEfiMain = False\r
349 if bInModuleEntry:\r
350 if line.startswith('</dl>'):\r
351 ModuleEntryDlCount = ModuleEntryDlCount + 1\r
352 if ModuleEntryDlCount == 1:\r
353 ModuleEntryDelStart = index + 1\r
354 if bInEfiMain:\r
355 if line.startswith('</dl>'):\r
356 EfiMainDlCount = EfiMainDlCount + 1\r
357 if EfiMainDlCount == 1:\r
358 EfiMainDelStart = index + 1\r
359\r
360 if EfiMainDelEnd > EfiMainDelStart:\r
361 for index in range(EfiMainDelEnd, EfiMainDelStart, -1):\r
362 del lines[index]\r
363 if ModuleEntryDelEnd > ModuleEntryDelStart:\r
364 for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):\r
365 del lines[index]\r
366\r
367 try:\r
368 f = open(path, 'w')\r
369 f.write('\n'.join(lines))\r
370 f.close()\r
371 except:\r
372 logging.getLogger().error(" <<< Fail to fixup file %s" % path)\r
373 return\r
374 print " <<< Finish to fixup file %s\n" % path\r
375\r
376if __name__ == '__main__':\r
377 wspath, pkgpath, doxpath, outpath, archtag, docmode, isinc, hwpath = parseCmdArgs()\r
378\r
379 # configure logging system\r
380 logfilepath = os.path.join(outpath, 'log.txt')\r
381 logging.basicConfig(format='%(levelname)-8s %(message)s', level=logging.DEBUG)\r
382\r
383 # create package model object firstly\r
384 pkgObj = createPackageObject(wspath, pkgpath)\r
4231a819 385 if pkgObj is None:\r
7ccc9c95
YZ
386 sys.exit(-1)\r
387\r
388 # create doxygen action model\r
389 arch = None\r
390 tooltag = None\r
391 if archtag.lower() != 'all':\r
392 arch = archtag.split('_')[0]\r
393 tooltag = archtag.split('_')[1]\r
394 else:\r
395 arch = 'all'\r
396 tooltag = 'all'\r
397\r
398 # preprocess package and call doxygen\r
399 try:\r
400 action = doxygengen.PackageDocumentAction(doxpath,\r
401 hwpath,\r
402 outpath,\r
403 pkgObj,\r
404 docmode,\r
405 callbackLogMessage,\r
406 arch,\r
407 tooltag,\r
408 isinc,\r
409 True)\r
410 action.RegisterCallbackDoxygenProcess(callbackCreateDoxygenProcess)\r
411 action.Generate()\r
412 except:\r
413 message = traceback.format_exception(*sys.exc_info())\r
414 logging.getLogger().error('Fail to create doxygen action! \n%s' % ''.join(message))\r
415 sys.exit(-1)\r
416\r
417 DocumentFixup(outpath, arch)\r
418\r
419 # generate CHM is necessary\r
420 if docmode.lower() == 'chm':\r
421 indexpath = os.path.join(outpath, 'html', 'index.hhp')\r
422 if sys.platform == 'win32':\r
423 cmd = '"%s" %s' % (hwpath, indexpath)\r
424 else:\r
425 cmd = '%s %s' % (hwpath, indexpath)\r
426 subprocess.call(cmd)\r
427 print '\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.chm')\r
428 else:\r
429 print '\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.html')\r