tfscript/src/tfscript/cli.py

106 lines
4.1 KiB
Python

"""CLI module for converting YAML to tfscript"""
# https://www.w3schools.io/file/yaml-arrays/
# Standard libraries
import sys
import os
import argparse
import tempfile
import yaml
# Local libraries
import tfscript
import verify
def parseFile(inputFile):
"""Parse, verify, and do the conversion."""
config = yaml.safe_load(inputFile)
# See verify.py
config = verify.verifyConfig(config)
if "errors" in config:
for e in config["errors"]:
print(e,file=sys.stderr)
else:
parseConfig(config)
def writeOutput(scriptString, className):
"""Given the string of stuff to write, write it out to the given handle."""
global args
prefix = './cfg'
chunksize = 2**20 # 1Mb maximum cfg file size
chunk = 1
# Make sure ./cfg exists before we try to use it
if os.path.isdir( prefix ) == False:
try:
os.mkdir( prefix )
if args.debug:
print( f'DEBUG: created {prefix}')
except Exception as fileExcept:
print( f'WARN: Failed to create {prefix}: {fileExcept.strerror}\nUsing current directory instead.' )
prefix = '.'
# If the string is more than 1048576 bytes, we need divide it into files that each
# are less than 1048576 bytes
chunksneeded = int( 1 + len(scriptString) / chunksize )
if args.debug:
print( f'DEBUG: need {chunksneeded} files for {className}')
if( chunksneeded == 1):
# If it can be done in one chunk, do it in one chunk.
outfile = tempfile.NamedTemporaryFile( prefix=className, delete=False )
if args.debug:
print( f'DEBUG: created temporary {outfile.name} ')
outfile.write(scriptString.encode("utf8"))
outfile.close()
os.replace(outfile.name, f'{prefix}/{className}_script_{chunk:02d}.cfg')
if args.debug:
print( f'DEBUG: Created {prefix}/{className}_script_{chunk:02d}.cfg')
else:
# Gotta do it in multiple chunks
classLines = scriptString.splitlines()
execString = f'exec {className}_script_{chunk:02d}'.encode("utf8")
# extra 4 bytes is just a little buffer so we don't get exactly chunksize bytes
reservedSpace = len(execString) + 4
n = 0
while( chunk <= chunksneeded ):
outfile = tempfile.NamedTemporaryFile( prefix=className, delete=False )
byteswritten = 0
if args.debug:
print( f'DEBUG: created temporary {outfile.name} ')
while( n < len(classLines) and (byteswritten + len(classLines[n]) + reservedSpace) < chunksize ):
line = classLines[n].encode("utf8") + os.linesep.encode("utf8")
outfile.write(line)
byteswritten += len(line)
n+=1
if( chunk < chunksneeded ):
line = f'exec {className}_script_{chunk+1:02d}'.encode("utf8") + os.linesep.encode("utf8")
outfile.write(line)
byteswritten += len(line)
outfile.close()
os.replace(outfile.name, f'{prefix}/{className}_script_{chunk:02d}.cfg')
if args.debug:
print( f'DEBUG: Wrote {byteswritten} bytes to {prefix}/{className}_script_{chunk:02d}.cfg')
chunk += 1
def parseConfig(config):
"""With validated data structure, write out all the files."""
for currentClass in config:
classDict = config[currentClass]
stringToWrite = tfscript.makeCFG(classDict)
writeOutput(stringToWrite, currentClass)
# Main function
if __name__ == "__main__":
# Handle command line
parser = argparse.ArgumentParser(
description="Parse YAML file and produce TF2 config script."
)
parser.add_argument( '-d', '--debug', action='store_true',
help="Enable debugging messages.")
parser.add_argument( '-n', '--dry-run', action='store_true',
help="Parse input file, but don't write anything.")
# positional argument: first non-hyphenated argument is input file
parser.add_argument( 'infile', type=argparse.FileType('r'),
help='File containing YAML to convert.')
args = parser.parse_args()
parseFile(args.infile)