tfscript/src/tfscript/cli.py

181 lines
5.7 KiB
Python
Raw Normal View History

2022-08-21 21:21:09 -04:00
'''
Command line module for making Team Fortress 2 macro scripts from
YAML source code.
2022-08-21 21:21:09 -04:00
'''
__all__ = ['parseFile']
2022-08-21 21:21:09 -04:00
__author__ = 'Nicholas Hope <tfscript@nickhope.world'
__date__ = '26 August 2022'
__version__ = '1.0'
__copyright__ = 'Copyright © 2022 Nicholas Hope. See LICENSE for details.'
2022-08-06 21:45:36 -04:00
# Standard libraries
2022-08-14 13:07:08 -04:00
from sys import stderr
2022-08-19 21:34:45 -04:00
from os import mkdir, sep as dirsep
2022-08-14 13:07:08 -04:00
from os.path import isdir, expanduser, normpath
2022-08-06 21:45:36 -04:00
import argparse
2022-08-14 13:07:08 -04:00
from warnings import warn
from tempfile import NamedTemporaryFile
2022-08-06 21:45:36 -04:00
import yaml
from platform import system as GetOSName, release as GetOSRelease
try:
2022-08-14 13:07:08 -04:00
from winreg import HKEY_LOCAL_MACHINE, ConnectRegistry, OpenKey, EnumValue
except ModuleNotFoundError:
# Not running on windows
pass
2022-08-06 21:45:36 -04:00
# Local libraries
import tfscript
2022-09-17 14:08:25 -04:00
from tfscript import verify, writing, makeCFG
args = {}
2022-08-21 21:21:09 -04:00
targetDir = ''
2022-08-06 21:45:36 -04:00
def parseFile(inputFile) -> (dict, dict):
2022-08-21 21:21:09 -04:00
'''Parse, verify, and do the conversion.'''
2022-08-06 21:45:36 -04:00
config = yaml.safe_load(inputFile)
# See verify.py
2022-08-21 21:21:09 -04:00
config, defaults = verify.verifyConfig(config)
2022-10-02 12:12:15 -04:00
if 'warnings' in config:
for cclass, messages in config.pop('warnings').items():
print(f'Warning in {cclass}:', file=stderr)
for msg in messages:
print(f' {msg}', file=stderr)
2022-08-21 21:21:09 -04:00
if 'errors' in config:
for cclass, messages in config['errors'].items():
2022-08-25 20:34:38 -04:00
print(f'Error in {cclass}:', file=stderr)
for msg in messages:
2022-08-25 20:34:38 -04:00
print(f' {msg}', file=stderr)
return None, None
2022-08-06 21:45:36 -04:00
else:
2022-08-21 21:21:09 -04:00
return config, defaults
def parseConfig(config, defaults):
2022-08-21 21:21:09 -04:00
'''With validated data structure, write out all the files.'''
global args
global targetDir
2022-08-14 13:07:08 -04:00
if isdir(targetDir) == False:
mkdir(targetDir)
if args.debug:
2022-08-21 21:21:09 -04:00
print( f'DEBUG: Created directory {targetDir}', file=stderr)
tempsAndReals = {}
if defaults is not None:
2022-09-04 09:25:33 -04:00
config.update({'default': defaults})
2022-09-17 14:08:25 -04:00
for class_ in config:
stringToWrite = makeCFG(
config[class_],
default=(class_ == 'default')
)
replaceDict = writing.writeOutput(stringToWrite, class_, args)
2022-09-04 09:25:33 -04:00
tempsAndReals.update(replaceDict)
return tempsAndReals
2022-08-06 21:45:36 -04:00
def parseCLI():
2022-08-06 21:45:36 -04:00
# Handle command line
parser = argparse.ArgumentParser(
2022-08-21 21:21:09 -04:00
description='Parse YAML file and produce TF2 config script.'
2022-08-06 21:45:36 -04:00
)
parser.add_argument( '-d', '--debug', action='store_true',
2022-08-21 21:21:09 -04:00
help='Enable debugging messages.')
2022-08-06 21:45:36 -04:00
parser.add_argument( '-n', '--dry-run', action='store_true',
2022-08-21 21:21:09 -04:00
help='Parse input file, but don\'t write anything.')
parser.add_argument( '-f', '--force', action='store_true',
2022-08-21 21:21:09 -04:00
help='Force tfscript to continue until catastrophic failure')
parser.add_argument( '-D', '--directory', action='store', type=str,
2022-08-21 21:21:09 -04:00
help='Change output directory')
2022-10-05 21:31:58 -04:00
# warnings
parseWarnNames = [
'implicit-release', 'implicit-off',
'implicit-primary', 'implicit-secondary',
'implicit'
]
for warnName in parseWarnNames:
splitWarnName = ' '.join(warnName.split('-'))
parser.add_argument( '-W' + warnName, action='store_true',
help=f'Generate warning on {splitWarnName} creation')
2022-08-06 21:45:36 -04:00
# positional argument: first non-hyphenated argument is input file
parser.add_argument( 'infile', type=argparse.FileType('r'),
help='File containing YAML to convert.')
return parser
def getTargetDir(systemName):
2022-08-21 21:21:09 -04:00
if systemName == 'Darwin':
if float( '.'.join( GetOSRelease().split('.')[0:2] ) ) >= 10.15:
2022-08-14 13:07:08 -04:00
warn(
2022-10-05 21:31:58 -04:00
'As of macOS Catalina (v10.15), 32-bit applications'
+ ' like TF2 do not run. tfscript will run, but you can\'t run TF2'
+ ' on this system',
category=RuntimeWarning )
2022-10-05 21:31:58 -04:00
return None
return expanduser('~/Library/Application Support/Steam')
2022-08-21 21:21:09 -04:00
elif systemName == 'Windows':
# oh god why do we have to use the registry
2022-08-14 13:07:08 -04:00
accessReg = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
2022-08-21 21:21:09 -04:00
accessKey = OpenKey(accessReg, 'SOFTWARE\\WOW6432Node\\Valve\\Steam')
2022-08-13 20:16:21 -04:00
keyNum = 0
while True:
try:
2022-08-14 13:07:08 -04:00
accessSubkeyName, data, _ = EnumValue(accessKey, keyNum)
2022-08-21 21:21:09 -04:00
if accessSubkeyName == 'InstallPath':
2022-08-13 20:16:21 -04:00
return data
except EnvironmentError:
break
keyNum += 1
return None
2022-08-21 21:21:09 -04:00
elif systemName == 'Linux':
return expanduser('~/.local/Steam')
2022-08-21 21:21:09 -04:00
elif systemName == 'Java':
warn('Java-based OSes are not supported yet by tfscript.', category=RuntimeWarning)
return None
def main() -> int:
2022-08-21 21:21:09 -04:00
''' Command line interface. '''
global args
global targetDir
parser = parseCLI()
2022-08-06 21:45:36 -04:00
args = parser.parse_args()
systemName = GetOSName()
if args.directory is not None:
2022-08-19 21:34:45 -04:00
targetDir = normpath(args.directory) + dirsep
else:
targetDir = getTargetDir(systemName)
if targetDir is not None:
# Supported OS: add steamapps path
2022-08-21 21:21:09 -04:00
targetDir += normpath('/steamapps/common/Team Fortress 2/tf/cfg') + dirsep
elif args.force:
# Unsupported OS but -f specified
if args.debug:
2022-08-21 21:21:09 -04:00
print('DEBUG: forced to continue, output set to current directory', file=stderr)
2022-08-09 19:09:46 -04:00
targetDir = '.'
else:
# Unsupported OS and not forced to continue
return 2
config, defaults = parseFile(args.infile)
if config is None:
return 2
fileNames = parseConfig(config, defaults)
fileList = writing.replaceFiles(targetDir, fileNames, args)
2022-08-14 15:47:48 -04:00
defaultsGiven = (defaults is not None)
writing.appendToActuals(targetDir, fileList, defaultsGiven, args)
return 0
2022-08-21 21:21:09 -04:00
if __name__ == '__main__':
exit(main())