106 lines
4.1 KiB
Python
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) |