forked from godotengine/godot-docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmove_rst_files.py
108 lines (91 loc) · 3.7 KB
/
move_rst_files.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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)