From 0c137b6403accd771c406f4d9ae8f540d46186b6 Mon Sep 17 00:00:00 2001 From: Jesse Sopel Date: Sat, 7 Oct 2017 18:21:16 -0400 Subject: [PATCH] Add editor config for spaces, some pep8 and fixes in setup module to read/write the vdf file --- .editorconfig | 13 ++++ .gitignore | 2 + README.md | 2 +- bin/steamfootbridge | 33 ++++---- setup.py | 13 ++-- steamfootbridge/config.py | 147 ++++++++++++++++++++---------------- steamfootbridge/download.py | 21 +++--- steamfootbridge/execute.py | 12 +-- steamfootbridge/setup.py | 46 ++++++----- 9 files changed, 168 insertions(+), 121 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1a773c4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +insert_final_newline = true + + +# 4 space indentation +[*.py] +charset = utf-8 +indent_style = space +indent_size = 4 diff --git a/.gitignore b/.gitignore index d579f3d..5bd01ed 100644 --- a/.gitignore +++ b/.gitignore @@ -89,3 +89,5 @@ ENV/ .ropeproject .*.sw* + +.idea diff --git a/README.md b/README.md index e54bd3b..9bc5cad 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ For when the [Regular Bridge] [SteamBridge] is too... *sketchy*. Installation includes an executable Python script named steamfootbridge. -~~Run **steamfootbridge setup** to configure the Wine Steam installation~~ Actually a no-op +Run **steamfootbridge setup** to configure the Wine Steam installation right now. Run **steamfootbridge download (appid)** to download the application corresponding to (appid) diff --git a/bin/steamfootbridge b/bin/steamfootbridge index af50183..42db3fd 100644 --- a/bin/steamfootbridge +++ b/bin/steamfootbridge @@ -1,13 +1,16 @@ #!/usr/bin/env python3 -import argparse, os, sys +import argparse +import sys import steamfootbridge -def error(message): + +def print_error(message): print("{}: {}".format(steamfootbridge.__app_name__, message)) exit(1) -def help(): + +def print_help(): print("Command: \t \t \t Description:") print("\t-v, --version or version : Prints the version of steamfootbridge to the screen") print("\t-h, --help or help : Prints this screen") @@ -16,14 +19,18 @@ def help(): print("\tsetup {steamid} : Set up a new Wineprefix for the specified app") exit(0) -def version(): + +def print_version(): print("{} {}".format(steamfootbridge.__app_name__, steamfootbridge.__version__)) exit(0) + class CLI: def create_parser(self, command, description): - return argparse.ArgumentParser(prog="{} {}".format(steamfootbridge.__app_name__, command), - description=description) + return argparse.ArgumentParser( + prog="{} {}".format(steamfootbridge.__app_name__, command), + description=description + ) def download(self, args): parser = self.create_parser("download", "Download an application inside Wine Steam") @@ -31,7 +38,6 @@ class CLI: args = parser.parse_args(args) steamfootbridge.download.do(args.appid) - def execute(self, args): parser = self.create_parser("execute", "Execute an application inside Wine Steam") parser.add_argument("appid", type=int, help="the Steam application's AppID") @@ -43,16 +49,17 @@ class CLI: args = parser.parse_args(args) steamfootbridge.setup.do() + if len(sys.argv) < 2: - error("Need a command") + print_error("Need a command") cmd = sys.argv[1].lower() cli = CLI() -if cmd == "--help" or cmd == "-h" or cmd == "help": - help() -elif cmd == "--version" or cmd == "-v" or cmd == "version": - version() +if cmd in ("--help", "-h", "help"): + print_help() +elif cmd in ("--version", "-v", "version"): + print_version() elif cmd == "download": cli.download(sys.argv[2:]) elif cmd == "execute": @@ -60,5 +67,5 @@ elif cmd == "execute": elif cmd == "setup": cli.setup(sys.argv[2:]) else: - error("Unknown or unrecognized command: {}".format(cmd)) + print_error("Unknown or unrecognized command: {}".format(cmd)) diff --git a/setup.py b/setup.py index 14bf8c2..b574292 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,11 @@ from setuptools import setup -setup(name='steamfootbridge', - version='0.0.1', - packages=['steamfootbridge'], - scripts=['bin/steamfootbridge'], - install_requires=[ +setup( + name='steamfootbridge', + version='0.0.1', + packages=['steamfootbridge'], + scripts=['bin/steamfootbridge'], + install_requires=[ 'steamodd', - ], + ], ) diff --git a/steamfootbridge/config.py b/steamfootbridge/config.py index b875d00..f08bdd0 100644 --- a/steamfootbridge/config.py +++ b/steamfootbridge/config.py @@ -1,7 +1,11 @@ # SteamFootBridge # Copyright (c) 2016 Bryan DeGrendel -import os, re, shutil, string, subprocess, tempfile +import os +import re +import shutil +import subprocess +import tempfile # NOTE: No explict \"s around the path. They're necessary when running as an actual shell to keep # the shell from parsing the slash and whatnot, but are actually stripped out when passed @@ -13,69 +17,80 @@ __wine_steam_user_directories__ = "/userdata" __wine_steam_userconfig_file__ = "/config/localconfig.vdf" + +STEAM_EXE_REGEX = re.compile(r'"SteamExe"="(.*)"') +STEAM_PATH_REGEX = re.compile(r'"SteamPath"="(.*)"') + + class Configuration: - def __init__(self): - pass - - def __enter__(self): - self._temp_directory = tempfile.mkdtemp("steamfootbridge") - self._read_registry_keys() - self._userid = self._determine_current_user() - return self - - def __exit__(self, exception_type, exception_value, traceback): - shutil.rmtree(self._temp_directory) - - def get_wine_steam_windows_executable(self): - return self._wine_steam_windows_executable - - def get_wine_steam_windows_path(self): - return self._wine_steam_windows_path - - def get_wine_steam_path(self): - return self._wine_steam_path - - def get_current_user(self): - return self._userid - - def get_wine_steam_userconfig_filename(self): - return "{}{}/{}{}".format(self.get_wine_steam_path(), __wine_steam_user_directories__, - self._userid, __wine_steam_userconfig_file__) - - def _determine_current_user(self): - directories = os.listdir(self._wine_steam_path.decode() + __wine_steam_user_directories__) - if len(directories) == 0: - raise StandardException("No users found! Have you logged into Wine Steam?") - elif len(directories) > 1: - raise StandardException("Mulitple users found! This will evenatually be handled correctly") - else: - return directories[0] - - - # TODO: This is awfully slow, and it's /probably/ fine to just get the Wine Prefix and do a - # direct search through user.reg - and probably considerably faster. - # TODO: Should handle not finding keys or regedit error or whatever - # TODO: It's probably a good idea to cache this if sticking with regedit, and re-read on request - # or if the path isn't valid - # TODO: Should check to make sure executable actually exists, and path is a directory - def _read_registry_keys(self): - subprocess.call(["regedit", "-E", - "{}/{}".format(self._temp_directory, __wine_registry_dump_file__), - __wine_registry_steam_key__]) - self._wine_steam_windows_path = None - self._wine_steam_windows_executable = None - with open("{}/{}".format(self._temp_directory, __wine_registry_dump_file__)) as f: - for line in f: - result = re.search("\"SteamExe\"=\"(.*)\"", line) - if result: - self._wine_steam_windows_executable = result.group(1) - - result = re.search("\"SteamPath\"=\"(.*)\"", line) - if result: - self._wine_steam_windows_path = result.group(1) - if self._wine_steam_windows_path == None: - raise StandardException("Unable to determine the SteamPath") - if self._wine_steam_windows_executable == None: - raise StandardException("Unable to determine the SteamExe") - self._wine_steam_path = subprocess.check_output(["winepath", - self._wine_steam_windows_path]).strip() + def __init__(self): + pass + + def __enter__(self): + self._temp_directory = tempfile.mkdtemp("steamfootbridge") + self._read_registry_keys() + self._userid = self._determine_current_user() + return self + + def __exit__(self, exception_type, exception_value, traceback): + shutil.rmtree(self._temp_directory) + + def get_wine_steam_windows_executable(self): + return self._wine_steam_windows_executable + + def get_wine_steam_windows_path(self): + return self._wine_steam_windows_path + + def get_wine_steam_path(self): + return self._wine_steam_path + + def get_current_user(self): + return self._userid + + def get_wine_steam_userconfig_filename(self): + return "{}{}/{}{}".format( + self.get_wine_steam_path(), __wine_steam_user_directories__, self._userid, __wine_steam_userconfig_file__ + ) + + def _determine_current_user(self): + directories = os.listdir(self._wine_steam_path + __wine_steam_user_directories__) + if len(directories) == 0: + raise Exception("No users found! Have you logged into Wine Steam?") + elif len(directories) > 1: + raise Exception("Mulitple users found! This will evenatually be handled correctly") + else: + return directories[0] + + # TODO: This is awfully slow, and it's /probably/ fine to just get the Wine Prefix and do a + # direct search through user.reg - and probably considerably faster. + # TODO: Should handle not finding keys or regedit error or whatever + # TODO: It's probably a good idea to cache this if sticking with regedit, and re-read on request + # or if the path isn't valid + # TODO: Should check to make sure executable actually exists, and path is a directory + def _read_registry_keys(self): + subprocess.call([ + "regedit", "-E", "{}/{}".format( + self._temp_directory, __wine_registry_dump_file__ + ), + __wine_registry_steam_key__ + ]) + self._wine_steam_windows_path = None + self._wine_steam_windows_executable = None + with open("{}/{}".format(self._temp_directory, __wine_registry_dump_file__), encoding='utf-16') as f: + for line in f: + result = STEAM_EXE_REGEX.search(line) + if result: + self._wine_steam_windows_executable = result.group(1) + + result = STEAM_PATH_REGEX.search(line) + if result: + self._wine_steam_windows_path = result.group(1) + if self._wine_steam_windows_path is None: + raise Exception("Unable to determine the SteamPath") + + if self._wine_steam_windows_executable is None: + raise Exception("Unable to determine the SteamExe") + + self._wine_steam_path = subprocess.check_output( + ["winepath", self._wine_steam_windows_path] + ).strip().decode('utf-8') diff --git a/steamfootbridge/download.py b/steamfootbridge/download.py index 2a9bec9..eae53de 100644 --- a/steamfootbridge/download.py +++ b/steamfootbridge/download.py @@ -5,14 +5,15 @@ from . import config + def do(appid): - print("Downloading {}".format(appid)) - with config.Configuration() as c: - # NOTE: It appears that generated shortcuts are little more than - # C:\\Windows\command\start.exe steam://rungameid/ - # Which I'm 90% sure is simply redirecting to Steam.exe steam://rungameid/ - # - possibly with quotation marks. If so, we probably don't need anything beyond this. - # TODO: In the future, SteamFootBridge will cache the list of possible applications and their - # states. Starting a download like this should trigger a refresh. - subprocess.Popen(["wine", c.get_wine_steam_windows_executable(), "-silent", - "steam://install/{}".format(appid)]) + print("Downloading {}".format(appid)) + with config.Configuration() as c: + # NOTE: It appears that generated shortcuts are little more than + # C:\\Windows\command\start.exe steam://rungameid/ + # Which I'm 90% sure is simply redirecting to Steam.exe steam://rungameid/ + # - possibly with quotation marks. If so, we probably don't need anything beyond this. + # TODO: In the future, SteamFootBridge will cache the list of possible applications and their + # states. Starting a download like this should trigger a refresh. + subprocess.Popen(["wine", c.get_wine_steam_windows_executable(), "-silent", + "steam://install/{}".format(appid)]) diff --git a/steamfootbridge/execute.py b/steamfootbridge/execute.py index 9913b14..c2a278b 100644 --- a/steamfootbridge/execute.py +++ b/steamfootbridge/execute.py @@ -5,9 +5,11 @@ from . import config + def do(appid): - print("Executing appid {}".format(appid)) - with config.Configuration() as c: - # TODO: Should we explicitly start Steam if it isn't already running? - subprocess.Popen(["wine", c.get_wine_steam_windows_executable(), "-silent", "-applaunch", - str(appid)]) + print("Executing appid {}".format(appid)) + with config.Configuration() as c: + # TODO: Should we explicitly start Steam if it isn't already running? + subprocess.Popen([ + "wine", c.get_wine_steam_windows_executable(), "-silent", "-applaunch", str(appid) + ]) diff --git a/steamfootbridge/setup.py b/steamfootbridge/setup.py index ee6dff8..3b77d40 100644 --- a/steamfootbridge/setup.py +++ b/steamfootbridge/setup.py @@ -5,6 +5,7 @@ import steam + # TODO: Does capitalization mater? __root_userconfig_key__ = 'UserLocalConfigStore' __friends_userconfig_key__ = 'friends' @@ -15,35 +16,40 @@ # TODO: Option to disable setting friends autologin # TODO: Option to disable setting overlay disabled # TODO: Option to avoid touching the userconfig at all + + def do(): - with config.Configuration() as c: - path = c.get_wine_steam_userconfig_filename() - print("Reading {}".format(path)) + with config.Configuration() as c: + path = c.get_wine_steam_userconfig_filename() + print("Reading {}".format(path)) - with open(path, 'r') as f: - userconfig = steam.vdf.load(f) + with open(path, mode='r', encoding='utf-16') as f: + userconfig = steam.vdf.load(f) - _base_setup_userconfig(userconfig) - _set_disable_friends_auto_login(userconfig) - _set_disable_overlay(userconfig) + _base_setup_userconfig(userconfig) + _set_disable_friends_auto_login(userconfig) + _set_disable_overlay(userconfig) + + print("Writing updated {}".format(path)) + with open(path, mode='w', encoding='utf-16') as f: + f.write(steam.vdf.dumps(userconfig).decode('utf-16').lstrip('\n')) - print("Writing updated {}".format(path)) - with open(path, 'w') as f: - steam.vdf.dump(userconfig, f) def _base_setup_userconfig(userconfig): - if not __root_userconfig_key__ in userconfig: - userconfig[__root_userconfig_key__] = {} - root = userconfig[__root_userconfig_key__] + if __root_userconfig_key__ not in userconfig: + userconfig[__root_userconfig_key__] = {} + root = userconfig[__root_userconfig_key__] + + if __friends_userconfig_key__ not in root: + root[__friends_userconfig_key__] = {} - if not __friends_userconfig_key__ in root: - root[__friends_userconfig_key__] = {} + if __system_userconfig_key__ not in root: + root[__system_userconfig_key__] = {} - if not __system_userconfig_key__ in root: - root[__system_userconfig_key__] = {} def _set_disable_friends_auto_login(userconfig): - userconfig[__root_userconfig_key__][__friends_userconfig_key__][__autologin_friends_key__] = '0' + userconfig[__root_userconfig_key__][__friends_userconfig_key__][__autologin_friends_key__] = '0' + def _set_disable_overlay(userconfig): - userconfig[__root_userconfig_key__][__system_userconfig_key__][__enable_game_overlay_key__] = '0' + userconfig[__root_userconfig_key__][__system_userconfig_key__][__enable_game_overlay_key__] = '0'