"""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)