Ver código fonte

Add a tool to move rst files and images

The program moves a list of rst files along with their image
dependencies to a target directory. It then outputs redirects
in the format the ReadTheDocs backend expects.
Nathan Lovato 4 anos atrás
pai
commit
5e3a7c8fd1
1 arquivos alterados com 108 adições e 0 exclusões
  1. 108 0
      _tools/move_rst_files.py

+ 108 - 0
_tools/move_rst_files.py

@@ -0,0 +1,108 @@
+import re
+from argparse import ArgumentParser
+from os.path import isfile, isdir, join, realpath, split, dirname, relpath
+import os
+import shutil
+
+
+def parse_and_get_arguments():
+    """Creates and returns an object with parsed arguments, using argparse."""
+    parser: ArgumentParser = ArgumentParser(
+        prog="move_rst_files",
+        description="Moves reST documents and their dependencies from one folder to another. Outputs required redirections in the ReadTheDocs backend.",
+    )
+    parser.add_argument(
+        "documents", nargs="+", help="Paths of documents to move.",
+    )
+    parser.add_argument(
+        "output_path", help="Path to the target output directory.",
+    )
+    return parser.parse_args()
+
+
+def find_project_root_path(document_path):
+    """Returns the path to the repository's root directory by looking for the file conf.py, starting
+from the path of any file in the project."""
+    full_path = realpath(document_path)
+    dirpath = split(full_path)[0]
+
+    root_path = ""
+    current = dirpath
+    iterations = 0
+    while root_path == "":
+        if isfile(join(current, "conf.py")):
+            root_path = current
+        else:
+            current = split(current)[0]
+            if current == "":
+                break
+        iterations += 1
+        if iterations > 20:
+            break
+    return root_path
+
+
+def find_images(document):
+    """Returns the list of image filepaths used by the `document`."""
+    images = []
+    for line in document:
+        match = re.match(r"\.\. image::\s+(img\/.+)", line)
+        if match:
+            images.append(match[1])
+    return list(set(images))
+
+
+def find_document_dependencies(documents):
+    """For each document path in `documents`, finds all pictures it depends on and returns a dict with the form { document: [images] }."""
+    data = {}
+    for path in documents:
+        with open(path, "r") as rst_file:
+            images = find_images(rst_file)
+            data[path] = images
+    return data
+
+
+def move_documents(paths, output_path):
+    """Moves .rst files and all their image dependencies to `output_path`"""
+    data = find_document_dependencies(paths)
+    for path in data:
+        directory = dirname(path)
+        shutil.move(path, output_path)
+        for image in data[path]:
+            image_in_path = join(directory, image)
+            image_out_path = join(output_path, image)
+            image_out_dirpath = dirname(image_out_path)
+            if not isdir(image_out_dirpath):
+                os.makedirs(image_out_dirpath)
+            shutil.move(image_in_path, image_out_path)
+
+
+def print_redirects(paths):
+    """Prints redirects we need to make on the ReadTheDocs backend with the form "input -> output".
+    Moving the file /learning/features/viewports/viewports.rst to /tutorials/viewports/viewports.rst
+    Requires the following redirect:
+    /learning/features/viewports/viewports.html -> /tutorials/viewports/viewports.html
+    """
+    redirects = ""
+    project_root_path = find_project_root_path(paths[0])
+    out_path_relative = relpath(args.output_path, project_root_path)
+    for document in paths:
+        in_path_relative = relpath(document, project_root_path)
+        in_directory, filename_rst = split(in_path_relative)
+        filename_html = filename_rst.rsplit(".rst", 1)[0] + ".html"
+
+        in_path = join(in_directory, filename_html)
+        out_path = join(out_path_relative, filename_html)
+        redirects += in_path + " -> " + out_path + "\n"
+    print(redirects)
+
+
+if __name__ == "__main__":
+    args = parse_and_get_arguments()
+    assert isdir(args.output_path)
+
+    documents = [
+        path for path in args.documents if isfile(path) and path.endswith(".rst")
+    ]
+    move_documents(documents, args.output_path)
+    print_redirects(documents)