3 # Copyright (c) 2014 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
18 if sys
.version_info
< (2, 7, 0):
19 sys
.stderr
.write("python 2.7 or later is required run this script\n")
23 SCRIPT_DIR
= os
.path
.dirname(os
.path
.abspath(__file__
))
24 DOC_DIR
= os
.path
.dirname(SCRIPT_DIR
)
27 ChannelInfo
= collections
.namedtuple('ChannelInfo', ['branch', 'version'])
32 sys
.stderr
.write(str(msg
) + '\n')
38 url
= 'http://omahaproxy.appspot.com/json'
39 u
= urllib2
.urlopen(url
)
41 data
= json
.loads(u
.read())
48 if osname
not in ('win', 'mac', 'linux'):
50 for version_row
in os_row
['versions']:
51 channel
= version_row
['channel']
52 # We don't display canary docs.
53 if channel
== 'canary':
56 version
= version_row
['version'].split('.')[0] # Major version
57 branch
= version_row
['true_branch']
61 if channel
in channel_info
:
62 existing_info
= channel_info
[channel
]
63 if branch
!= existing_info
.branch
:
64 sys
.stderr
.write('Warning: found different branch numbers for '
65 'channel %s: %s vs %s. Using %s.\n' % (
66 channel
, branch
, existing_info
.branch
, existing_info
.branch
))
68 channel_info
[channel
] = ChannelInfo(branch
, version
)
73 def RemoveFile(filename
):
74 if os
.path
.exists(filename
):
78 def RemoveDir(dirname
):
79 if os
.path
.exists(dirname
):
80 shutil
.rmtree(dirname
)
84 cmd
= ['git', 'for-each-ref', '--format=%(refname)',
85 'refs/remotes/branch-heads']
86 output
= subprocess
.check_output(cmd
).splitlines()
90 def CheckoutDirectories(dest_dirname
, refname
, root_path
, patterns
=None):
91 treeish
= '%s:%s' % (refname
, root_path
)
92 cmd
= ['git', 'ls-tree', '--full-tree', '-r', treeish
]
96 Trace('Running \"%s\":' % ' '.join(cmd
))
97 output
= subprocess
.check_output(cmd
)
98 for line
in output
.splitlines():
99 info
, rel_filename
= line
.split('\t')
100 sha
= info
.split(' ')[2]
102 Trace(' %s %s' % (sha
, rel_filename
))
104 cmd
= ['git', 'show', sha
]
105 blob
= subprocess
.check_output(cmd
)
106 filename
= os
.path
.join(dest_dirname
, rel_filename
)
107 dirname
= os
.path
.dirname(filename
)
108 if not os
.path
.exists(dirname
):
111 Trace(' writing to %s' % filename
)
112 with
open(filename
, 'w') as f
:
116 def CheckoutPepperDocs(branch
, doc_dirname
):
117 Trace('Removing directory %s' % doc_dirname
)
118 RemoveDir(doc_dirname
)
120 if branch
== 'master':
121 refname
= 'refs/remotes/origin/master'
123 refname
= 'refs/remotes/branch-heads/%s' % branch
125 Trace('Checking out docs into %s' % doc_dirname
)
126 subdirs
= ['api', 'generators', 'cpp', 'utility']
127 CheckoutDirectories(doc_dirname
, refname
, 'ppapi', subdirs
)
129 # The IDL generator needs PLY (a python lexing library); check it out into
131 ply_dirname
= os
.path
.join(doc_dirname
, 'generators', 'ply')
132 Trace('Checking out PLY into %s' % ply_dirname
)
133 CheckoutDirectories(ply_dirname
, refname
, 'third_party/ply')
136 def FixPepperDocLinks(doc_dirname
):
137 # TODO(binji): We can remove this step when the correct links are in the
139 Trace('Looking for links to fix in Pepper headers...')
140 for root
, dirs
, filenames
in os
.walk(doc_dirname
):
141 # Don't recurse into .svn
145 for filename
in filenames
:
146 header_filename
= os
.path
.join(root
, filename
)
147 Trace(' Checking file %r...' % header_filename
)
149 '<a href="/native-client/{{pepperversion}}/devguide/coding/audio">':
150 '<a href="/native-client/devguide/coding/audio.html">',
151 '<a href="/native-client/devguide/coding/audio">':
152 '<a href="/native-client/devguide/coding/audio.html">',
153 '<a href="/native-client/{{pepperversion}}/pepperc/globals_defs"':
154 '<a href="globals_defs.html"',
155 '<a href="../pepperc/ppb__image__data_8h.html">':
156 '<a href="../c/ppb__image__data_8h.html">'}
158 with
open(header_filename
) as f
:
162 for find
, replace
in replacements
.iteritems():
163 pos
= line
.find(find
)
165 Trace(' Found %r...' % find
)
167 line
= line
[:pos
] + replace
+ line
[pos
+ len(find
):]
171 Trace(' Writing new file.')
172 with
open(header_filename
, 'w') as f
:
176 def GenerateCHeaders(pepper_version
, doc_dirname
):
177 script
= os
.path
.join(os
.pardir
, 'generators', 'generator.py')
178 cwd
= os
.path
.join(doc_dirname
, 'api')
179 out_dirname
= os
.path
.join(os
.pardir
, 'c')
180 cmd
= [sys
.executable
, script
, '--cgen', '--release', 'M' + pepper_version
,
181 '--wnone', '--dstroot', out_dirname
]
182 Trace('Generating C Headers for version %s\n %s' % (
183 pepper_version
, ' '.join(cmd
)))
184 subprocess
.check_call(cmd
, cwd
=cwd
)
187 def GenerateDoxyfile(template_filename
, out_dirname
, doc_dirname
, doxyfile
):
188 Trace('Writing Doxyfile "%s" (from template %s)' % (
189 doxyfile
, template_filename
))
191 with
open(template_filename
) as f
:
194 with
open(doxyfile
, 'w') as f
:
196 'out_dirname': out_dirname
,
197 'doc_dirname': doc_dirname
,
198 'script_dirname': SCRIPT_DIR
})
201 def RunDoxygen(out_dirname
, doxyfile
):
202 Trace('Removing old output directory %s' % out_dirname
)
203 RemoveDir(out_dirname
)
205 Trace('Making new output directory %s' % out_dirname
)
206 os
.makedirs(out_dirname
)
208 doxygen
= os
.environ
.get('DOXYGEN', 'doxygen')
209 cmd
= [doxygen
, doxyfile
]
210 Trace('Running Doxygen:\n %s' % ' '.join(cmd
))
211 subprocess
.check_call(cmd
)
214 def RunDoxyCleanup(out_dirname
):
215 script
= os
.path
.join(SCRIPT_DIR
, 'doxy_cleanup.py')
216 cmd
= [sys
.executable
, script
, out_dirname
]
219 Trace('Running doxy_cleanup:\n %s' % ' '.join(cmd
))
220 subprocess
.check_call(cmd
)
223 def RunRstIndex(kind
, channel
, pepper_version
, out_dirname
, out_rst_filename
):
224 assert kind
in ('root', 'c', 'cpp')
225 script
= os
.path
.join(SCRIPT_DIR
, 'rst_index.py')
226 cmd
= [sys
.executable
, script
,
228 '--channel', channel
,
229 '--version', pepper_version
,
231 '-o', out_rst_filename
]
232 Trace('Running rst_index:\n %s' % ' '.join(cmd
))
233 subprocess
.check_call(cmd
)
236 def GetRstName(kind
, channel
):
237 if channel
== 'stable':
238 filename
= '%s-api.rst' % kind
240 filename
= '%s-api-%s.rst' % (kind
, channel
)
241 return os
.path
.join(DOC_DIR
, filename
)
244 def GenerateDocs(root_dirname
, channel
, pepper_version
, branch
):
245 Trace('Generating docs for %s (branch %s)' % (channel
, branch
))
246 pepper_dirname
= 'pepper_%s' % channel
247 out_dirname
= os
.path
.join(root_dirname
, pepper_dirname
)
250 svn_dirname
= tempfile
.mkdtemp(prefix
=pepper_dirname
)
251 doxyfile_dirname
= tempfile
.mkdtemp(prefix
='%s_doxyfiles' % pepper_dirname
)
253 CheckoutPepperDocs(branch
, svn_dirname
)
254 FixPepperDocLinks(svn_dirname
)
255 GenerateCHeaders(pepper_version
, svn_dirname
)
260 # Generate Root index
261 rst_index_root
= os
.path
.join(DOC_DIR
, pepper_dirname
, 'index.rst')
262 RunRstIndex('root', channel
, pepper_version
, out_dirname
, rst_index_root
)
265 out_dirname_c
= os
.path
.join(out_dirname
, 'c')
266 doxyfile_c
= os
.path
.join(doxyfile_dirname
, 'Doxyfile.c.%s' % channel
)
267 doxyfile_c_template
= os
.path
.join(SCRIPT_DIR
, 'Doxyfile.c.template')
268 rst_index_c
= GetRstName('c', channel
)
269 GenerateDoxyfile(doxyfile_c_template
, out_dirname_c
, svn_dirname
,
271 RunDoxygen(out_dirname_c
, doxyfile_c
)
272 RunDoxyCleanup(out_dirname_c
)
273 RunRstIndex('c', channel
, pepper_version
, out_dirname_c
, rst_index_c
)
276 out_dirname_cpp
= os
.path
.join(out_dirname
, 'cpp')
277 doxyfile_cpp
= os
.path
.join(doxyfile_dirname
, 'Doxyfile.cpp.%s' % channel
)
278 doxyfile_cpp_template
= os
.path
.join(SCRIPT_DIR
, 'Doxyfile.cpp.template')
279 rst_index_cpp
= GetRstName('cpp', channel
)
280 GenerateDoxyfile(doxyfile_cpp_template
, out_dirname_cpp
, svn_dirname
,
282 RunDoxygen(out_dirname_cpp
, doxyfile_cpp
)
283 RunDoxyCleanup(out_dirname_cpp
)
284 RunRstIndex('cpp', channel
, pepper_version
, out_dirname_cpp
, rst_index_cpp
)
287 RemoveDir(svn_dirname
)
288 RemoveDir(doxyfile_dirname
)
292 parser
= optparse
.OptionParser(usage
='Usage: %prog [options] <out_directory>')
293 parser
.add_option('-v', '--verbose',
294 help='Verbose output', action
='store_true')
295 options
, dirs
= parser
.parse_args(argv
)
301 parser
.error('Expected an output directory')
303 channel_info
= GetChannelInfo()
304 for channel
, info
in channel_info
.iteritems():
305 GenerateDocs(dirs
[0], channel
, info
.version
, info
.branch
)
310 if __name__
== '__main__':
312 rtn
= main(sys
.argv
[1:])
313 except KeyboardInterrupt:
314 sys
.stderr
.write('%s: interrupted\n' % os
.path
.basename(__file__
))