#!/usr/bin/env python # Copyright (c) 2017, NORDUnet A/S. # See LICENSE for licensing information. import argparse import sys import readconfig import re import base64 import shutil from datetime import datetime from orderedtree import TreeNode def level_is_list(schema): if len(schema.keys()) != 1: return False return schema.keys()[0] == "[]" def traverse_schema_part(schema): tree = TreeNode() for k in sorted(schema.keys()): schema_part = schema.get(k) result = None if isinstance(schema_part, tuple): (lowleveldatatype, highleveldatatype, extra) = schema_part if isinstance(highleveldatatype, list): formatted_datatype = "|".join(["**"+t+"**" for t in highleveldatatype]) else: formatted_datatype = "__" + highleveldatatype.replace(" ", "-") + "__" if k == "[]": result = "list of " + formatted_datatype else: result = "**" + k + "**: " + formatted_datatype if extra["optional"]: result += " (optional)" default = extra["default"] if default != None: result += " (default: %s)" % (default) tree.add(k, (result, [])) elif isinstance(schema_part, dict): if k == "[]": result = "list of items" else: if level_is_list(schema_part): formatted_datatype = "(list of items)" schema_part = schema_part["[]"] else: formatted_datatype = "" result = "**"+k+"**: " + formatted_datatype subtree = traverse_schema_part(schema_part) tree.add(k, (result, []), subtree=subtree) else: print >>sys.stderr, "unknown type", type(schema_part) sys.exit(1) return tree def traverse_schema(schema): transformed_schema = readconfig.transform_schema(schema) tree = traverse_schema_part(transformed_schema) return tree def is_adoc_header(row): return set(row.rstrip()) == set("=") def is_adoc_section(row): return set(row.rstrip()) == set("-") def parse_manpage(filename): f = open(filename) header = [] for row in f: if is_adoc_header(row): break header.append(row.rstrip("\n")) section_name = None section = [] sections = [] for row in f: if is_adoc_section(row): if section_name: sections.append((section_name, section[:-1])) section_name = section[-1] section = [] else: section.append(row.rstrip("\n")) if section_name: sections.append((section_name, section)) return (header, sections) def is_manpage_option(row): return row.endswith("::") def extract_option_name(row): if row == None: return (None, None) (name_part, _, _) = row.lstrip().partition(":") depth = len(row) - len(row.rstrip(":")) - 2 return (name_part.replace("*", ""), depth) def parse_manpage_options(option_rows): option_name_row = None options = [] option = [] for row in option_rows: if is_manpage_option(row): options.append((option_name_row, option)) option_name_row = row option = [] else: option.append(row) options.append((option_name_row, option)) return options def build_tree(l, key): tree = TreeNode() curpath = [] for e in l: (k, depth) = key(e) if depth > len(curpath): print >>sys.stderr, "depth", depth, "from", e, "greater than length of curpath", curpath sys.exit(1) curpath = curpath[:depth] tree.walk(curpath).add(k, e) curpath.append(k) return tree def transfer_tree(current, wanted): for name in wanted.iterkeys(): if name in current and name != None: transfer_tree(current[name], wanted[name]) if wanted.entry: wanted.entry = (wanted.entry[0], current.entry[1]) def print_tree(f, tree, depth=0): if tree.entry: (section, rows) = tree.entry print >>f, " " * depth + section + (depth+1) * ":" has_content = False for row in rows: if row.strip(): has_content = True print >>f, row if not has_content: print >>f, "// " + " " * depth + "write description here" print >>f, "" for name in tree.iterkeys(): print_tree(f, tree[name], depth=depth+1) def rewrite_options(f, schema, options): wanted = traverse_schema(schema) current = build_tree(options, lambda e: extract_option_name(e[0])) transfer_tree(current, wanted) print_tree(f, wanted) def rewrite_manpage(filename, schema, man_source, man_manual, title, name): try: (header, sections) = parse_manpage(filename) except IOError: sections = [] sections_dict = dict(sections) section_names = [e for e, _ in sections] options = parse_manpage_options(sections_dict.get("OPTIONS", [])) sections_dict["NAME"] = [name] if "NAME" not in section_names: section_names.append("NAME") if "OPTIONS" not in section_names: section_names.append("OPTIONS") f = open(filename + ".new", "w") print >>f, ":man source: " + man_source print >>f, ":man manual: " + man_manual print >>f, title print >>f, len(title) * "=" print >>f, "" for section_name in section_names: print >>f, section_name print >>f, len(section_name) * "-" if section_name == "OPTIONS": rewrite_options(f, schema, options) continue for row in sections_dict[section_name]: print >>f, row print >>f, "" f.close() shutil.move(filename + ".new", filename)