| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 | import refrom argparse import ArgumentParserfrom os.path import isfile, isdir, join, realpath, split, dirname, relpathimport osimport shutildef 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, startingfrom 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_pathdef 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 datadef 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)
 |