/Mac/Tools/Doc/setup.py

http://unladen-swallow.googlecode.com/ · Python · 214 lines · 164 code · 23 blank · 27 comment · 21 complexity · cc4b7675b14a7bcfea9770cc135d1258 MD5 · raw file

  1. # Build and install an Apple Help Viewer compatible version of the Python
  2. # documentation into the framework.
  3. # Code by Bill Fancher, with some modifications by Jack Jansen.
  4. #
  5. # You must run this as a two-step process
  6. # 1. python setupDocs.py build
  7. # 2. Wait for Apple Help Indexing Tool to finish
  8. # 3. python setupDocs.py install
  9. #
  10. # To do:
  11. # - test whether the docs are available locally before downloading
  12. # - fix buildDocsFromSource
  13. # - Get documentation version from sys.version, fallback to 2.2.1
  14. # - See if we can somehow detect that Apple Help Indexing Tool is finished
  15. # - data_files to setup() doesn't seem the right way to pass the arguments
  16. #
  17. import sys, os, re
  18. from distutils.cmd import Command
  19. from distutils.command.build import build
  20. from distutils.core import setup
  21. from distutils.file_util import copy_file
  22. from distutils.dir_util import copy_tree
  23. from distutils.log import log
  24. from distutils.spawn import spawn
  25. from distutils import sysconfig, dep_util
  26. from distutils.util import change_root
  27. import HelpIndexingTool
  28. import Carbon.File
  29. import time
  30. MAJOR_VERSION='2.4'
  31. MINOR_VERSION='2.4.1'
  32. DESTDIR='/Applications/MacPython-%s/PythonIDE.app/Contents/Resources/English.lproj/PythonDocumentation' % MAJOR_VERSION
  33. class DocBuild(build):
  34. def initialize_options(self):
  35. build.initialize_options(self)
  36. self.build_html = None
  37. self.build_dest = None
  38. self.download = 1
  39. self.doc_version = MINOR_VERSION # Only needed if download is true
  40. def finalize_options(self):
  41. build.finalize_options(self)
  42. if self.build_html is None:
  43. self.build_html = os.path.join(self.build_base, 'html')
  44. if self.build_dest is None:
  45. self.build_dest = os.path.join(self.build_base, 'PythonDocumentation')
  46. def spawn(self, *args):
  47. spawn(args, 1, self.verbose, self.dry_run)
  48. def downloadDocs(self):
  49. workdir = os.getcwd()
  50. # XXX Note: the next strings may change from version to version
  51. url = 'http://www.python.org/ftp/python/doc/%s/html-%s.tar.bz2' % \
  52. (self.doc_version,self.doc_version)
  53. tarfile = 'html-%s.tar.bz2' % self.doc_version
  54. dirname = 'Python-Docs-%s' % self.doc_version
  55. if os.path.exists(self.build_html):
  56. raise RuntimeError, '%s: already exists, please remove and try again' % self.build_html
  57. os.chdir(self.build_base)
  58. self.spawn('curl','-O', url)
  59. self.spawn('tar', '-xjf', tarfile)
  60. os.rename(dirname, 'html')
  61. os.chdir(workdir)
  62. ## print "** Please unpack %s" % os.path.join(self.build_base, tarfile)
  63. ## print "** Unpack the files into %s" % self.build_html
  64. ## raise RuntimeError, "You need to unpack the docs manually"
  65. def buildDocsFromSource(self):
  66. srcdir = '../../..'
  67. docdir = os.path.join(srcdir, 'Doc')
  68. htmldir = os.path.join(docdir, 'html')
  69. spawn(('make','--directory', docdir, 'html'), 1, self.verbose, self.dry_run)
  70. self.mkpath(self.build_html)
  71. copy_tree(htmldir, self.build_html)
  72. def ensureHtml(self):
  73. if not os.path.exists(self.build_html):
  74. if self.download:
  75. self.downloadDocs()
  76. else:
  77. self.buildDocsFromSource()
  78. def hackIndex(self):
  79. ind_html = 'index.html'
  80. #print 'self.build_dest =', self.build_dest
  81. hackedIndex = file(os.path.join(self.build_dest, ind_html),'w')
  82. origIndex = file(os.path.join(self.build_html,ind_html))
  83. r = re.compile('<style type="text/css">.*</style>', re.DOTALL)
  84. hackedIndex.write(r.sub('<META NAME="AppleTitle" CONTENT="Python Documentation">',origIndex.read()))
  85. def hackFile(self,d,f):
  86. origPath = os.path.join(d,f)
  87. assert(origPath[:len(self.build_html)] == self.build_html)
  88. outPath = os.path.join(self.build_dest, d[len(self.build_html)+1:], f)
  89. (name, ext) = os.path.splitext(f)
  90. if os.path.isdir(origPath):
  91. self.mkpath(outPath)
  92. elif ext == '.html':
  93. if self.verbose: print 'hacking %s to %s' % (origPath,outPath)
  94. hackedFile = file(outPath, 'w')
  95. origFile = file(origPath,'r')
  96. hackedFile.write(self.r.sub('<dl><dt><dd>', origFile.read()))
  97. else:
  98. copy_file(origPath, outPath)
  99. def hackHtml(self):
  100. self.r = re.compile('<dl><dd>')
  101. os.path.walk(self.build_html, self.visit, None)
  102. def visit(self, dummy, dirname, filenames):
  103. for f in filenames:
  104. self.hackFile(dirname, f)
  105. def makeHelpIndex(self):
  106. app = '/Developer/Applications/Apple Help Indexing Tool.app'
  107. self.spawn('open', '-a', app , self.build_dest)
  108. print "Please wait until Apple Help Indexing Tool finishes before installing"
  109. def makeHelpIndex(self):
  110. app = HelpIndexingTool.HelpIndexingTool(start=1)
  111. app.open(Carbon.File.FSSpec(self.build_dest))
  112. sys.stderr.write("Waiting for Help Indexing Tool to start...")
  113. while 1:
  114. # This is bad design in the suite generation code!
  115. idle = app._get(HelpIndexingTool.Help_Indexing_Tool_Suite._Prop_idleStatus())
  116. time.sleep(10)
  117. if not idle: break
  118. sys.stderr.write(".")
  119. sys.stderr.write("\n")
  120. sys.stderr.write("Waiting for Help Indexing Tool to finish...")
  121. while 1:
  122. # This is bad design in the suite generation code!
  123. idle = app._get(HelpIndexingTool.Help_Indexing_Tool_Suite._Prop_idleStatus())
  124. time.sleep(10)
  125. if idle: break
  126. sys.stderr.write(".")
  127. sys.stderr.write("\n")
  128. def run(self):
  129. self.ensure_finalized()
  130. self.mkpath(self.build_base)
  131. self.ensureHtml()
  132. if not os.path.isdir(self.build_html):
  133. raise RuntimeError, \
  134. "Can't find source folder for documentation."
  135. self.mkpath(self.build_dest)
  136. if dep_util.newer(os.path.join(self.build_html,'index.html'), os.path.join(self.build_dest,'index.html')):
  137. self.mkpath(self.build_dest)
  138. self.hackHtml()
  139. self.hackIndex()
  140. self.makeHelpIndex()
  141. class AHVDocInstall(Command):
  142. description = "install Apple Help Viewer html files"
  143. user_options = [('install-doc=', 'd',
  144. 'directory to install HTML tree'),
  145. ('root=', None,
  146. "install everything relative to this alternate root directory"),
  147. ]
  148. def initialize_options(self):
  149. self.build_dest = None
  150. self.install_doc = None
  151. self.prefix = None
  152. self.root = None
  153. def finalize_options(self):
  154. self.set_undefined_options('install',
  155. ('prefix', 'prefix'),
  156. ('root', 'root'))
  157. # import pdb ; pdb.set_trace()
  158. build_cmd = self.get_finalized_command('build')
  159. if self.build_dest is None:
  160. build_cmd = self.get_finalized_command('build')
  161. self.build_dest = build_cmd.build_dest
  162. if self.install_doc is None:
  163. self.install_doc = os.path.join(self.prefix, DESTDIR)
  164. print 'INSTALL', self.build_dest, '->', self.install_doc
  165. def run(self):
  166. self.finalize_options()
  167. self.ensure_finalized()
  168. print "Running Installer"
  169. instloc = self.install_doc
  170. if self.root:
  171. instloc = change_root(self.root, instloc)
  172. self.mkpath(instloc)
  173. copy_tree(self.build_dest, instloc)
  174. print "Installation complete"
  175. def mungeVersion(infile, outfile):
  176. i = file(infile,'r')
  177. o = file(outfile,'w')
  178. o.write(re.sub('\$\(VERSION\)',sysconfig.get_config_var('VERSION'),i.read()))
  179. i.close()
  180. o.close()
  181. def main():
  182. # turn off warnings when deprecated modules are imported
  183. ## import warnings
  184. ## warnings.filterwarnings("ignore",category=DeprecationWarning)
  185. setup(name = 'Documentation',
  186. version = '%d.%d' % sys.version_info[:2],
  187. cmdclass = {'install_data':AHVDocInstall, 'build':DocBuild},
  188. data_files = ['dummy'],
  189. )
  190. if __name__ == '__main__':
  191. main()