165 lines
5.2 KiB
Python
165 lines
5.2 KiB
Python
"""
|
|
Command line module for making Team Fortress 2 macro scripts from
|
|
YAML source code.
|
|
"""
|
|
|
|
__all__ = ['parseFile']
|
|
__author__ = "Nicholas Hope <tfscript@nickhope.world"
|
|
__date__ = "26 August 2022"
|
|
__version__ = "1.0"
|
|
__copyright__ = "Copyright © 2022 Nicholas Hope. See LICENSE for details."
|
|
|
|
# Standard libraries
|
|
from sys import stderr
|
|
from os import mkdir, sep as dirsep
|
|
from os.path import isdir, expanduser, normpath
|
|
import argparse
|
|
from warnings import warn
|
|
from tempfile import NamedTemporaryFile
|
|
import yaml
|
|
from platform import system as GetOSName, release as GetOSRelease
|
|
|
|
try:
|
|
from winreg import HKEY_LOCAL_MACHINE, ConnectRegistry, OpenKey, EnumValue
|
|
except ModuleNotFoundError:
|
|
# Not running on windows
|
|
pass
|
|
|
|
# Local libraries
|
|
import tfscript
|
|
from tfscript import verify
|
|
from tfscript import writing
|
|
|
|
args = {}
|
|
targetDir = ""
|
|
|
|
def parseFile(inputFile) -> (dict, dict):
|
|
"""Parse, verify, and do the conversion."""
|
|
config = yaml.safe_load(inputFile)
|
|
|
|
# See verify.py
|
|
config, aliases = verify.verifyConfig(config)
|
|
if "errors" in config:
|
|
for cclass, messages in config["errors"].items():
|
|
print(f"Error in {cclass}:")
|
|
for msg in messages:
|
|
print(f" {msg}")
|
|
return None, None
|
|
else:
|
|
return config, aliases
|
|
|
|
def parseConfig(config, defaults):
|
|
"""With validated data structure, write out all the files."""
|
|
global args
|
|
global targetDir
|
|
|
|
if isdir(targetDir) == False:
|
|
mkdir(targetDir)
|
|
if args.debug:
|
|
print( f"DEBUG: Created directory {targetDir}", file=stderr)
|
|
|
|
tempsAndReals = {}
|
|
|
|
if defaults is not None:
|
|
stringToWrite = tfscript.makeCFG(defaults, default=True)
|
|
replaceDict = writing.writeOutput(stringToWrite, "default", args)
|
|
tempsAndReals.update(replaceDict)
|
|
|
|
for currentClass in config:
|
|
classDict = config[currentClass]
|
|
stringToWrite = tfscript.makeCFG(classDict)
|
|
replaceDict = writing.writeOutput(stringToWrite, currentClass, args)
|
|
tempsAndReals.update(replaceDict)
|
|
|
|
return tempsAndReals
|
|
|
|
def parseCLI():
|
|
# 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.")
|
|
parser.add_argument( '-f', '--force', action='store_true',
|
|
help="Force tfscript to continue until catastrophic failure")
|
|
parser.add_argument( '-D', '--directory', action='store', type=str,
|
|
help="Change output directory")
|
|
# 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):
|
|
if systemName == "Darwin":
|
|
if float( '.'.join( GetOSRelease().split('.')[0:2] ) ) >= 10.15:
|
|
warn(
|
|
"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 )
|
|
return expanduser("~/Library/Application Support/Steam")
|
|
|
|
elif systemName == "Windows":
|
|
# oh god why do we have to use the registry
|
|
accessReg = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
|
|
accessKey = OpenKey(accessReg, "SOFTWARE\\WOW6432Node\\Valve\\Steam")
|
|
keyNum = 0
|
|
while True:
|
|
try:
|
|
accessSubkeyName, data, _ = EnumValue(accessKey, keyNum)
|
|
if accessSubkeyName == "InstallPath":
|
|
return data
|
|
except EnvironmentError:
|
|
break
|
|
keyNum += 1
|
|
return None
|
|
|
|
elif systemName == "Linux":
|
|
return expanduser("~/.local/Steam")
|
|
|
|
elif systemName == "Java":
|
|
warn("Java-based OSes are not supported yet by tfscript.", category=RuntimeWarning)
|
|
|
|
return None
|
|
|
|
def main() -> int:
|
|
""" Command line interface. """
|
|
global args
|
|
global targetDir
|
|
parser = parseCLI()
|
|
|
|
args = parser.parse_args()
|
|
|
|
systemName = GetOSName()
|
|
if args.directory is not None:
|
|
targetDir = normpath(args.directory) + dirsep
|
|
else:
|
|
targetDir = getTargetDir(systemName)
|
|
if targetDir is not None:
|
|
# Supported OS: add steamapps path
|
|
targetDir += normpath("/steamapps/common/Team Fortress 2/tf/cfg") + dirsep
|
|
elif args.force:
|
|
# Unsupported OS but -f specified
|
|
if args.debug:
|
|
print("DEBUG: forced to continue, output set to current directory", file=stderr)
|
|
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)
|
|
defaultsGiven = (defaults is not None)
|
|
writing.appendToActuals(targetDir, fileList, defaultsGiven, args)
|
|
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
exit(main())
|