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