Browse Source

Buildsite changes to use YAML API docs

pull/156/head
Sami Vaarala 10 years ago
parent
commit
3e6d355663
  1. 140
      website/buildsite.py

140
website/buildsite.py

@ -5,6 +5,7 @@
import os
import sys
import traceback
import time
import datetime
import shutil
@ -12,6 +13,8 @@ import re
import tempfile
import atexit
import md5
import json
import yaml
from bs4 import BeautifulSoup, Tag
colorize = True
@ -92,6 +95,13 @@ def stripNewline(x):
return x[:-1]
return x
def splitNewlineNoLastEmpty(x):
assert(x is not None)
res = x.split('\n')
if len(res) > 0 and res[-1] == '':
res = res[:-1]
return res
def validateAndParseHtml(data):
# first parse as xml to get errors out
ign_soup = BeautifulSoup(data, 'xml')
@ -186,36 +196,6 @@ def renderFancyStack(inp_line):
return ' '.join(res) + '\n' # stack is a one-liner; spaces are for text browser rendering
def parseApiDoc(filename):
f = open(filename, 'rb')
parts = {}
state = None
for line in f.readlines():
line = stripNewline(line)
if line.startswith('='):
state = line[1:]
elif state is not None:
if not parts.has_key(state):
parts[state] = []
parts[state].append(line)
else:
if line != '':
raise Exception('unparsed non-empty line: %r' % line)
else:
# ignore
pass
f.close()
# remove leading and trailing empty lines
for k in parts:
p = parts[k]
while len(p) > 0 and p[0] == '':
p.pop(0)
while len(p) > 0 and p[-1] == '':
p.pop()
return parts
# C99: these are used if available
type_repl_c99_32bit = [
['duk_int_t', 'int' ],
@ -275,22 +255,22 @@ def substitutePrototypeTypes(line, repl):
line = line.replace(t[0], t[1])
return line
def processApiDoc(parts, funcname, testrefs, used_tags):
def processApiDoc(doc, testrefs, used_tags):
res = []
# the 'hidechar' span is to allow browser search without showing the char
res.append('<h1 id="%s" class="apih1">' % funcname)
res.append('<a href="#%s"><span class="hidechar">.</span>%s()</a>' % (funcname, funcname))
if floating_list_tags and parts.has_key('tags'):
p = sorted(parts['tags'], reverse=True) # reversed because floated to right (which reverses DOM order)
res.append('<h1 id="%s" class="apih1">' % doc['name'])
res.append('<a href="#%s"><span class="hidechar">.</span>%s()</a>' % (doc['name'], doc['name']))
if floating_list_tags and len(doc['tags']) > 0:
p = sorted(doc['tags'], reverse=True) # reversed because floated to right (which reverses DOM order)
# For now, add the introduced version as a tag
if parts.has_key('introduced'):
p = [ parts['introduced'][0] ] + p
if parts.has_key('deprecated'):
if doc.has_key('introduced'):
p = [ doc['introduced'] ] + p
if doc.has_key('deprecated'):
# XXX: must mark deprecation
pass
if parts.has_key('removed'):
if doc.has_key('removed'):
# XXX: must mark removal
pass
@ -306,8 +286,8 @@ def processApiDoc(parts, funcname, testrefs, used_tags):
res.append('<div class="api-call">')
if parts.has_key('proto'):
p = parts['proto']
if doc.has_key('proto'):
p = splitNewlineNoLastEmpty(doc['proto'])
res.append('<div class="api-part">')
res.append('<h2 class="api-proto">Prototype</h2>')
alt_typing_c99 = []
@ -334,10 +314,11 @@ def processApiDoc(parts, funcname, testrefs, used_tags):
else:
pass
if parts.has_key('stack'):
p = parts['stack']
if doc.has_key('stack'):
p = splitNewlineNoLastEmpty(doc['stack'])
res.append('<div class="api-part">')
res.append('<h2 class="api-stack">Stack</h2>')
assert(len(p) > 0)
for line in p:
res.append('<pre class="stack">' + \
'%s' % htmlEscape(line) + \
@ -351,8 +332,8 @@ def processApiDoc(parts, funcname, testrefs, used_tags):
res.append('</div>') # api-part
res.append('')
if parts.has_key('summary'):
p = parts['summary']
if doc.has_key('summary'):
p = splitNewlineNoLastEmpty(doc['summary'])
res.append('<div class="api-part">')
res.append('<h2 class="api-summary">Summary</h2>')
@ -376,8 +357,8 @@ def processApiDoc(parts, funcname, testrefs, used_tags):
res.append('</div>') # api-part
res.append('')
if parts.has_key('example'):
p = parts['example']
if doc.has_key('example'):
p = splitNewlineNoLastEmpty(doc['example'])
res.append('<div class="api-part">')
res.append('<h2 class="api-example">Example</h2>')
res.append('<pre class="c-code">')
@ -387,8 +368,8 @@ def processApiDoc(parts, funcname, testrefs, used_tags):
res.append('</div>') # api-part
res.append('')
if parts.has_key('seealso'):
p = parts['seealso']
if doc.has_key('seealso'):
p = doc['seealso']
res.append('<div class="api-part">')
res.append('<h2 class="api-seealso">See also</h2>')
res.append('<ul>')
@ -401,9 +382,9 @@ def processApiDoc(parts, funcname, testrefs, used_tags):
if testcase_refs:
res.append('<div class="api-part">')
res.append('<h2 class="api-testcases">Related test cases</h2>')
if testrefs.has_key(funcname):
if testrefs.has_key(doc['name']):
res.append('<ul>')
for i in testrefs[funcname]:
for i in testrefs[doc['name']]:
res.append('<li>%s</li>' % htmlEscape(i))
res.append('</ul>')
else:
@ -411,15 +392,15 @@ def processApiDoc(parts, funcname, testrefs, used_tags):
res.append('</div>') # api-part
res.append('')
if not testrefs.has_key(funcname):
if not testrefs.has_key(doc['name']):
res.append('<div class="fixme">This API call has no test cases.</div>')
if list_tags and parts.has_key('tags'):
if list_tags and len(doc['tags']) > 0:
# FIXME: placeholder
res.append('<div class="api-part">')
res.append('<h2 class="api-tags">Tags</h2>')
res.append('<p>')
p = parts['tags']
p = doc['tags']
for idx, val in enumerate(p):
if idx > 0:
res.append(' ')
@ -428,8 +409,8 @@ def processApiDoc(parts, funcname, testrefs, used_tags):
res.append('</div>') # api-part
res.append('')
if parts.has_key('fixme'):
p = parts['fixme']
if doc.has_key('fixme'):
p = splitNewlineNoLastEmpty(doc['fixme'])
res.append('<div class="fixme">')
for i in p:
res.append(htmlEscape(i))
@ -704,9 +685,7 @@ def createTagIndex(api_docs, used_tags):
res.append('<h2 id="taglist-' + htmlEscape(tag) + '">' + htmlEscape(tag) + '</h2>')
res.append('<ul class="taglist">')
for doc in api_docs:
if not doc['parts'].has_key('tags'):
continue
for i in doc['parts']['tags']:
for i in doc['tags']:
if i != tag:
continue
res.append('<li><a href="#%s">%s</a></li>' % (htmlEscape(doc['name']), htmlEscape(doc['name'])))
@ -723,7 +702,7 @@ def generateApiDoc(apidocdir, apitestdir):
tmpfiles = os.listdir(apidocdir)
apifiles = []
for filename in tmpfiles:
if os.path.splitext(filename)[1] == '.txt':
if os.path.splitext(filename)[1] == '.yaml':
apifiles.append(filename)
apifiles.sort()
#print(apifiles)
@ -743,19 +722,40 @@ def generateApiDoc(apidocdir, apitestdir):
# scan api doc files
used_tags = []
api_docs = [] # [ { 'parts': xxx, 'name': xxx } ]
api_docs = [] # structure from YAML file directly
for filename in apifiles:
parts = parseApiDoc(os.path.join(apidocdir, filename))
apidoc = None
try:
with open(os.path.join(apidocdir, filename), 'rb') as f:
apidoc = yaml.safe_load(f)
if isinstance(apidoc, (str, unicode)):
apidoc = None
raise Exception('parsed as string')
except:
print 'WARNING: FAILED TO PARSE API DOC: ' + str(filename)
print traceback.format_exc()
pass
funcname = os.path.splitext(os.path.basename(filename))[0]
if parts.has_key('tags') and 'omit' in parts['tags']:
print 'Omit API doc: ' + str(funcname)
continue
if parts.has_key('tags'):
for i in parts['tags']:
#print(json.dumps(apidoc, indent=4))
if apidoc is not None:
if not apidoc.has_key('tags'):
apidoc['tags'] = [] # ensures tags is present
apidoc['name'] = funcname # add funcname automatically
if 'omit' in apidoc['tags']:
print 'Omit API doc: ' + str(funcname)
continue
for i in apidoc['tags']:
assert(i is not None)
if i not in used_tags:
used_tags.append(i)
api_docs.append({ 'parts': parts, 'name': funcname })
api_docs.append(apidoc)
used_tags.sort()
@ -805,11 +805,11 @@ def generateApiDoc(apidocdir, apitestdir):
data = None
try:
data = processApiDoc(doc['parts'], doc['name'], testrefs, used_tags)
data = processApiDoc(doc, testrefs, used_tags)
res += data
except:
print repr(data)
print 'FAIL: ' + repr(filename)
print 'FAIL: ' + repr(doc['name'])
raise
print('used tags: ' + repr(used_tags))

Loading…
Cancel
Save