blob: 35e1c1620618dfa0ceb215fe07b641b4bd0d0c1c [file] [log] [blame]
Joe Gregorio9d56b5a2012-03-30 09:21:26 -04001#!/usr/bin/python
2# -*- coding: utf-8 -*-
3#
4# Copyright (C) 2012 Google Inc.
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18"""Build wiki page with a list of all samples.
19
20The information for the wiki page is built from data found in all the README
21files in the samples. The format of the README file is:
22
23
24 Description is everything up to the first blank line.
25
26 api: plus (Used to look up the long name in discovery).
27 keywords: appengine (such as appengine, oauth2, cmdline)
28
29 The rest of the file is ignored when it comes to building the index.
30"""
31
32import httplib2
33import itertools
34import json
35import os
36import re
37
38http = httplib2.Http('.cache')
39r, c = http.request('https://www.googleapis.com/discovery/v1/apis')
40if r.status != 200:
41 raise ValueError('Received non-200 response when retrieving Discovery document.')
42
43# Dictionary mapping api names to their discovery description.
44DIRECTORY = {}
45for item in json.loads(c)['items']:
46 if item['preferred']:
47 DIRECTORY[item['name']] = item
48
49# A list of valid keywords. Should not be taken as complete, add to
50# this list as needed.
51KEYWORDS = {
52 'appengine': 'Google App Engine',
53 'oauth2': 'OAuth 2.0',
54 'cmdline': 'Command-line',
55 'django': 'Django',
56 'threading': 'Threading',
57 'pagination': 'Pagination'
58 }
59
60
61def get_lines(name, lines):
62 """Return lines that begin with name.
63
64 Lines are expected to look like:
65
66 name: space separated values
67
68 Args:
69 name: string, parameter name.
70 lines: iterable of string, lines in the file.
71
72 Returns:
73 List of values in the lines that match.
74 """
75 retval = []
76 matches = itertools.ifilter(lambda x: x.startswith(name + ':'), lines)
77 for line in matches:
78 retval.extend(line[len(name)+1:].split())
79 return retval
80
81
82def wiki_escape(s):
83 """Detect WikiSyntax (i.e. InterCaps, a.k.a. CamelCase) and escape it."""
84 ret = []
85 for word in s.split():
86 if re.match(r'[A-Z]+[a-z]+[A-Z]', word):
87 word = '!%s' % word
88 ret.append(word)
89 return ' '.join(ret)
90
91
92def context_from_sample(api, keywords, dirname, desc):
93 """Return info for expanding a sample into a template.
94
95 Args:
96 api: string, name of api.
97 keywords: list of string, list of keywords for the given api.
98 dirname: string, directory name of the sample.
99 desc: string, long description of the sample.
100
101 Returns:
102 A dictionary of values useful for template expansion.
103 """
104 if api is None:
105 return None
106 else:
107 entry = DIRECTORY[api]
108 context = {
109 'api': api,
110 'version': entry['version'],
111 'api_name': wiki_escape(entry.get('title', entry.get('description'))),
112 'api_desc': wiki_escape(entry['description']),
113 'api_icon': entry['icons']['x32'],
114 'keywords': keywords,
115 'dir': dirname,
116 'dir_escaped': dirname.replace('/', '%2F'),
117 'desc': wiki_escape(desc),
118 }
119 return context
120
121
122def keyword_context_from_sample(keywords, dirname, desc):
123 """Return info for expanding a sample into a template.
124
125 Sample may not be about a specific sample.
126
127 Args:
128 keywords: list of string, list of keywords for the given api.
129 dirname: string, directory name of the sample.
130 desc: string, long description of the sample.
131
132 Returns:
133 A dictionary of values useful for template expansion.
134 """
135 context = {
136 'keywords': keywords,
137 'dir': dirname,
138 'dir_escaped': dirname.replace('/', '%2F'),
139 'desc': wiki_escape(desc),
140 }
141 return context
142
143
144def scan_readme_files(dirname):
145 """Scans all subdirs of dirname for README files.
146
147 Args:
148 dirname: string, name of directory to walk.
149
150 Returns:
151 (samples, keyword_set): list of information about all samples, the union
152 of all keywords found.
153 """
154 samples = []
155 keyword_set = set()
156
157 for root, dirs, files in os.walk(dirname):
158 if 'README' in files:
159 filename = os.path.join(root, 'README')
160 with open(filename, 'r') as f:
161 content = f.read()
162 lines = content.splitlines()
163 desc = ' '.join(itertools.takewhile(lambda x: x, lines))
164 api = get_lines('api', lines)
165 keywords = get_lines('keywords', lines)
166
167 for k in keywords:
168 if k not in KEYWORDS:
169 raise ValueError(
170 '%s is not a valid keyword in file %s' % (k, filename))
171 keyword_set.update(keywords)
172 if not api:
173 api = [None]
174 samples.append((api[0], keywords, root[1:], desc))
175
176 samples.sort()
177
178 return samples, keyword_set
179
180
181def main():
182 # Get all the information we need out of the README files in the samples.
183 samples, keyword_set = scan_readme_files('./samples')
184
185 # Now build a wiki page with all that information. Accumulate all the
186 # information as string to be concatenated when were done.
187 page = ['<wiki:toc max_depth="3" />\n= Samples By API =\n']
188
189 # All the samples, grouped by API.
190 current_api = None
191 for api, keywords, dirname, desc in samples:
192 context = context_from_sample(api, keywords, dirname, desc)
193 if context is None:
194 continue
195 if current_api != api:
196 page.append("""
197=== %(api_icon)s %(api_name)s ===
198
199%(api_desc)s
200
201Documentation for the %(api_name)s in [http://api-python-client-doc.appspot.com/%(api)s/%(version)s PyDoc]
202
203""" % context)
204 current_api = api
205
206 page.append('|| [http://code.google.com/p/google-api-python-client/source/browse/#hg%(dir_escaped)s %(dir)s] || %(desc)s ||\n' % context)
207
208 # Now group the samples by keywords.
209 for keyword, keyword_name in KEYWORDS.iteritems():
210 if keyword not in keyword_set:
211 continue
212 page.append('\n= %s Samples =\n\n' % keyword_name)
213 page.append('<table border=1 cellspacing=0 cellpadding=8px>\n')
214 for _, keywords, dirname, desc in samples:
215 context = keyword_context_from_sample(keywords, dirname, desc)
216 if keyword not in keywords:
217 continue
218 page.append("""
219<tr>
220 <td>[http://code.google.com/p/google-api-python-client/source/browse/#hg%(dir_escaped)s %(dir)s] </td>
221 <td> %(desc)s </td>
222</tr>""" % context)
223 page.append('</table>\n')
224
225 print ''.join(page)
226
227
228if __name__ == '__main__':
229 main()