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.
This commit is contained in:
Nathan Lovato
2020-10-06 20:10:11 -06:00
parent 9a632289a3
commit 5e3a7c8fd1

108
_tools/move_rst_files.py Normal file
View File

@@ -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)