Compare commits

..

No commits in common. "master" and "customStylesheet" have entirely different histories.

View file

@ -1,13 +1,13 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
#takes directory, converts all .adoc files to html files, copying the resulting html files to an identical directory strucuture, and copies over all non .adoc files unchanged. Optionally outputs as a tar.gz file. #takes directory, converts all .adoc files to html files, copying the resulting html files to an identical directory strucuture, and copies over all non .adoc files unchanged. Optionally outputs as a tar.gz file.
import subprocess, argparse, logging, tempfile, shutil, os, glob import subprocess, sys, argparse, logging, tempfile, shutil, os, glob
from pathlib import Path from pathlib import Path
logging.basicConfig(format='%(asctime)s:%(message)s', level=logging.INFO) logging.basicConfig(format='%(asctime)s:%(message)s', level=logging.INFO)
#logging.basicConfig(format='%(asctime)s:%(message)s', level=logging.DEBUG) #logging.basicConfig(format='%(asctime)s:%(message)s', level=logging.DEBUG)
def parse_arguments()->tuple[Path, Path, Path | None, bool, list[str]]: def parse_arguments():
parser=argparse.ArgumentParser(description='create a website directory structure by converting .adoc files in a directory strucutre to .html files.') parser=argparse.ArgumentParser(description='create a website directory structure by converting .adoc files in a directory strucutre to .html files.')
parser.add_argument('inputDir', type=Path, help='The directory of adoc files to be copied and converted.') parser.add_argument('inputDir', type=Path, help='The directory of adoc files to be copied and converted.')
parser.add_argument('-o', '--output', type=Path, help='What to name the generated directory or tar file') parser.add_argument('-o', '--output', type=Path, help='What to name the generated directory or tar file')
@ -27,23 +27,23 @@ def parse_arguments()->tuple[Path, Path, Path | None, bool, list[str]]:
if args.output != None and not args.compress: if args.output != None and not args.compress:
#detect based on whether outFile has a .tar.gz filename. #detect based on whether outFile has a .tar.gz filename.
if args.output.suffixes == ['.tar', '.gz']: if args.output.suffixes == ['.tar', '.gz']:
compress:bool=True compress=True
else: else:
compress:bool=False compress=False
else: else:
compress:bool=args.compress compress=args.compress
#If outfile was not set, set it. #If outfile was not set, set it.
if args.output == None: if args.output == None:
baseName:str=args.inputDir.with_name(args.inputDir.name+'_compiled').name baseName=args.inputDir.with_name(args.inputDir.name+'_compiled').name
outFile:Path=Path(os.getcwd()).joinpath(baseName) outFile=Path(os.getcwd()).joinpath(baseName)
else: else:
outFile:Path=Path(args.output.resolve()) outFile=args.output.resolve()
#add .tar.gz if compress is set and the outfile does not already have it. #add .tar.gz if compress is set and the outfile does not already have it.
if compress and outFile.suffixes != ['.tar', '.gz']: if compress and outFile.suffixes != ['.tar', '.gz']:
logging.info(f'outFile was {outFile}, corrected because compress flag is set.') logging.info(f'outFile was {outFile}, corrected because compress flag is set.')
outFile:Path=outFile.with_suffix('.tar.gz').resolve() outFile=outFile.with_suffix('.tar.gz').resolve()
if args.inputDir.resolve() == outFile.resolve(): if args.inputDir.resolve() == outFile.resolve():
raise FileExistsError('output file cannot have the same path as the input file!') raise FileExistsError('output file cannot have the same path as the input file!')
@ -52,7 +52,7 @@ def parse_arguments()->tuple[Path, Path, Path | None, bool, list[str]]:
logging.info(f'outputting to {outFile.resolve()}') logging.info(f'outputting to {outFile.resolve()}')
logging.debug(f'compress is {compress}') logging.debug(f'compress is {compress}')
exclude:list[str]=[] exclude=[]
if args.exclude_file != None: if args.exclude_file != None:
with open(args.exclude_file, 'r') as file: with open(args.exclude_file, 'r') as file:
exclude=[glob.strip() for glob in file] exclude=[glob.strip() for glob in file]
@ -64,56 +64,53 @@ def parse_arguments()->tuple[Path, Path, Path | None, bool, list[str]]:
print(f'Inputdir {args.inputDir.resolve()} does not exist!') print(f'Inputdir {args.inputDir.resolve()} does not exist!')
exit() exit()
stylesheet:Path|None=None stylesheet=None
if args.stylesheet != None: if args.stylesheet != None:
stylesheet=args.stylesheet.resolve() stylesheet =args.stylesheet.resolve()
logging.info(f'using stylesheet {stylesheet}') logging.info(f'using stylesheet {stylesheet}')
return Path(args.inputDir.resolve()), outFile, stylesheet, compress, exclude return args.inputDir.resolve(), outFile, stylesheet, compress, exclude
#Doing it in a tmpDir first, as some distrubutions put temp files on a ramdisk. this should speed up the operation sigificantly. #Doing it in a tmpDir first, as some distrubutions put temp files on a ramdisk. this should speed up the operation sigificantly.
class TmpDir: class TmpDir:
def __init__(self, srcDir:Path, exclude:list[str]): def __init__(self, srcDir, exclude):
self.tmpDir=tempfile.TemporaryDirectory() self.tmpDir=tempfile.TemporaryDirectory()
logging.debug(f'making tmp file from {srcDir} at {self.tmpDir.name}') logging.debug(f'making tmp file from {srcDir} at {self.tmpDir.name}')
self.path:Path=Path(self.tmpDir.name+'/'+Path(srcDir).resolve().name) self.path=self.tmpDir.name+'/'+Path(srcDir).resolve().name
self.ignorePatterns:list[str]=['*.adoc', '.gitignore', '.git/*'] self.ignorePatterns=['*.adoc', '.gitignore', '.git/*']
self.ignorePatterns.extend(exclude) self.ignorePatterns.extend(exclude)
self.ignorePattern=shutil.ignore_patterns(*self.ignorePatterns) self.ignorePattern=shutil.ignore_patterns(*self.ignorePatterns)
shutil.copytree(srcDir, self.path, ignore=self.ignorePattern, symlinks=False) shutil.copytree(srcDir, self.path, ignore=self.ignorePattern, symlinks=False)
#copy out from tmpDir (which may be in RAM, depending on distrubution) to disk #copy out from tmpDir (which may be in RAM, depending on distrubution) to disk
def copy_self_to(self, destPath:Path): def copy_self_to(self, destPath):
logging.debug(f'outputting to {Path(destPath).resolve()}') logging.debug(f'outputting to {Path(destPath).resolve()}')
shutil.copytree(self.path, destPath, symlinks=False) shutil.copytree(self.path, destPath, symlinks=False)
#copy out from tmpDir (which may be in RAM, depending on distrubution) to a compressed file on disk #copy out from tmpDir (which may be in RAM, depending on distrubution) to a compressed file on disk
def compress_and_copy_self_to(self, destPath:Path)->Path: def compress_and_copy_self_to(self, destPath):
#shutil.make_archive wants destPath to be without file extentions for some godforsaken reason. #shutil.make_archive wants destPath to be without file extentions for some godforsaken reason.
destPath=Path(destPath.with_name(destPath.name.split('.')[0])).resolve() destPath=Path(destPath.with_name(destPath.name.split('.')[0])).resolve()
logging.debug(f'compressing to {Path(destPath).resolve()} from {Path(self.path).parent}') logging.debug(f'compressing to {Path(destPath).resolve()} from {Path(self.path).parent}')
tarFile:Path=Path(shutil.make_archive(str(destPath), 'gztar', Path(self.path).parent)) tarFile=shutil.make_archive(destPath, 'gztar', Path(self.path).parent)
return tarFile
def cleanup(self): def cleanup(self):
self.tmpDir.cleanup() self.tmpDir.cleanup()
#works on the current working directory #works on the current working directory
def find_paths_to_convert(fileNameGlob:str)->list[Path]: def find_paths_to_convert(fileNameGlob):
pathstrings: list[str] = glob.glob(f'**/{fileNameGlob}', recursive=True) return glob.glob(f'**/{fileNameGlob}', recursive=True)
paths:list[Path]=[Path(i) for i in pathstrings]
return paths
#finds the depth of a file relative to given directory #finds the depth of a file relative to given directory
def find_relative_file_depth (subfile:Path, parentDir:Path)->int: def find_relative_file_depth (subfile, parentDir):
subfile=Path(subfile).resolve() subfile=Path(subfile).resolve()
parentDir=Path(parentDir).resolve() parentDir=Path(parentDir).resolve()
return len(subfile.parts)-len(parentDir.parts)-1 return len(subfile.parts)-len(parentDir.parts)-1
#simple wrapper around the asciidoctor cli. #simple wrapper around the asciidoctor cli.
def convert_file(inDir: Path, outDir: Path, inFile: Path, stylesheet: Path|None): def convert_file(inDir: Path, outDir: Path, inFile: Path, stylesheet: Path):
#in order for the stylesdir and imagesdir to be linked to correctly, we need to know the relative depth between the two directories. #in order for the stylesdir and imagesdir to be linked to correctly, we need to know the relative depth between the two directories.
depth:int=find_relative_file_depth(inFile, inDir) depth=find_relative_file_depth(inFile, inDir)
logging.info(f'converting {Path(inFile).resolve()}') logging.info(f'converting {Path(inFile).resolve()}')
logging.debug(f'converting {inFile=}, {outDir=}, {inDir=}, {stylesheet=}') logging.debug(f'converting {inFile=}, {outDir=}, {inDir=}, {stylesheet=}')
@ -131,7 +128,7 @@ def convert_file(inDir: Path, outDir: Path, inFile: Path, stylesheet: Path|None)
#Destination dir. It takes the file from the subtree --source-dir and puts it in the equivilant location in the subtree --destination-dir. (talking about filesystem subtrees). #Destination dir. It takes the file from the subtree --source-dir and puts it in the equivilant location in the subtree --destination-dir. (talking about filesystem subtrees).
f'--destination-dir={outDir}', f'--destination-dir={outDir}',
inFile] inFile]
if stylesheet != None: if stylesheet != None:
arguments.insert(1, f'--attribute=copycss={stylesheet}') arguments.insert(1, f'--attribute=copycss={stylesheet}')
arguments.insert(1, f'--attribute=stylesheet={stylesheet.name}') arguments.insert(1, f'--attribute=stylesheet={stylesheet.name}')
@ -148,11 +145,11 @@ def convert_file(inDir: Path, outDir: Path, inFile: Path, stylesheet: Path|None)
if __name__ == '__main__': if __name__ == '__main__':
inFile, outFile, stylesheet, compress, exclude=parse_arguments() inFile, outFile, stylesheet, compress, exclude=parse_arguments()
os.chdir(inFile) os.chdir(inFile)
tmpDir=TmpDir(Path('./'), exclude) tmpDir=TmpDir('./', exclude)
pathsToConvert:list[Path]=find_paths_to_convert('*.adoc') pathsToConvert=find_paths_to_convert('*.adoc')
for i in pathsToConvert: for i in pathsToConvert:
convert_file(inDir=Path('./'), outDir=tmpDir.path, inFile=i, stylesheet=stylesheet) convert_file(inDir='./', outDir=tmpDir.path, inFile=i, stylesheet=stylesheet)
if compress: if compress:
tmpDir.compress_and_copy_self_to(outFile) tmpDir.compress_and_copy_self_to(outFile)