add cli and various methods to Config class

This commit is contained in:
Izalia Mae 2024-01-07 14:09:38 -05:00
parent 9b9f0c5bed
commit 68433fc968
5 changed files with 145 additions and 33 deletions

View file

@ -1,20 +1,4 @@
import sys
from .config import Config
from .cli import main
config = Config(sys.argv[-1] if sys.argv[-1].endswith("ProjectTorque.exe") else None)
try:
config.load()
except FileNotFoundError:
config.save()
config.setup()
try:
config.run()
except KeyboardInterrupt:
print('Bye')
main()

View file

@ -1,3 +1,62 @@
import click
from pathlib import Path
from .config import Config
@click.group("cli")
@click.pass_context
def cli(ctx):
"Unofficial Linux launcher for Project Torque"
ctx.obj = Config()
try:
ctx.obj.load()
except FileNotFoundError:
ctx.obj.save()
@cli.command("locate")
@click.option("-d", "--directory", help = "Base directory to search from")
@click.pass_context
def cli_locate_bin(ctx, directory: str = None):
"Search for 'ProjectTorque.exe' and set it as the game binary"
search_path = Path(directory or "~/.steam").expanduser().resolve()
click.echo(f"Searching '{search_path}' for 'ProjectTorque.exe'")
try:
path = ctx.obj.locate_bin(directory)
ctx.obj.save()
click.echo(f"Found game binary at '{path}'")
except FileNotFoundError:
click.echo("Could not find game binary")
@cli.command("setup")
@click.option("-n", "--nuke", is_flag = True, help = "Nuke the WINE prefix before continuing")
@click.pass_context
def cli_setup(ctx, nuke: bool = False):
"Setup the WINE prefix for Project Torque"
ctx.obj.setup(nuke = nuke)
click.echo("WINE prefix for Project Torque setup :3")
@cli.command("run", context_settings = {"allow_extra_args": True})
@click.pass_context
def cli_run(ctx):
"Run Project Torque"
if ctx.args and ctx.args[-1].lower().endswith("projecttorque.exe"):
ctx.obj.binpath = Path(ctx.args[-1]).expanduser().resolve()
ctx.obj.run()
def main(): # pylint: disable=missing-function-docstring
cli(prog_name = "ptlaunch") # pylint: disable=no-value-for-parameter

View file

@ -1,6 +1,7 @@
import json
import shutil
import subprocess
import sys
import tarfile
from pathlib import Path
@ -36,7 +37,7 @@ class Config:
:param winetricks: Path to the ``winetricks`` script
"""
self.path = Path(Config.path)
self.path = Path(Config.path).expanduser().resolve()
self.binpath = Path(binpath or Config.binpath).expanduser().resolve()
self.prefix = Path(prefix or Config.prefix).expanduser().resolve()
self.winetricks = Path(winetricks or Config.winetricks).expanduser().resolve()
@ -81,6 +82,36 @@ class Config:
self.winetricks.chmod(0o755)
def load(self):
"Load the config file"
with self.path.open("r", encoding = "utf-8") as fd:
data = json.load(fd)
for param in ("binpath", "prefix", "winetricks"):
path = Path(data.get(param, getattr(Config, param))).expanduser().resolve()
setattr(self, param, path)
def locate_bin(self, directory: str = None) -> Path:
"""
Search for ``ProjectTorque.exe`` and set :attr:`Config.binpath` if it exists
:param directory: Base directory to search. If one is not specified, the steam
directory will be used instead.
:raises FileNotFoundError: If the game binary cannot be found
"""
path = Path(directory or "~/.steam").expanduser().resolve()
for item in path.rglob("*.exe"):
if item.name.lower() == "projecttorque.exe":
self.binpath = item
return item
raise FileNotFoundError("Cannot find 'ProjectTorque.exe'")
def nuke_prefix(self):
"Remove the WINE prefix"
@ -139,35 +170,47 @@ class Config:
)
def setup(self, dxvk_version: str = "2.3", nuke: bool = False, force: bool = False):
def save(self):
"Save the config to a file"
params = ("binpath", "prefix", "winetricks")
data = {param: getattr(self, param) for param in params}
self.path.parent.mkdir(exist_ok = True, parents = True)
with self.path.open("w", encoding = "utf-8") as fd:
json.dump(data, fd, indent = "\t", default = str)
def setup(self, dxvk_version: str = "2.3", nuke: bool = False):
"""
Setup the WINE prefix
:param dxvk_version: Version of DXVK to use
:param nuke: Run :meth:`Config.nuke_prefix` before setting up the prefix
:param force: Run setup even if the prefix is already setup
"""
if self.prefix.joinpath("setup").exists() and not force:
if self.prefix.joinpath("setup").exists() and not nuke:
return
if not self.winetricks.exists():
self.fetch_winetricks()
if nuke:
self.nuke_prefix()
# todo: figure out which prefixes are actually needed
if not self.winetricks.exists():
self.fetch_winetricks()
winetricks_cmd = [
self.winetricks,
# "d3dx9_36",
"mfc80",
"dotnet35sp1",
"tahoma",
# "d3dx9_41",
"d3dcompiler_43",
# "allfonts",
"d3dx9"
# unneeded fixes?
# "allfonts",
# "d3dcompiler_43",
# "d3dx9_36",
# "d3dx9_41",
# "mfc80"
]
if self.run_command(*winetricks_cmd).returncode != 0:
@ -203,3 +246,28 @@ class Config:
if proc.returncode != 0:
raise RuntimeError(f"Failed to register dll: {dll}.dll")
def main(): # pylint: disable=missing-function-docstring
config = Config()
try:
config.load()
except FileNotFoundError:
config.save()
if sys.argv[-1].endswith("ProjectTorque.exe"):
config.binpath = Path(sys.argv[-1]).expanduser().resolve()
config.setup()
try:
config.run()
except KeyboardInterrupt:
print('Bye')
if __name__ == "__main__":
main()

View file

@ -32,5 +32,6 @@ disable = [
"too-few-public-methods",
"too-many-public-methods",
"too-many-return-statements",
"wrong-import-order",
"wrong-import-position"
]

View file

@ -1,5 +1,5 @@
[metadata]
name = CaddyCLI
name = PTLaunch
version = attr: ptlaunch.__version__
description = Run Project Torque in a WINE prefix
long_description = file: README.md
@ -53,7 +53,7 @@ dev =
[options.entry_points]
console_scripts =
caddycli = ptlaunch.cli:main
ptlaunch = ptlaunch.cli:main
[bdist_wheel]