Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(560)

Side by Side Diff: chrome/common/extensions/docs/server2/converter.py

Issue 10832042: Extensions Docs Server: Doc conversion script (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: everything but svn stuff Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 # Example run from the server2/ directory:
7 # $ converter.py ../static/ ../../api templates/articles/ templates/intros/
8 # templates/public/ static/images/ -r
9
10 import optparse
11 import os
12 import re
13 import shutil
14
15 from docs_server_utils import SanitizeAPIName
16
17 IGNORED_FILES = [
18 # These are custom files.
19 '404',
20 'api_index',
21 'experimental',
22 'samples',
23 'index',
24 # These are APIs that should not have docs.
25 'test',
26 'experimental_idltest',
27 ]
28
29 # These are mappings for APIs that have no intros. They are needed because the
30 # names of the JSON files do not give enough information on the actual API name.
31 CUSTOM_MAPPINGS = {
32 'experimental_input_virtual_keyboard': 'experimental_input_virtualKeyboard',
33 'input_ime': 'input_ime'
34 }
35
36 def _ReadFile(filename):
37 with open(filename, 'r') as f:
38 return f.read()
39
40 def _WriteFile(filename, data):
41 with open(filename, 'w+') as f:
42 f.write(data)
43
44 def _UnixName(name):
45 """Returns the unix_style name for a given lowerCamelCase string.
46 Shamelessly stolen from json_schema_compiler/model.py.
47 """
48 name = os.path.splitext(name)[0]
49 s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name)
50 s2 = re.sub('([A-Z]+)([A-Z][a-z])', r'\1_\2', s1)
51 return s2.replace('.', '_').lower()
52
53 def _ListAllAPIs(dirname):
54 all_files = []
55 for path, dirs, files in os.walk(dirname):
56 if path == '.':
57 all_files.extend([f for f in files
58 if f.endswith('.json') or f.endswith('.idl')])
59 else:
60 all_files.extend([os.path.join(path, f) for f in files
61 if f.endswith('.json') or f.endswith('.idl')])
62 dirname = dirname.rstrip('/') + '/'
63 return [f[len(dirname):] for f in all_files
64 if os.path.splitext(f)[0].split('_')[-1] not in ['private',
65 'internal']]
66
67 def _MakeArticleTemplate(filename):
68 return '{{+partials.standard_article article:intros.%s}}' % filename
69
70 def _MakeAPITemplate(intro_name, api_name, has_intro):
71 if has_intro:
72 return ('{{+partials.standard_api api:apis.%s intro:intros.%s}}' %
73 (api_name, intro_name))
74 else:
75 return '{{+partials.standard_api api:apis.%s}}' % api_name
76
77 def _GetAPIPath(name, api_dir):
78 api_files = _ListAllAPIs(api_dir)
79 for filename in api_files:
80 if name == _UnixName(SanitizeAPIName(filename)):
81 return _UnixName(filename)
82
83 def _CleanAPIs(source_dir, api_dir, intros_dest, template_dest, exclude):
84 source_files = os.listdir(source_dir)
85 source_files_unix = set(_UnixName(f) for f in source_files)
86 api_files = set(_UnixName(SanitizeAPIName(f)) for f in _ListAllAPIs(api_dir))
87 intros_files = set(_UnixName(f) for f in os.listdir(intros_dest))
88 to_delete = api_files - source_files_unix - set(exclude)
89 for filename in os.listdir(template_dest):
90 no_ext = os.path.splitext(filename)[0]
91 # Check for changes like appWindow -> app.window.
92 if (_UnixName(filename) in source_files_unix - set(exclude) and
93 no_ext not in source_files):
94 os.remove(os.path.join(template_dest, filename))
95 if _UnixName(filename) in to_delete:
96 try:
97 os.remove(os.path.join(intros_dest, filename))
98 except OSError:
99 pass
100 os.remove(os.path.join(template_dest, filename))
101
102 def _FormatFile(contents, path, name, image_dest, replace, is_api):
103 # Copy all images referenced in the page.
104 for image in re.findall(r'src="\.\./images/([^"]*)"', contents):
105 if not replace and os.path.exists(os.path.join(image_dest, image)):
106 continue
107 if '/' in image:
108 try:
109 os.makedirs(os.path.join(image_dest, image.rsplit('/', 1)[0]))
110 except:
111 pass
112 shutil.copy(
113 os.path.join(path, os.pardir, 'images', image),
114 os.path.join(image_dest, image))
115 contents = re.sub(r'<!--.*?(BEGIN|END).*?-->', r'', contents)
116 contents = re.sub(r'\.\./images', r'{{static}}/images', contents)
117 exp = re.compile(r'<div[^>.]*?id="pageData-showTOC"[^>.]*?>.*?</div>',
118 flags=re.DOTALL)
119 contents = re.sub(exp, r'', contents)
120 exp = re.compile(r'<div[^>.]*?id="pageData-name"[^>.]*?>(.*?)</div>',
121 flags=re.DOTALL)
122 if is_api:
123 contents = re.sub(exp, r'', contents)
124 else:
125 contents = re.sub(exp, r'<h1>\1</h1>', contents)
126 contents = contents.strip()
127
128 # Attempt to guess if the page has no title.
129 if '<h1' not in contents and not is_api:
130 title = _UnixName(name)
131 title = ' '.join([part[0].upper() + part[1:] for part in title.split('_')])
132 contents = ('<h1 class="page_title">%s</h1>' % title) + contents
133 return contents
134
135 def _ProcessName(name):
136 processed_name = []
137 if name.startswith('experimental_'):
138 name = name[len('experimental_'):]
139 processed_name.append('experimental_')
140 parts = name.split('_')
141 processed_name.append(parts[0])
142 processed_name.extend([p[0].upper() + p[1:] for p in parts[1:]])
143 return ''.join(processed_name)
144
145 def _MoveAllFiles(source_dir,
146 api_dir,
147 articles_dest,
148 intros_dest,
149 template_dest,
150 image_dest,
151 replace=False,
152 exclude_dir=None):
153 if exclude_dir is None:
154 exclude_files = []
155 else:
156 exclude_files = [_UnixName(f) for f in os.listdir(exclude_dir)]
157 exclude_files.extend(IGNORED_FILES)
158 api_files = _ListAllAPIs(api_dir)
159 original_files = [os.path.splitext(f)[0] for f in os.listdir(template_dest)]
160 if replace:
161 _CleanAPIs(source_dir, api_dir, intros_dest, template_dest, exclude_files)
162 files = set(os.listdir(source_dir))
163 unix_files = [_UnixName(f) for f in files]
164 for name in [SanitizeAPIName(f) for f in _ListAllAPIs(api_dir)]:
165 if _UnixName(name) not in unix_files:
166 files.add(name + '.html')
167 for file_ in files:
168 if (_UnixName(file_) in exclude_files or
169 file_.startswith('.') or
170 file_.startswith('_')):
171 continue
172 _MoveSingleFile(source_dir,
173 file_,
174 api_dir,
175 articles_dest,
176 intros_dest,
177 template_dest,
178 image_dest,
179 replace=replace,
180 original_files=original_files)
181
182 def _MoveSingleFile(source_dir,
183 source_file,
184 api_dir,
185 articles_dest,
186 intros_dest,
187 template_dest,
188 image_dest,
189 replace=False,
190 original_files=None):
191 unix_name = _UnixName(source_file)
192 is_api = unix_name in [_UnixName(SanitizeAPIName(f))
193 for f in _ListAllAPIs(api_dir)]
194 if unix_name in CUSTOM_MAPPINGS:
195 processed_name = CUSTOM_MAPPINGS[unix_name]
196 else:
197 processed_name = os.path.splitext(source_file)[0].replace('.', '_')
198 if (is_api and
199 '_' in source_file.replace('experimental_', '') and
200 not os.path.exists(os.path.join(source_dir, source_file))):
201 processed_name = _ProcessName(processed_name)
202 if original_files is None or processed_name not in original_files:
203 print 'WARNING: The correct name of this file was guessed:'
204 print
205 print '%s -> %s' % (os.path.splitext(source_file)[0], processed_name)
206 print
207 print ('If this is incorrect, change |CUSTOM_MAPPINGS| in chrome/'
208 'common/extensions/docs/server2/converter.py.')
209 try:
210 static_data = _FormatFile(_ReadFile(os.path.join(source_dir, source_file)),
211 source_dir,
212 source_file,
213 image_dest,
214 replace,
215 is_api)
216 except IOError:
217 static_data = None
218 template_file = os.path.join(template_dest, processed_name + '.html')
219 if is_api:
220 template_data = _MakeAPITemplate(processed_name,
221 _GetAPIPath(unix_name, api_dir),
222 static_data is not None)
223 static_file = os.path.join(intros_dest, processed_name + '.html')
224 else:
225 template_data = _MakeArticleTemplate(unix_name)
226 static_file = os.path.join(articles_dest, processed_name + '.html')
227 if replace or not os.path.exists(template_file):
228 _WriteFile(template_file, template_data)
229 if static_data is not None and (replace or not os.path.exists(static_file)):
230 _WriteFile(static_file, static_data)
231
232 if __name__ == '__main__':
233 parser = optparse.OptionParser(
234 description='Converts static files from the old documentation system to '
235 'the new one. If run without -f, all the files in |src| will '
236 'be converted.',
237 usage='usage: %prog [options] static_src_dir [-f static_src_file] '
238 'api_dir articles_dest intros_dest template_dest image_dest')
239 parser.add_option('-f',
240 '--file',
241 action='store_true',
242 default=False,
243 help='convert single file')
244 parser.add_option('-e',
245 '--exclude',
246 default=None,
247 help='exclude files matching the names in this dir')
248 parser.add_option('-r',
249 '--replace',
250 action='store_true',
251 default=False,
252 help='replace existing files')
253 (opts, args) = parser.parse_args()
254 if (not opts.file and len(args) != 6) or (opts.file and len(args) != 7):
255 parser.error('incorrect number of arguments.')
256
257 if opts.file:
258 _MoveSingleFile(*args, replace=opts.replace)
259 else:
260 _MoveAllFiles(*args, replace=opts.replace, exclude_dir=opts.exclude)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698