pw_docgen: Fix paths, multiple sources

- Fix code for remapping paths into the docgen tree. Some path prefixes
  were being incorrectly trimmed, preventing size report inclusion in
  some cases.
- Make Sphinx warnings errors.
- Allow specifying multiple top-level sources to a pw_doc_gen.
- Move documentation for modules to their own table of contents.
- Rename module documentation to the module names.

Change-Id: Ic475019673ccefdb786a28d241a143886af097ab
diff --git a/docs/BUILD.gn b/docs/BUILD.gn
index b45bfe8..0dffb53 100644
--- a/docs/BUILD.gn
+++ b/docs/BUILD.gn
@@ -23,7 +23,10 @@
 
 pw_doc_gen("docs") {
   conf = "conf.py"
-  index = "index.rst"
+  sources = [
+    "index.rst",
+    "modules.rst",
+  ]
   output_directory = target_gen_dir
   deps = [
     ":core_docs",
diff --git a/docs/index.rst b/docs/index.rst
index 5b2d715..055690e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -8,11 +8,9 @@
 facilitate easy integration into existing codebases.
 
 .. toctree::
-   :maxdepth: 1
-   :hidden:
+  :maxdepth: 1
+  :hidden:
 
-   docs/embedded_cpp_guide
-   docs/style_guide
-   pw_bloat/bloat
-   pw_docgen/docgen
-   pw_preprocessor/docs
+  docs/embedded_cpp_guide
+  docs/style_guide
+  modules
diff --git a/docs/modules.rst b/docs/modules.rst
new file mode 100644
index 0000000..87df808
--- /dev/null
+++ b/docs/modules.rst
@@ -0,0 +1,10 @@
+=======
+Modules
+=======
+
+.. toctree::
+  :maxdepth: 1
+
+  pw_bloat/bloat
+  pw_docgen/docgen
+  pw_preprocessor/docs
diff --git a/pw_bloat/bloat.rst b/pw_bloat/bloat.rst
index b6448b7..73003a1 100644
--- a/pw_bloat/bloat.rst
+++ b/pw_bloat/bloat.rst
@@ -4,9 +4,9 @@
 
 .. highlight:: sh
 
------
-Bloat
------
+--------
+pw_bloat
+--------
 The bloat module provides tools to generate size report cards for output
 binaries.
 
diff --git a/pw_docgen/docgen.rst b/pw_docgen/docgen.rst
index 7d1af5e..6ddad49 100644
--- a/pw_docgen/docgen.rst
+++ b/pw_docgen/docgen.rst
@@ -4,9 +4,9 @@
 
 .. highlight:: sh
 
-------
-Docgen
-------
+---------
+pw_docgen
+---------
 The docgen module provides tools to generate documentation for Pigweed-based
 projects, and for Pigweed itself.
 
diff --git a/pw_docgen/docs.gni b/pw_docgen/docs.gni
index 8fde171..34af772 100644
--- a/pw_docgen/docs.gni
+++ b/pw_docgen/docs.gni
@@ -56,15 +56,14 @@
 #
 # Args:
 #   deps: List of pw_doc_group targets.
-#   index: Top-level documentation index file.
+#   sources: Top-level documentation .rst source files.
 #   conf: Configuration script (conf.py) for Sphinx.
 #   output_directory: Path to directory to which HTML output is rendered.
 template("pw_doc_gen") {
   assert(defined(invoker.deps),
          "pw_doc_gen requires doc groups as dependencies")
-  assert(
-      defined(invoker.index),
-      "pw_doc_gen requires an 'index' argument pointing a top-level index.rst")
+  assert(defined(invoker.sources) && invoker.sources != [],
+         "pw_doc_gen requires a 'sources' list with at least one .rst source")
   assert(defined(invoker.conf),
          "pw_doc_gen requires a 'conf' argument pointing a top-level conf.py")
   assert(defined(invoker.output_directory),
@@ -86,21 +85,26 @@
 
   _script_args = [
     "--gn-root",
-    "//",
+    rebase_path("//", root_out_dir),
+    "--gn-gen-root",
+    rebase_path(root_gen_dir, root_out_dir) + "/",
     "--sphinx-build-dir",
     get_path_info("$target_gen_dir/pw_docgen_tree", "abspath"),
     "--conf",
     get_path_info(invoker.conf, "abspath"),
-    "--index",
-    get_path_info(invoker.index, "abspath"),
     "--out-dir",
     get_path_info(invoker.output_directory, "abspath"),
+    "--metadata",
   ]
 
   # Metadata JSON file path.
   _script_args +=
       get_path_info(get_target_outputs(":$_metadata_file_target"), "abspath")
 
+  foreach(path, invoker.sources) {
+    _script_args += [ get_path_info(path, "abspath") ]
+  }
+
   pw_python_script(target_name) {
     script = "$dir_pw_docgen/py/docgen.py"
     args = _script_args
@@ -109,8 +113,8 @@
     ]
     inputs = [
       invoker.conf,
-      invoker.index,
     ]
+    inputs += invoker.sources
     stamp = true
   }
 }
diff --git a/pw_docgen/py/docgen.py b/pw_docgen/py/docgen.py
index f1ff045..b9806f0 100644
--- a/pw_docgen/py/docgen.py
+++ b/pw_docgen/py/docgen.py
@@ -41,17 +41,20 @@
     """Parses command-line arguments."""
 
     parser = argparse.ArgumentParser(description=__doc__)
-    parser.add_argument('--sphinx-build-dir', type=str, required=True,
+    parser.add_argument('--sphinx-build-dir', required=True,
                         help='Directory in which to build docs')
-    parser.add_argument('--conf', type=str, required=True,
+    parser.add_argument('--conf', required=True,
                         help='Path to conf.py file for Sphinx')
-    parser.add_argument('--gn-root', type=str, required=True,
+    parser.add_argument('--gn-root', required=True,
                         help='Root of the GN build tree')
-    parser.add_argument('--index', type=str, required=True,
-                        help='Path to root index.rst file')
-    parser.add_argument('--out-dir', type=str, required=True,
+    parser.add_argument('--gn-gen-root', required=True,
+                        help='Root of the GN gen tree')
+    parser.add_argument('sources', nargs='+',
+                        help='Paths to the root level rst source files')
+    parser.add_argument('--out-dir', required=True,
                         help='Output directory for rendered HTML docs')
-    parser.add_argument('metadata_file', type=argparse.FileType('r'))
+    parser.add_argument('--metadata', required=True,
+                        type=argparse.FileType('r'), help='Metadata JSON file')
     return parser.parse_args()
 
 
@@ -60,7 +63,7 @@
 
     # TODO(frolv): Specify the Sphinx script from a prebuilts path instead of
     # requiring it in the tree.
-    command = ['sphinx-build', '-b', 'html', '-d',
+    command = ['sphinx-build', '-W', '-b', 'html', '-d',
                f'{dst_dir}/help', src_dir, f'{dst_dir}/html']
     return subprocess.call(command)
 
@@ -82,13 +85,19 @@
 
     def build_path(path):
         """Converts a source path to a filename in the build directory."""
-        return f'{args.sphinx_build_dir}/{path[len(args.gn_root):]}'
+        if path.startswith(args.gn_root):
+            path = os.path.relpath(path, args.gn_root)
+        elif path.startswith(args.gn_gen_root):
+            path = os.path.relpath(path, args.gn_gen_root)
 
-    source_files = json.load(args.metadata_file)
+        return os.path.join(args.sphinx_build_dir, path)
+
+    source_files = json.load(args.metadata)
     copy_paths = [build_path(f) for f in source_files]
 
     mkdir(args.sphinx_build_dir)
-    copy(args.index, f'{args.sphinx_build_dir}/index.rst')
+    for path in args.sources:
+      copy(path, f'{args.sphinx_build_dir}/')
     copy(args.conf, f'{args.sphinx_build_dir}/conf.py')
 
     # Map of directory path to list of source and destination file paths.
diff --git a/pw_preprocessor/docs.rst b/pw_preprocessor/docs.rst
index 37ddbf6..048abb3 100644
--- a/pw_preprocessor/docs.rst
+++ b/pw_preprocessor/docs.rst
@@ -4,9 +4,9 @@
 
 .. highlight:: sh
 
-------------
-Preprocessor
-------------
+---------------
+pw_preprocessor
+---------------
 The preprocessor module provides various helpful preprocessor macros.
 
 Compatibility