mirror of
https://github.com/kennethreitz-archive/sphinx-to-github.git
synced 2026-06-05 23:40:17 +00:00
Implemented in a "Clean Code" manner with verbose option
Design is inspired by Google's Clean Code talks and is aimed at testability, though currently there are no tests.
This commit is contained in:
+194
-50
@@ -1,55 +1,199 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
from optparse import OptionParser
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
dir = sys.argv[1]
|
||||
|
||||
def convert_file(file, convert_dict):
|
||||
print "Converting: %s" % file
|
||||
text = open(file).read()
|
||||
for old_link in convert_dict:
|
||||
new_link = convert_dict[old_link]
|
||||
text = text.replace(old_link, new_link)
|
||||
open(file, "w").write(text)
|
||||
|
||||
def remove_underscores(path):
|
||||
i = path.find("_")
|
||||
if i != -1:
|
||||
path = path[:i] + path[i+1:]
|
||||
return remove_underscores(path)
|
||||
else:
|
||||
return path
|
||||
|
||||
def strip_beginning_dotslash(path):
|
||||
if "./" == path[:2]:
|
||||
path = path[2:]
|
||||
return path
|
||||
|
||||
# build up the global dictionary with files we need to convert:
|
||||
d = {}
|
||||
for old_root, dirs, files in os.walk(dir):
|
||||
if "_" in old_root:
|
||||
new_root = remove_underscores(old_root)
|
||||
assert new_root != old_root
|
||||
os.mkdir(new_root)
|
||||
for file in files:
|
||||
old_path = os.path.join(old_root, file)
|
||||
new_path = os.path.join(new_root, file)
|
||||
os.rename(old_path, new_path)
|
||||
new_path = strip_beginning_dotslash(new_path)
|
||||
old_path = strip_beginning_dotslash(old_path)
|
||||
d[old_path] = new_path
|
||||
|
||||
# delete the old "_" directories
|
||||
for old_root, dirs, files in os.walk(dir, topdown=False):
|
||||
if "_" in old_root:
|
||||
os.rmdir(old_root)
|
||||
|
||||
# convert all html files:
|
||||
for root, dirs, files in os.walk(dir):
|
||||
for file in files:
|
||||
if file.endswith(".html"):
|
||||
convert_file(os.path.join(root, file), d)
|
||||
|
||||
|
||||
class NoDirectoriesError(Exception):
|
||||
"Error thrown when no directories starting with an underscore are found"
|
||||
|
||||
class Replacer(object):
|
||||
"Encapsulates a simple text replace"
|
||||
|
||||
def __init__(self, from_, to):
|
||||
|
||||
self.from_ = from_
|
||||
self.to = to
|
||||
|
||||
def process(self, text):
|
||||
|
||||
return text.replace( self.from_, self.to )
|
||||
|
||||
class FileHandler(object):
|
||||
"Applies a series of replacements the contents of a file inplace"
|
||||
|
||||
def __init__(self, name, replacers):
|
||||
|
||||
self.name = name
|
||||
self.replacers = replacers
|
||||
|
||||
def process(self):
|
||||
|
||||
text = open(self.name).read()
|
||||
|
||||
for replacer in self.replacers:
|
||||
text = replacer.process( text )
|
||||
|
||||
open(self.name, "w").write(text)
|
||||
|
||||
class DirectoryHandler(object):
|
||||
"Encapsulates renaming a directory by removing its first character"
|
||||
|
||||
def __init__(self, name, root):
|
||||
|
||||
self.name = name
|
||||
self.new_name = name[1:]
|
||||
self.root = root + os.sep
|
||||
|
||||
def path(self):
|
||||
|
||||
return os.path.join(self.root, self.name)
|
||||
|
||||
def relative_path(self, directory, filename):
|
||||
|
||||
path = directory.replace(self.root, "", 1)
|
||||
return os.path.join(path, filename)
|
||||
|
||||
def new_relative_path(self, directory, filename):
|
||||
|
||||
path = self.relative_path(directory, filename)
|
||||
return path.replace(self.name, self.new_name, 1)
|
||||
|
||||
def process(self):
|
||||
|
||||
from_ = os.path.join(self.root, self.name)
|
||||
to = os.path.join(self.root, self.new_name)
|
||||
os.rename(from_, to)
|
||||
|
||||
class VerboseDirectoryHandler(DirectoryHandler):
|
||||
|
||||
def __init__(self, name, root, stream):
|
||||
|
||||
DirectoryHandler.__init__(self, name, root)
|
||||
|
||||
self.stream = stream
|
||||
|
||||
def process(self):
|
||||
|
||||
self.stream.write(
|
||||
"Renaming directory '%s' -> '%s'\n" % (self.name, self.new_name)
|
||||
)
|
||||
|
||||
DirectoryHandler.process(self)
|
||||
|
||||
class Layout(object):
|
||||
"""
|
||||
Applies a set of operations which result in the layout
|
||||
of a directory changing
|
||||
"""
|
||||
|
||||
def __init__(self, directory_handlers, file_handlers):
|
||||
|
||||
self.directory_handlers = directory_handlers
|
||||
self.file_handlers = file_handlers
|
||||
|
||||
def process(self):
|
||||
|
||||
for handler in self.file_handlers:
|
||||
handler.process()
|
||||
|
||||
for handler in self.directory_handlers:
|
||||
handler.process()
|
||||
|
||||
|
||||
class LayoutFactory(object):
|
||||
"Creates a layout object"
|
||||
|
||||
def __init__(self, verbose, stream):
|
||||
|
||||
self.verbose = verbose
|
||||
self.output_stream = stream
|
||||
|
||||
def create_layout(self, path):
|
||||
|
||||
contents = os.listdir(path)
|
||||
|
||||
# Build list of directories to process
|
||||
directories = [d for d in contents if self.is_underscore_dir(path, d)]
|
||||
if self.verbose:
|
||||
underscore_directories = [
|
||||
VerboseDirectoryHandler(d, path, self.output_stream)
|
||||
for d in directories
|
||||
]
|
||||
else:
|
||||
underscore_directories = [
|
||||
DirectoryHandler(d, path) for d in directories
|
||||
]
|
||||
|
||||
if not underscore_directories:
|
||||
raise NoDirectoriesError()
|
||||
|
||||
# Build list of files that are in those directories
|
||||
replacers = []
|
||||
for handler in underscore_directories:
|
||||
for directory, dirs, files in os.walk(handler.path()):
|
||||
for f in files:
|
||||
replacers.append(
|
||||
Replacer(
|
||||
handler.relative_path(directory, f),
|
||||
handler.new_relative_path(directory, f)
|
||||
)
|
||||
)
|
||||
|
||||
# Build list of handlers to process all files
|
||||
filelist = []
|
||||
for root, dirs, files in os.walk(path):
|
||||
for f in files:
|
||||
if f.endswith(".html"):
|
||||
filelist.append(
|
||||
FileHandler(os.path.join(root, f), replacers)
|
||||
)
|
||||
|
||||
return Layout(underscore_directories, filelist)
|
||||
|
||||
@staticmethod
|
||||
def is_underscore_dir(path, directory):
|
||||
|
||||
return (os.path.isdir(os.path.join(path, directory))
|
||||
and directory.startswith("_"))
|
||||
|
||||
|
||||
|
||||
def main(args):
|
||||
|
||||
usage = "usage: %prog [options] <html directory>"
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-v","--verbose", action="store_true",
|
||||
dest="verbose", default=False, help="Provides verbose output")
|
||||
opts, args = parser.parse_args(args)
|
||||
|
||||
try:
|
||||
path = args[0]
|
||||
except IndexError:
|
||||
sys.stderr.write(
|
||||
"Error - Expecting path to html directory:"
|
||||
"sphinx-to-github <path>\n"
|
||||
)
|
||||
return
|
||||
|
||||
layout_factory = LayoutFactory(opts.verbose, sys.stdout)
|
||||
|
||||
try:
|
||||
layout = layout_factory.create_layout(path)
|
||||
except NoDirectoriesError:
|
||||
sys.stderr.write(
|
||||
"Error - No top level directories starting with an underscore "
|
||||
"were found in '%s'\n" % path
|
||||
)
|
||||
return
|
||||
|
||||
layout.process()
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user