Merge pull request #60 from matrix-org/gendoc-logging

Gendoc logging
This commit is contained in:
Kegsay 2015-09-23 16:52:24 +01:00
commit 0346568519
5 changed files with 95 additions and 47 deletions

View file

@ -1,5 +1,6 @@
#! /usr/bin/env python #! /usr/bin/env python
from argparse import ArgumentParser
from docutils.core import publish_file from docutils.core import publish_file
import copy import copy
import fileinput import fileinput
@ -17,6 +18,7 @@ stylesheets = {
"stylesheet_path": ["basic.css", "nature.css", "codehighlight.css"] "stylesheet_path": ["basic.css", "nature.css", "codehighlight.css"]
} }
VERBOSE = False
""" """
Read a RST file and replace titles with a different title level if required. Read a RST file and replace titles with a different title level if required.
@ -64,8 +66,8 @@ def load_with_adjusted_titles(filename, file_stream, title_level, title_styles):
if file_offset is None: if file_offset is None:
file_offset = line_title_level file_offset = line_title_level
if file_offset != 0: if file_offset != 0:
print (" WARNING: %s starts with a title style of '%s' but '%s' " + logv((" WARNING: %s starts with a title style of '%s' but '%s' " +
"is preferable.") % (filename, line_title_style, title_styles[0]) "is preferable.") % (filename, line_title_style, title_styles[0]))
# Sanity checks: Make sure that this file is obeying the title levels # Sanity checks: Make sure that this file is obeying the title levels
# specified and bail if it isn't. # specified and bail if it isn't.
@ -101,12 +103,11 @@ def load_with_adjusted_titles(filename, file_stream, title_level, title_styles):
continue continue
# Adjusting line levels # Adjusting line levels
# print ( logv(
# "File: %s Adjusting %s to %s because file_offset=%s title_offset=%s" % "File: %s Adjusting %s to %s because file_offset=%s title_offset=%s" %
# (filename, line_title_style, (filename, line_title_style, title_styles[adjusted_level],
# title_styles[adjusted_level], file_offset, title_level)
# file_offset, title_level) )
# )
rst_lines.append(line.replace( rst_lines.append(line.replace(
line_title_style, line_title_style,
title_styles[adjusted_level] title_styles[adjusted_level]
@ -118,7 +119,7 @@ def load_with_adjusted_titles(filename, file_stream, title_level, title_styles):
def get_rst(file_info, title_level, title_styles, spec_dir, adjust_titles): def get_rst(file_info, title_level, title_styles, spec_dir, adjust_titles):
# string are file paths to RST blobs # string are file paths to RST blobs
if isinstance(file_info, basestring): if isinstance(file_info, basestring):
print "%s %s" % (">" * (1 + title_level), file_info) log("%s %s" % (">" * (1 + title_level), file_info))
with open(os.path.join(spec_dir, file_info), "r") as f: with open(os.path.join(spec_dir, file_info), "r") as f:
rst = None rst = None
if adjust_titles: if adjust_titles:
@ -240,19 +241,24 @@ def rst2html(i, o):
) )
def run_through_template(input): def run_through_template(input, set_verbose):
tmpfile = './tmp/output' tmpfile = './tmp/output'
try: try:
with open(tmpfile, 'w') as out: with open(tmpfile, 'w') as out:
args = [
'python', 'build.py',
"-i", "matrix_templates",
"-o", "../scripts/tmp",
"../scripts/"+input
]
if set_verbose:
args.insert(2, "-v")
log("EXEC: %s" % " ".join(args))
log(" ==== build.py output ==== ")
print subprocess.check_output( print subprocess.check_output(
[ args,
'python', 'build.py', "-v",
"-i", "matrix_templates",
"-o", "../scripts/tmp",
"../scripts/"+input
],
stderr=out, stderr=out,
cwd="../templating", cwd="../templating"
) )
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
with open(tmpfile, 'r') as f: with open(tmpfile, 'r') as f:
@ -347,6 +353,13 @@ def get_build_target(targets_listing, target_name):
build_target["files"] = resolved_files build_target["files"] = resolved_files
return build_target return build_target
def log(line):
print "gendoc: %s" % line
def logv(line):
if VERBOSE:
print "gendoc:V: %s" % line
def prepare_env(): def prepare_env():
try: try:
@ -363,36 +376,43 @@ def cleanup_env():
shutil.rmtree("./tmp") shutil.rmtree("./tmp")
def main(target_name): def main(target_name, keep_intermediates):
prepare_env() prepare_env()
print "Building spec [target=%s]" % target_name log("Building spec [target=%s]" % target_name)
target = get_build_target("../specification/targets.yaml", target_name) target = get_build_target("../specification/targets.yaml", target_name)
build_spec(target=target, out_filename="tmp/templated_spec.rst") build_spec(target=target, out_filename="tmp/templated_spec.rst")
run_through_template("tmp/templated_spec.rst") run_through_template("tmp/templated_spec.rst", VERBOSE)
fix_relative_titles( fix_relative_titles(
target=target, filename="tmp/templated_spec.rst", target=target, filename="tmp/templated_spec.rst",
out_filename="tmp/full_spec.rst" out_filename="tmp/full_spec.rst"
) )
shutil.copy("../supporting-docs/howtos/client-server.rst", "tmp/howto.rst") shutil.copy("../supporting-docs/howtos/client-server.rst", "tmp/howto.rst")
run_through_template("tmp/howto.rst") run_through_template("tmp/howto.rst", False) # too spammy to mark -v on this
rst2html("tmp/full_spec.rst", "gen/specification.html") rst2html("tmp/full_spec.rst", "gen/specification.html")
rst2html("tmp/howto.rst", "gen/howtos.html") rst2html("tmp/howto.rst", "gen/howtos.html")
if "--nodelete" not in sys.argv: if not keep_intermediates:
cleanup_env() cleanup_env()
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1:] != ["--nodelete"]: parser = ArgumentParser(
# we accept almost no args, so they don't know what they're doing! "gendoc.py - Generate the Matrix specification as HTML to the gen/ folder."
print "gendoc.py - Generate the Matrix specification as HTML." )
print "Usage:" parser.add_argument(
print " python gendoc.py [--nodelete]" "--nodelete", "-n", action="store_true",
print "" help="Do not delete intermediate files. They will be found in tmp/"
print "The specification can then be found in the gen/ folder." )
print ("If --nodelete was specified, intermediate files will be " parser.add_argument(
"present in the tmp/ folder.") "--target", "-t", default="main",
print "" help="Specify the build target to build from specification/targets.yaml"
print "Requirements:" )
print " - This script requires Jinja2 and rst2html (docutils)." parser.add_argument(
sys.exit(0) "--verbose", "-v", action="store_true",
main("main") help="Turn on verbose mode."
)
args = parser.parse_args()
if not args.target:
parser.print_help()
sys.exit(1)
VERBOSE = args.verbose
main(args.target, args.nodelete)

View file

@ -16,7 +16,7 @@ class Sections(object):
def log(self, text): def log(self, text):
if self.debug: if self.debug:
print text print "batesian:sections: %s" % text
def get_sections(self): def get_sections(self):
render_list = inspect.getmembers(self, predicate=inspect.ismethod) render_list = inspect.getmembers(self, predicate=inspect.ismethod)

View file

@ -22,7 +22,11 @@ class Units(object):
def log(self, text): def log(self, text):
if self.debug: if self.debug:
print text func_name = ""
trace = inspect.stack()
if len(trace) > 1 and len(trace[1]) > 2:
func_name = trace[1][3] + ":"
print "batesian:units:%s %s" % (func_name, text)
def get_units(self, debug=False): def get_units(self, debug=False):
unit_list = inspect.getmembers(self, predicate=inspect.ismethod) unit_list = inspect.getmembers(self, predicate=inspect.ismethod)

View file

@ -52,8 +52,8 @@ def create_from_template(template, sections):
def check_unaccessed(name, store): def check_unaccessed(name, store):
unaccessed_keys = store.get_unaccessed_set() unaccessed_keys = store.get_unaccessed_set()
if len(unaccessed_keys) > 0: if len(unaccessed_keys) > 0:
print "Found %s unused %s keys." % (len(unaccessed_keys), name) log("Found %s unused %s keys." % (len(unaccessed_keys), name))
print unaccessed_keys log(unaccessed_keys)
def main(input_module, file_stream=None, out_dir=None, verbose=False): def main(input_module, file_stream=None, out_dir=None, verbose=False):
if out_dir and not os.path.exists(out_dir): if out_dir and not os.path.exists(out_dir):
@ -121,17 +121,19 @@ def main(input_module, file_stream=None, out_dir=None, verbose=False):
return return
# check the input files and substitute in sections where required # check the input files and substitute in sections where required
print "Parsing input template: %s" % file_stream.name log("Parsing input template: %s" % file_stream.name)
temp = Template(file_stream.read()) temp = Template(file_stream.read())
print "Creating output for: %s" % file_stream.name log("Creating output for: %s" % file_stream.name)
output = create_from_template(temp, sections) output = create_from_template(temp, sections)
with open( with open(
os.path.join(out_dir, os.path.basename(file_stream.name)), "w" os.path.join(out_dir, os.path.basename(file_stream.name)), "w"
) as f: ) as f:
f.write(output) f.write(output)
print "Output file for: %s" % file_stream.name log("Output file for: %s" % file_stream.name)
check_unaccessed("units", units) check_unaccessed("units", units)
def log(line):
print "batesian: %s" % line
if __name__ == '__main__': if __name__ == '__main__':
parser = ArgumentParser( parser = ArgumentParser(
@ -175,7 +177,7 @@ if __name__ == '__main__':
sys.exit(0) sys.exit(0)
if not args.file: if not args.file:
print "No file supplied." log("No file supplied.")
parser.print_help() parser.print_help()
sys.exit(1) sys.exit(1)

View file

@ -1,4 +1,12 @@
"""Contains all the units for the spec.""" """
Contains all the units for the spec.
This file loads swagger and JSON schema files and parses out the useful bits
and returns them as Units for use in Batesian.
For the actual conversion of data -> RST (including templates), see the sections
file instead.
"""
from batesian.units import Units from batesian.units import Units
import inspect import inspect
import json import json
@ -134,7 +142,7 @@ class MatrixUnits(Units):
"good_response": "" "good_response": ""
} }
} }
self.log(".o.O.o. Endpoint: %s %s" % (method, path)) self.log(" ------- Endpoint: %s %s ------- " % (method, path))
for param in single_api.get("parameters", []): for param in single_api.get("parameters", []):
# description # description
desc = param.get("description", "") desc = param.get("description", "")
@ -183,6 +191,9 @@ class MatrixUnits(Units):
"desc": json_body[key]["description"] "desc": json_body[key]["description"]
}) })
# endfor[param] # endfor[param]
for row in endpoint["req_params"]:
self.log("Request parameter: %s" % row)
# group params by location to ease templating # group params by location to ease templating
endpoint["req_param_by_loc"] = { endpoint["req_param_by_loc"] = {
# path: [...], query: [...], body: [...] # path: [...], query: [...], body: [...]
@ -240,6 +251,7 @@ class MatrixUnits(Units):
# add response params if this API has any. # add response params if this API has any.
if good_response: if good_response:
self.log("Found a 200 response for this API")
res_type = Units.prop(good_response, "schema/type") res_type = Units.prop(good_response, "schema/type")
if res_type and res_type not in ["object", "array"]: if res_type and res_type not in ["object", "array"]:
# response is a raw string or something like that # response is a raw string or something like that
@ -278,6 +290,16 @@ class MatrixUnits(Units):
}] }]
}) })
for response_table in endpoint["res_tables"]:
self.log("Response: %s" % response_table["title"])
for r in response_table["rows"]:
self.log("Row: %s" % r)
if len(endpoint["res_tables"]) == 0:
self.log(
"This API appears to have no response table. Are you " +
"sure this API returns no parameters?"
)
endpoints.append(endpoint) endpoints.append(endpoint)
aliases = single_api.get("x-alias", None) aliases = single_api.get("x-alias", None)
@ -475,7 +497,7 @@ class MatrixUnits(Units):
if re.match("^v[0-9\.]+$", word): if re.match("^v[0-9\.]+$", word):
version = word[1:] # strip the 'v' version = word[1:] # strip the 'v'
self.log("Version: %s Title part: %s Changelog lines: %s" % ( self.log("Version: %s Title part: %s Changelog line count: %s" % (
version, title_part, len(changelog_lines) version, title_part, len(changelog_lines)
)) ))
if not version or len(changelog_lines) == 0: if not version or len(changelog_lines) == 0: