| #!/usr/bin/env fuchsia-vendored-python |
| # Copyright 2023 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Processes the zip archive of syscall markdown and adds toc and readme.""" |
| |
| import argparse |
| import json |
| import os |
| import shutil |
| import sys |
| import io |
| import zipfile |
| |
| README_HEADER = """# Zircon System Calls |
| |
| [Life of a Fuchsia syscall](/docs/concepts/kernel/life_of_a_syscall.md) |
| |
| """ |
| |
| TOC_HEADER = """# Copyright 2023 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # Please, read https://fuchsia.dev/fuchsia-src/contribute/docs/documentation-navigation-toc |
| # before making changes to this file, and add a member of the fuchsia.dev |
| # team as reviewer. |
| toc: |
| """ |
| |
| # TODO(b/306180541): Move syscall categories closer to source .fidl files. |
| |
| # These are the sections for the system calls in order of appearance. |
| README_SECTIONS = [ |
| ("Handles", "handle"), |
| ("Objects", "object"), |
| ("Threads", "thread"), |
| ("Thread Sampling", "sampler"), |
| ("IO Buffers", "iob"), |
| ("Processes", "process"), |
| ("Jobs", "job"), |
| ("Tasks (Thread, Process, or Job)", "task"), |
| ("Profiles", "profile"), |
| ("Exceptions", "exception"), |
| ("Channels", "channel"), |
| ("Sockets", "socket"), |
| ("Streams", "stream"), |
| ("Fifos", "fifo"), |
| ("Events and Event Pairs", "event"), |
| ("Ports", "port"), |
| ("Futexes", "futex"), |
| ("Virtual Memory Objects (VMOs)", "vmo"), |
| ("Virtual Memory Address Regions (VMARs)", "vmar"), |
| ("Userspace Pagers", "pager"), |
| ("Cryptographically Secure RNG", "cprng"), |
| ("Time", "time"), |
| ("Timers", "timer"), |
| ("Message Signaled Interrupts (MSIs)", "msi"), |
| ("Hypervisor guests", "guest"), |
| ("Virtual CPUs", "vcpu"), |
| ("Global system information", "global"), |
| ("Debug Logging", "debug"), |
| ("Multi-function", "multi-function"), |
| ("System", "system"), |
| ("DDK", "ddk"), |
| ("Display drivers", "framebuffer"), |
| ("Tracing", "tracing"), |
| ("Restricted Mode (Work in progress)", "restricted"), |
| ("Others/Work in progress", "others"), |
| ] |
| |
| |
| def gen_readme_and_toc(data, reference_root): |
| readme = io.StringIO() |
| toc = io.StringIO() |
| print(README_HEADER, file=readme) |
| |
| print(TOC_HEADER, file=toc) |
| print('- title: "Overview"', file=toc) |
| print(f" path: {reference_root}/README.md", file=toc) |
| |
| topic_map = dict() |
| # build a map of prefixes from the topics |
| for entry in data: |
| if entry["topic"] not in topic_map: |
| topic_map[entry["topic"]] = [entry] |
| else: |
| topic_map[entry["topic"]].append(entry) |
| |
| for title, topic in README_SECTIONS: |
| entries = topic_map[topic] |
| entries.sort(key=lambda x: x["filename"]) |
| del topic_map[topic] |
| print(f"## {title}\n", file=readme) |
| print(f'- title: "{title}"', file=toc) |
| print(f" section:", file=toc) |
| |
| for entry in entries: |
| label = entry["filename"][:-3] |
| filename = entry["filename"] |
| summary = entry["summary"] |
| print(f"* [{label}]({filename}) - {summary}", file=readme) |
| print(f' - title: "zx_{label}"', file=toc) |
| print(f" path: {reference_root}/{filename}", file=toc) |
| print("", file=readme) |
| |
| if topic_map: |
| raise ValueError(f"Uncategorized topics: {topic_map}") |
| |
| return (readme.getvalue(), toc.getvalue()) |
| |
| |
| def get_topic(filename): |
| topic = filename.split("_")[0] |
| |
| # There are some special cases |
| if topic == "vmar" and filename == "vmar_unmap_handle_close_thread_exit.md": |
| topic = "multi-function" |
| elif topic == "eventpair": |
| topic = "event" |
| elif topic == "system": |
| if filename == "system_get_event.md": |
| topic = "event" |
| if filename in [ |
| "system_get_dcache_line_size.md", |
| "system_get_features.md", |
| "system_get_num_cpus.md", |
| "system_get_page_size.md", |
| "system_get_physmem.md", |
| "system_get_version_string.md", |
| ]: |
| topic = "global" |
| elif topic in [ |
| "bti", |
| "cache", |
| "interrupt", |
| "iommu", |
| "pmt", |
| "resource", |
| "smc", |
| ]: |
| topic = "ddk" |
| elif topic in ["pci", "pc", "ioports"]: |
| topic = "others" |
| elif topic in ["clock", "deadline", "nanosleep.md", "ticks"]: |
| topic = "time" |
| elif topic in ["ktrace", "mtrace"]: |
| topic = "tracing" |
| elif topic in ["debuglog"]: |
| topic = "debug" |
| |
| return topic |
| |
| |
| def read_summary(input): |
| """Read the first line of the Summary section.""" |
| lines = input.decode().splitlines() |
| saw_summary = False |
| for l in lines: |
| if l == "## Summary": |
| saw_summary = True |
| elif saw_summary and l: |
| return l |
| return "" |
| |
| |
| def gen_toc_readme(inzip, outzip, reference_root): |
| """Generates _toc.yaml and README.md for the files in inzip.""" |
| |
| # Copy the zip |
| shutil.copy2(inzip, outzip) |
| |
| data = [] |
| # Build the list of topic, summary, path tuples |
| with zipfile.ZipFile(inzip) as zf: |
| for m in zf.infolist(): |
| if not m.is_dir(): |
| filename = m.filename |
| topic = get_topic(filename) |
| contents = zf.read(m) |
| summary = read_summary(contents) |
| data.append( |
| {"topic": topic, "summary": summary, "filename": filename} |
| ) |
| (readme_contents, toc_contents) = gen_readme_and_toc(data, reference_root) |
| |
| with zipfile.ZipFile(outzip, "a") as zf: |
| zf.writestr("README.md", readme_contents) |
| zf.writestr("_toc.yaml", toc_contents) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser( |
| description=__doc__, # Prepend helpdoc with this file's docstring. |
| formatter_class=argparse.RawDescriptionHelpFormatter, |
| ) |
| parser.add_argument( |
| "--input", |
| type=str, |
| required=True, |
| help="Output location where generated docs should go", |
| ) |
| parser.add_argument( |
| "--output", |
| type=str, |
| required=True, |
| help="zipfile path for final output", |
| ) |
| parser.add_argument( |
| "--reference-root", |
| type=str, |
| required=True, |
| help="root path for reference directory. This is prepended to the filename paths to build the local URL for the toc.", |
| ) |
| |
| args = parser.parse_args() |
| |
| gen_toc_readme(args.input, args.output, args.reference_root) |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |