Skip to content

Commit

Permalink
Improve migrate
Browse files Browse the repository at this point in the history
  • Loading branch information
adikhoff committed Oct 13, 2024
1 parent b628c3b commit 0fabd7d
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 51 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Migrate to Redot
run: |
python migrate.py . _migrated True
python migrate.py . _migrated
# Use dummy builder to improve performance as we don't need the generated HTML in this workflow.
- name: Sphinx build
Expand Down
142 changes: 92 additions & 50 deletions migrate.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
"""
## Migrate files from Godot to Redot
Usage (order is important):
py migrate.py [inputdir] [outputdir] [include unimplemented]
usage: Migrate [-h] [-e] [-t] [-v] input output
example:
py migrate.py . _migrated True
Simple file migrator. Uses str.replace to map from Godot to Redot. Also converts some filenames.
Will replace specific godot strings with redot. It tries to ignore external projects and other things that can't
positional arguments:
input Input directory relative to current
output Output directory relative to current
options:
-h, --help show this help message and exit
-e, --extended Include unimplemented substitutions, don't use in production
-t, --tiny Exclude classes directory
-v, --verbose
Will replace specific godot strings with redot. It tries to ignore external projects and other things that shouldn't
change.
A distinction is made between unimplemented instances of the godot keyword (for instance references to the main
Expand All @@ -23,18 +31,23 @@
From there, the docs can be built in the normal way.
"""

import argparse
import fnmatch
import os
import re
from shutil import copyfile
import shutil
import sys
import codecs
from distutils.dir_util import copy_tree

encoding = 'utf-8'
defaultInputDirectory = '.'
defaultOutputDirectory = '_migrated'
defaultIncludeUnimplemented = False
defaultIgnoreClasses = True
defaultVerbose = False

encoding = 'utf-8'
filename_masks = ['.rst', '.md']

# Mappings that will currently lead to nowhere. Can be treated as a todo list.
Expand Down Expand Up @@ -72,7 +85,6 @@
('Support/Godot/', 'Support/Redot/'),
('config/godot/', 'config/redot/'),
('share/godot/', 'share/redot/'),
(' godot_', ' redot_'),
('org.godotengine.Godot', 'org.redotengine.Redot'),
('godot-ios-plugins', 'redot-ios-plugins'),
('godot-syntax-themes', 'redot-syntax-themes'),
Expand Down Expand Up @@ -180,13 +192,14 @@
('by-godot', 'by-redot'),
('MadeWithGodot', 'MadeWithRedot'),
(' if on_rtd else "(DEV) "', ''),
('<span class="fa fa-book"> Read the Docs</span>', '<span class="fa fa-book"> Versions</span>'),
("const homeUrl = baseUrl.split('/latest/')[0] + '/stable/';", "const homeUrl = 'https://redot-docs-4-3.pages.dev/';"),
('Read the Docs', 'Versions'),
('{% set listed_languages = ({"en":"#", "de":"#", "es":"#", "fr":"#"}).items() -%}', '{% set listed_languages = ({"en":"#"}).items() -%}'),
('({"stable":"#", "latest":"#"})', '({"stable":"https://redot-docs-4-3.pages.dev/", "latest":"https://redot-docs-4-4.pages.dev/", "3.6":"https://redot-docs-3-6.pages.dev/"})'),
('Hosted by <a href="https://readthedocs.org">Read the Docs', 'Hosted by <a href="https://cloudflare.com">CloudFlare'),
('<a href="https://docs.readthedocs.io/page/privacy-policy.html">Privacy Policy</a>', ''),
('G-dot', 'Godot'),
(' godot_', ' redot_'),
]

filename_mappings = [
Expand Down Expand Up @@ -243,18 +256,18 @@ def ensureDirExists(outputName):
except FileExistsError:
pass

def copyFile(root, filename, outputDirectory):
def copyFile(root, filename, outputDirectory, verbose):
inputName = os.path.join(root, filename)
outputName = generateOutputName(root, inputName.replace('.\\', '').replace('./', ''), outputDirectory)

print(f'Copying "{inputName}" to "{outputName}"')
if verbose: print(f'Copying "{inputName}" to "{outputName}"')
shutil.copyfile(inputName, outputName)

def convertFile(root, filename, outputDirectory, includeUnimplemented):
def convertFile(root, filename, outputDirectory, includeUnimplemented, verbose):
inputName = os.path.join(root, filename)
outputName = generateOutputName(root, filename, outputDirectory)

print(f'Converting "{inputName}" to "{outputName}"')
if verbose: print(f'Converting "{inputName}" to "{outputName}"')
with open(inputName, mode = 'r', encoding = encoding) as input:
data = input.read()

Expand All @@ -265,64 +278,93 @@ def convertFile(root, filename, outputDirectory, includeUnimplemented):
with open(outputName, mode = 'w', encoding = encoding) as output:
output.write(data)

def copyGlobalDir(inputDirectory, inputMask, outputDirectory):
def copyGlobalDir(inputDirectory, inputMask, outputDirectory, verbose):
for root, dirs, files in os.walk(inputDirectory):
if (inputMask in root and outputDirectory not in root):
for f in files:
inputName = os.path.join(root, f)
outputName = generateOutputName(root, f, outputDirectory)
ensureDirExists(outputName)
print(f"Copying {inputName} to {outputName}")
if verbose: print(f"Copying {inputName} to {outputName}")
copyfile(inputName, outputName)

def convertStaticDir(inputDirectory, outputDirectory):
def convertStaticDir(inputDirectory, outputDirectory, verbose):
for root, dirs, files in os.walk(inputDirectory):
if (outputDirectory not in root and '__' not in root):
for f in files:
if (f.split('.')[1] in alphanumeric):
convertFile(root, f, outputDirectory, True)
convertFile(root, f, outputDirectory, True, verbose)
else:
copyFile(root, f, outputDirectory)
copyFile(root, f, outputDirectory, verbose)

def migrate(inputDirectory, outputDirectory, includeUnimplemented):
def migrate(inputDirectory, outputDirectory, includeUnimplemented, ignoreClasses, verbose):
outputsig = os.path.join('.', outputDirectory)
for root, dirs, files in os.walk(inputDirectory):
# ignore output path
if (root.startswith(outputsig)):
continue

if (ignoreClasses and 'classes' in root):
continue

items = filter(is_target, files)
for item in items:
convertFile(root, item, outputDirectory, includeUnimplemented)

inputDir = defaultInputDirectory
outputDir = defaultOutputDirectory
includeUnimplemented = defaultIncludeUnimplemented
if (len(sys.argv) > 1):
inputDir = sys.argv[1]
if (len(sys.argv) > 2):
outputDir = sys.argv[2]
if (len(sys.argv) > 3):
includeUnimplemented = sys.argv[3]

print(f"Simple rst migrator. Uses str.replace to map from Godot to Redot.")
print(f"Usage: py migrate.py [inputDir] [outputDir] [includeUnimplemented], example: py migrate.py . _mymigration True")
print(f"Author: @Craptain on X")
print(f"Input directory: {inputDir}, output directory: {outputDir}, include unimplemented: {includeUnimplemented}")

migrate(inputDir, outputDir, includeUnimplemented)

print("Copying config files...")
convertFile(inputDir, 'conf.py', outputDir, includeUnimplemented)
convertFile(inputDir, 'robots.txt', outputDir, includeUnimplemented)
copyFile(inputDir, 'favicon.ico', outputDir)
print("Copying static directories...")

for dir in static_dirs:
if ('**' in dir):
print(f"Copying dirs with mask {dir}")
copyGlobalDir(inputDir, dir.split('/')[1], outputDir)
convertFile(root, item, outputDirectory, includeUnimplemented, verbose)

def main():
inputDir = defaultInputDirectory
outputDir = defaultOutputDirectory
includeUnimplemented = defaultIncludeUnimplemented
ignoreClasses = defaultIgnoreClasses
verbose = defaultVerbose

parser = argparse.ArgumentParser(
prog='Migrate',
description='Simple file migrator. Uses str.replace to map from Godot to Redot. Also converts some filenames.',
epilog='Done. Made by @Craptain')
parser.add_argument('input', help='Input directory relative to current')
parser.add_argument('output', help='Output directory relative to current')
parser.add_argument('-e', '--extended', action='store_true', help='Include unimplemented substitutions, don\'t use in production')
parser.add_argument('-t', '--tiny', action='store_true', help='Exclude classes directory')
parser.add_argument('-v', '--verbose', action='store_true')

args = parser.parse_args()
verbose = args.verbose
if (verbose):
print("arguments:")
print(args)

inputDir = args.input
if (args.output != '.' and not args.output.startswith('/')):
outputDir = args.output
else:
print(f"Converting dir {dir}")
convertStaticDir(dir, outputDir)
print("Done")
print("output can't be . or start with /")
exit(1)
includeUnimplemented = args.extended
ignoreClasses = args.tiny

print("Deleting output dir")
shutil.rmtree(outputDir)

print("Migrating...")
migrate(inputDir, outputDir, includeUnimplemented, ignoreClasses, verbose)

print("Copying config files...")
convertFile(inputDir, 'conf.py', outputDir, includeUnimplemented, verbose)
convertFile(inputDir, 'robots.txt', outputDir, includeUnimplemented, verbose)
copyFile(inputDir, 'favicon.ico', outputDir, verbose)

print("Copying static directories...")
for dir in static_dirs:
if ('**' in dir):
if verbose: print(f"Copying dirs with mask {dir}")
copyGlobalDir(inputDir, dir.split('/')[1], outputDir, verbose)
else:
if verbose: print(f"Converting dir {dir}")
convertStaticDir(dir, outputDir, verbose)

print(parser.epilog)

if __name__ == "__main__":
main()

0 comments on commit 0fabd7d

Please sign in to comment.