Hello community, here is the log from the commit of package steam for openSUSE:Factory:NonFree checked in at 2020-07-01 14:24:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory:NonFree/steam (Old) and /work/SRC/openSUSE:Factory:NonFree/.steam.new.3060 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "steam" Wed Jul 1 14:24:50 2020 rev:24 rq:817400 version:1.0.0.64 Changes: -------- --- /work/SRC/openSUSE:Factory:NonFree/steam/steam.changes 2020-06-15 20:26:01.433441744 +0200 +++ /work/SRC/openSUSE:Factory:NonFree/.steam.new.3060/steam.changes 2020-07-01 14:24:51.846426890 +0200 @@ -1,0 +2,29 @@ +Wed Jun 17 13:50:16 UTC 2020 - Callum Farmer <[email protected]> + +- Update to version 1.0.0.63 + * Update steam-devices subproject up to 2020-06-05 + - Add HORIPAD for Nintendo Switch (thanks, @BrokenGale) + (Fixes: steam-for-linux#6944, steam-devices#7) + - Add ASTRO C40 controller (thanks, @exhumer2) + (Fixes: steam-devices#5) + - Add PowerA Nintendo Switch Controller (thanks, @blazingkin) + (Fixes: steam-devices#6) + - Add a workaround for PowerA Wireless Controller + (thanks, Andrey Smirnov) (Fixes: steam-devices#9; T21767) + * debian/steam-launcher.postinst: Notify udevd to reload its rules. + This means the steam-devices rules should take effect immediately, + instead of being deferred until after the next reboot. (T19535) + * bin_steam.sh: Don't overwrite steam.desktop if it's a symlink. + In a pre-configured distro like SteamOS, ~/Desktop/steam.desktop + might already be a symlink to /usr/share/applications/steam.desktop, + in which case overwriting it is pointless. (T21633) +- steam-devices supplements steam +- Update to version 1.0.0.64 + * steam.list: Download updates via https (T21740) + In older versions of apt (lower than 1.6) we need to install + apt-transport-https to use https repositories, so do that. + * steam.list: Switch the suite from precise to stable + (Fixes: steam-for-linux#4436) + * steam.list: Add commented-out apt sources for the beta launcher + +------------------------------------------------------------------- Old: ---- steam_1.0.0.62.tar.gz New: ---- steam_1.0.0.64.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ steam.spec ++++++ --- /var/tmp/diff_new_pack.9masJM/_old 2020-07-01 14:24:52.678429470 +0200 +++ /var/tmp/diff_new_pack.9masJM/_new 2020-07-01 14:24:52.678429470 +0200 @@ -17,7 +17,7 @@ Name: steam -Version: 1.0.0.62 +Version: 1.0.0.64 Release: 0 Summary: Installer for Valve's digital software distribution service # "Limited Installation License" @@ -32,7 +32,7 @@ # PATCH-FIX-OPENSUSE steam-path-fix.patch bnc#1025841 Patch1: steam-path-fix.patch BuildRequires: hicolor-icon-theme -BuildRequires: shared-mime-info +BuildRequires: pkgconfig(shared-mime-info) BuildRequires: update-desktop-files BuildRequires: fdupes BuildRequires: pkgconfig(udev) @@ -134,6 +134,7 @@ Obsoletes: steam-vr < %{version} Provides: steam-controller = %{version} Provides: steam-vr = %{version} +Supplements: steam = %{version} Requires: steam = %{version} %if 0%{?suse_version} >= 1330 Requires(pre): group(games) @@ -149,9 +150,7 @@ %prep -%setup -q -n steam-launcher -%patch0 -p1 -%patch1 -p1 +%autosetup -n steam-launcher -p1 %build @@ -161,7 +160,7 @@ # TODO: Patch it so it works with zypper or at least does not invoke apt-get. rm %{buildroot}%{_bindir}/steamdeps -rm %{buildroot}/usr/lib/steam/bin_steamdeps.py +rm %{buildroot}%{_prefix}/lib/steam/bin_steamdeps.py mkdir -p %{buildroot}%{_udevrulesdir} cp subprojects/steam-devices/60-steam-input.rules %{buildroot}%{_udevrulesdir}/60-steam-input.rules @@ -207,8 +206,8 @@ %dir %{_datadir}/appdata/ %{_datadir}/appdata/%{name}.appdata.xml %config %{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/%{name} -/usr/lib/steam/bin_steam.sh -/usr/lib/steam/steam.desktop +%{_prefix}/lib/steam/bin_steam.sh +%{_prefix}/lib/steam/steam.desktop %files devices %license subprojects/steam-devices/LICENSE ++++++ steam_1.0.0.62.tar.gz -> steam_1.0.0.64.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/bin_steam.sh new/steam-launcher/bin_steam.sh --- old/steam-launcher/bin_steam.sh 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/bin_steam.sh 2020-06-24 12:36:09.000000000 +0200 @@ -14,7 +14,7 @@ bootstrapscript="$(readlink -f "$STEAMSCRIPT")" bootstrapdir="$(dirname "$bootstrapscript")" -export STEAMSCRIPT_VERSION=1.0.0.61+deb1 +export STEAMSCRIPT_VERSION=1.0.0.64 # Set up domain for script localization export TEXTDOMAIN=steam @@ -118,18 +118,21 @@ DESKTOP_DIR="${XDG_DESKTOP_DIR:-$HOME/Desktop}" if [ -d "$DESKTOP_DIR" ] && [ "x$bootstrapdir" = "x/usr/lib/$STEAMPACKAGE" ]; then - cp "$bootstrapdir/$STEAMPACKAGE.desktop" "$DESKTOP_DIR" - # Older .desktop implementations used the execute bits as - # a marker for a .desktop being safe to treat as a shortcut - chmod a+x "$DESKTOP_DIR/$STEAMPACKAGE.desktop" - if command -v gio >/dev/null; then - # Making it executable is not enough in recent - # (Ubuntu 20.04) versions of - # https://gitlab.gnome.org/World/ShellExtensions/desktop-icons - gio set --type=string "$DESKTOP_DIR/$STEAMPACKAGE.desktop" metadata::trusted true || : - # Generate an inotify event so the desktop - # implementation reloads it - touch "$DESKTOP_DIR/$STEAMPACKAGE.desktop" + # There might be a symlink in place already, in such case we do nothing + if [ ! -L "$DESKTOP_DIR/$STEAMPACKAGE.desktop" ]; then + cp "$bootstrapdir/$STEAMPACKAGE.desktop" "$DESKTOP_DIR" + # Older .desktop implementations used the execute bits as + # a marker for a .desktop being safe to treat as a shortcut + chmod a+x "$DESKTOP_DIR/$STEAMPACKAGE.desktop" + if command -v gio >/dev/null; then + # Making it executable is not enough in recent + # (Ubuntu 20.04) versions of + # https://gitlab.gnome.org/World/ShellExtensions/desktop-icons + gio set --type=string "$DESKTOP_DIR/$STEAMPACKAGE.desktop" metadata::trusted true || : + # Generate an inotify event so the desktop + # implementation reloads it + touch "$DESKTOP_DIR/$STEAMPACKAGE.desktop" + fi fi fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/bin_steamdeps.py new/steam-launcher/bin_steamdeps.py --- old/steam-launcher/bin_steamdeps.py 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/bin_steamdeps.py 2020-06-24 12:36:09.000000000 +0200 @@ -1,10 +1,10 @@ #!/usr/bin/env python3 """ - This script handles installing system dependencies for games using the - Steam runtime. It is intended to be customized by other distributions - to "do the right thing" + This script handles installing system dependencies for games using the + Steam runtime. It is intended to be customized by other distributions + to "do the right thing" - Usage: steamdeps dependencies.txt + Usage: steamdeps dependencies.txt """ import os @@ -14,232 +14,256 @@ import sys import tempfile +try: + import apt +except ImportError: + sys.stderr.write("Couldn't import apt, please install python3-apt or " + "update steamdeps for your distribution.\n") + sys.exit(3) + # This is the set of supported Steam runtime environments -SUPPORTED_STEAM_RUNTIME = [ '1' ] +SUPPORTED_STEAM_RUNTIME = ['1'] # This is the set of supported dependency formats -SUPPORTED_STEAM_DEPENDENCY_VERSION = [ '1' ] +SUPPORTED_STEAM_DEPENDENCY_VERSION = ['1'] -### +_arch = None + + +# # Get the current package architecture # This may be different than the actual architecture for the case of i386 # chroot environments on amd64 hosts. -_arch = None -def getArch(): - """ - Get the current architecture - """ - global _arch - - if ( _arch is None ): - _arch = subprocess.check_output(['dpkg', '--print-architecture']).decode("utf-8").strip() - return _arch +# +def get_arch(): + """ + Get the current architecture + """ + global _arch + + if _arch is None: + _arch = subprocess.check_output( + ['dpkg', '--print-architecture']).decode("utf-8").strip() + return _arch ### -def getFullPackageName( name ): - """ - Get the full name of a package, qualified by architecture - """ - if ( name.find(":") < 0 ): - return name + ":" + getArch() - else: - return name +def get_full_package_name(name): + """ + Get the full name of a package, qualified by architecture + """ + if name.find(":") < 0: + return name + ":" + get_arch() + else: + return name # -# Check to see if another package Provides this package # N.B. Version checks are not supported on virtual packages # -def isProvided(pkgname): - try: - process = subprocess.Popen( ['apt-cache', 'showpkg', pkgname], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - pattern = re.compile( r'^Reverse Provides\:') - providers = {} - for line in process.stdout: - if re.match(pattern,line): - for provider in process.stdout: - (name, version) = provider.split() - providers[name] = version - for provider in providers.keys(): - if hasPackage(provider): - return True - return False - except: - return False - return False +def is_provided(pkgname): + """ + Check to see if another package Provides this package + """ + cache = apt.Cache() + pkgs = cache.get_providing_packages(pkgname) + for pkg in pkgs: + if pkg.is_installed: + return True + return False ### class Package: - """ - Package definition class - """ - def __init__(self, name, versionConditions): - self.name = name - self.versionConditions = versionConditions - self.installed = None - - def setInstalled(self, version): - self.installed = version - - - def isAvailable(self): - if ( self.installed is None ): - # check to see if another package is providing this virtual package - return isProvided(self.name) - - for (op, version) in self.versionConditions: - if ( subprocess.call( ['dpkg', '--compare-versions', self.installed, op, version] ) != 0 ): - return False - - return True - - def __str__(self): - text = self.name - for (op, version) in self.versionConditions: - text += " (%s %s)" % (op, version) - return text - - -### -def hasPackage( package ): - process = subprocess.Popen( ['dpkg', '-l', package], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) - installed_pattern = re.compile( r"^\Si\s+([^\s]+)\s+([^\s]+)" ) - for line in process.stdout: - line = line.decode( "utf-8" ).strip() - match = re.match( installed_pattern, line ) - if ( match is None ): - continue - - return True - return False + """ + Package definition class + """ + + def __init__(self, name, version_conditions): + self.name = name + self.version_conditions = version_conditions + self.installed = None + + def set_installed(self, version): + self.installed = version + + def is_available(self): + if self.installed is None: + # check to see if another package is providing this virtual package + return is_provided(self.name) + + for (op, version) in self.version_conditions: + if subprocess.call(['dpkg', '--compare-versions', self.installed, + op, version]) != 0: + return False + + return True + + def __str__(self): + text = self.name + for (op, version) in self.version_conditions: + text += " (%s %s)" % (op, version) + return text def is_glvnd(): - try: - with subprocess.Popen( - ['apt-cache', 'pkgnames', 'libgl1'], - stdout=subprocess.PIPE, - ) as process: - for line in process.stdout: - line = line.decode('utf-8').strip() - - if line == 'libgl1': - return True - return False - except Exception: - return False - - -def remapPackage( name ): - if name in ( - 'python-apt', - ): - # Steam claims it needs python-apt, but it doesn't really - return None - - # Ubuntu 12.04.2, 12.04.3, and 12.04.4 introduce new X stacks which require - # different sets of incompatible glx packages depending on which X - # is currently installed. - - for lts in ('quantal', 'raring', 'saucy', 'trusty'): - if hasPackage('xserver-xorg-core-lts-' + lts): - if name in ( - 'libgl1-mesa-glx', - 'libgl1-mesa-dri', - ): - return name + '-lts-' + lts - - if name == 'libgl1-mesa-glx': - if is_glvnd(): - return 'libgl1' + try: + with subprocess.Popen(['apt-cache', 'pkgnames', 'libgl1'], + stdout=subprocess.PIPE,) as process: + for line in process.stdout: + line = line.decode('utf-8').strip() + + if line == 'libgl1': + return True + return False + except (OSError, FileNotFoundError): + return False + + +def remap_package(name): + if name in ( + 'python-apt', + ): + # Steam claims it needs python-apt, but it doesn't really + return None + + # Ubuntu 12.04.2, 12.04.3, and 12.04.4 introduce new X stacks which require + # different sets of incompatible glx packages depending on which X + # is currently installed. + + cache = apt.Cache() + for lts in ('quantal', 'raring', 'saucy', 'trusty', 'xenial'): + xserver = 'xserver-xorg-core-lts-' + lts + if xserver in cache and cache[xserver].is_installed: + if name in ( + 'libgl1-mesa-glx', + 'libgl1-mesa-dri', + ): + return name + '-lts-' + lts + + if name == 'libgl1-mesa-glx': + if is_glvnd(): + return 'libgl1' - return name + return name ### -def createPackage( description ): - """ - Create a package object based on a description. - This can return None if the package isn't meaningful on this platform. - """ - # Look for architecture conditions, e.g. foo [i386] - match = re.match( r"(.*) \[([^\]]+)\]", description ) - if match is not None: - description = match.group(1).strip() - condition = match.group(2) - if ( condition[0] == '!' ): - if ( getArch() == condition[1:] ): - return None - else: - if ( getArch() != condition ): - return None - - # Look for version requirements, e.g. foo (>= 1.0) - versionConditions = [] - while True: - match = re.search( r"\s*\(\s*([<>=]+)\s*([\w\-\.:]+)\s*\)\s*", description ) - if ( match is None ): - break - - versionConditions.append( ( match.group(1), match.group(2) ) ) - description = description[:match.start()] + description[match.end():] - - description = description.strip() - - if ':' in description: - name, multiarch = description.rsplit(':', 1) - else: - name = description - multiarch = None - - name = remapPackage(name) - - if name is None: - return None - elif multiarch is not None: - description = name + ':' + multiarch +def create_package(description): + """ + Create a package object based on a description. + This can return None if the package isn't meaningful on this platform. + """ + # Look for architecture conditions, e.g. foo [i386] + match = re.match(r"(.*) \[([^\]]+)\]", description) + if match is not None: + description = match.group(1).strip() + condition = match.group(2) + if condition[0] == '!': + if get_arch() == condition[1:]: + return None + else: + if get_arch() != condition: + return None + + # Look for version requirements, e.g. foo (>= 1.0) + version_conditions = [] + while True: + match = re.search(r"\s*\(\s*([<>=]+)\s*([\w\-.:]+)\s*\)\s*", + description) + if match is None: + break + + version_conditions.append((match.group(1), match.group(2))) + description = description[:match.start()] + description[match.end():] + + description = description.strip() + + if ':' in description: + name, multiarch = description.rsplit(':', 1) + else: + name = description + multiarch = None + + name = remap_package(name) + + if name is None: + return None + elif multiarch is not None: + description = name + ':' + multiarch - return Package( description, versionConditions ) - + return Package(description, version_conditions) ### -def getTerminalCommandLine( title ): - """ - Function to find a useful terminal like xterm or compatible - """ - if ( "DISPLAY" in os.environ ): - programs = [ - ( "gnome-terminal", ["gnome-terminal", "--disable-factory", "-t", title, "-e"] ), - ( "konsole", ["konsole", "--nofork", "-p", "tabtitle="+title, "-e"] ), - ( "xterm", ["xterm", "-bg", "#383635", "-fg", "#d1cfcd", "-T", title, "-e"] ), - ( "x-terminal-emulator", ["x-terminal-emulator", "-T", title, "-e"] ), - ] - for (program, commandLine) in programs: - if ( subprocess.call( ['which', program], stdout=subprocess.PIPE ) == 0 ): - return commandLine +def get_terminal_command_line(title): + """ + Function to find a useful terminal like xterm or compatible + """ + if "DISPLAY" in os.environ: + gnome_wait_option = None + try: + # Use the new '--wait' option if available + terminal_out = subprocess.check_output( + ["gnome-terminal", "--help-terminal-options"]).decode("utf-8") + if "--wait" in terminal_out: + gnome_wait_option = "--wait" + else: + # If the old '--disable-factory' is supported we use it + terminal_out = subprocess.check_output( + ["gnome-terminal", "--help"]).decode("utf-8") + if "--disable-factory" in terminal_out: + gnome_wait_option = "--disable-factory" + + if gnome_wait_option is not None: + # If 'gnome-terminal' with the right options is available, we + # just use it + return ["gnome-terminal", gnome_wait_option, "-t", title, "--"] + except FileNotFoundError: + pass + + programs = [ + ("konsole", + ["konsole", "--nofork", "-p", "tabtitle=" + title, "-e"]), + ("xterm", + ["xterm", "-bg", "#383635", "-fg", "#d1cfcd", "-T", title, "-e"]), + ("x-terminal-emulator", + ["x-terminal-emulator", "-T", title, "-e"]), + # If we reach this point either 'gnome-terminal' is not available + # or the current version is too old for the new '--wait' option. + # Anyway we can't know for sure if '--disable-factory' option + # is supported until we try it because, for example, + # on Ubuntu 16.04 '--disable-factory' is available but it doesn't + # show up with '--help'. Leave this 'gnome-terminal' test as the + # last resort because it's highly likely to fail. + ("gnome-terminal", + ["gnome-terminal", "--disable-factory", "-t", title, "--"]), + ] + for (program, commandLine) in programs: + if subprocess.call(['which', program], + stdout=subprocess.PIPE) == 0: + return commandLine - # Fallback if no GUI terminal program is available - return ['/bin/sh'] + # Fallback if no GUI terminal program is available + return ['/bin/sh'] ### -def updatePackages( packages ): - """ - Function to install or update package dependencies - Ideally we would call some sort of system UI that users were familiar with to do this, but nothing that exists yet does what we need. - """ - - packageList = " ".join( [ package.name for package in packages ] ) - - # Create a temporary file to hold the installation completion status - (fd, statusFile) = tempfile.mkstemp() - os.close( fd ) - - # Create a script to run, in a secure way - (fd, scriptFile) = tempfile.mkstemp() - script = """#!/bin/sh +def update_packages(packages): + """ + Function to install or update package dependencies + Ideally we would call some sort of system UI that users were familiar with + to do this, but nothing that exists yet does what we need. + """ + + package_list = " ".join([package.name for package in packages]) + + # Create a temporary file to hold the installation completion status + (fd, status_file) = tempfile.mkstemp() + os.close(fd) + + # Create a script to run, in a secure way + (fd, script_file) = tempfile.mkstemp() + script = """#!/bin/sh check_sudo() { # If your host file is misconfigured in certain circumstances this @@ -251,7 +275,8 @@ cat <<__EOF__ sudo timed out, your hostname may be missing from /etc/hosts. -See https://support.steampowered.com/kb_article.php?ref=7493-ADXN-9620 for more details. +See https://support.steampowered.com/kb_article.php?ref=7493-ADXN-9620 +for more details. __EOF__ return 1 else @@ -260,13 +285,14 @@ } cat <<__EOF__ -Steam needs to install these additional packages: - %s +Steam needs to install these additional packages: + %s __EOF__ check_sudo # Check to make sure 64-bit systems can get 32-bit packages -if [ "$(dpkg --print-architecture)" = "amd64" ] && ! dpkg --print-foreign-architectures | grep i386 >/dev/null; then +if [ "$(dpkg --print-architecture)" = "amd64" ] && \ + ! dpkg --print-foreign-architectures | grep i386 >/dev/null; then sudo dpkg --add-architecture i386 fi @@ -279,178 +305,190 @@ echo $? >%s echo -n "Press return to continue: " read line -""" % ( ", ".join( [ package.name for package in packages ] ), packageList, statusFile ) - os.write( fd, script.encode("utf-8") ) - os.close( fd ) - os.chmod( scriptFile, (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) ) - - try: - subprocess.call( getTerminalCommandLine( "Package Install" ) + [scriptFile] ) - except KeyboardInterrupt: - pass - os.unlink( scriptFile ) - - # Read the status out of the file, since if we ran the script in a - # terminal the process status will be whether the terminal started - try: - status = int( open( statusFile ).read() ) - except ValueError: - # The status wasn't written to the file - status = 255 +""" % (", ".join([package.name for package in packages]), package_list, + status_file) + os.write(fd, script.encode("utf-8")) + os.close(fd) + os.chmod(script_file, (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)) + + try: + subprocess.call( + get_terminal_command_line("Package Install") + [script_file]) + except KeyboardInterrupt: + pass + os.unlink(script_file) + + # Read the status out of the file, since if we ran the script in a + # terminal the process status will be whether the terminal started + try: + status = int(open(status_file).read()) + except ValueError: + # The status wasn't written to the file + status = 255 - os.unlink( statusFile ) + os.unlink(status_file) - return status + return status ### -def checkConfig( config ): - if ( "STEAM_RUNTIME" not in config ): - sys.stderr.write( "Missing STEAM_RUNTIME definition in %s\n" % sys.argv[1] ) - return False - - if ( config["STEAM_RUNTIME"] not in SUPPORTED_STEAM_RUNTIME ): - sys.stderr.write( "Unsupported Steam runtime: %s\n" % config["STEAM_RUNTIME"] ) - return False - - if ( "STEAM_DEPENDENCY_VERSION" not in config ): - sys.stderr.write( "Missing STEAM_DEPENDENCY_VERSION definition in %s\n" % sys.argv[1] ) - return False - - if ( config["STEAM_DEPENDENCY_VERSION"] not in SUPPORTED_STEAM_DEPENDENCY_VERSION ): - sys.stderr.write( "Unsupported dependency version: %s\n" % config["STEAM_DEPENDENCY_VERSION"] ) - return False - - # Make sure we can use dpkg on this system. - try: - subprocess.call( ['dpkg', '--version'], stdout=subprocess.PIPE ) - except: - sys.stderr.write( "Couldn't find dpkg, please update steamdeps for your distribution.\n" ) - return False +def check_config(config): + if "STEAM_RUNTIME" not in config: + sys.stderr.write( + "Missing STEAM_RUNTIME definition in %s\n" % sys.argv[1]) + return False + + if config["STEAM_RUNTIME"] not in SUPPORTED_STEAM_RUNTIME: + sys.stderr.write( + "Unsupported Steam runtime: %s\n" % config["STEAM_RUNTIME"]) + return False + + if "STEAM_DEPENDENCY_VERSION" not in config: + sys.stderr.write( + "Missing STEAM_DEPENDENCY_VERSION definition in %s\n" % sys.argv[ + 1]) + return False + + if config["STEAM_DEPENDENCY_VERSION"]\ + not in SUPPORTED_STEAM_DEPENDENCY_VERSION: + sys.stderr.write("Unsupported dependency version: %s\n" % config[ + "STEAM_DEPENDENCY_VERSION"]) + return False + + # Make sure we can use dpkg on this system. + try: + subprocess.call(['dpkg', '--version'], stdout=subprocess.PIPE) + except FileNotFoundError: + sys.stderr.write("Couldn't find dpkg, please update steamdeps for " + "your distribution.\n") + return False - return True + return True ### def main(): - config = {} + config = {} - # Check the command line arguments - if ( len(sys.argv) < 2 ): - sys.stderr.write( "Usage: %s dependencies.txt\n" % sys.argv[0] ) - return 1 - - # Make sure we can open the file - try: - fp = open(sys.argv[1]) - except Exception as e: - sys.stderr.write( "Couldn't open file: %s\n" % (e) ) - return 2 - - # Look for configuration variables - config_pattern = re.compile( r"(\w+)\s*=\s*(\w+)" ) - for line in fp: - line = line.strip() - if ( line == "" or line[0] == '#' ): - continue - - match = re.match(config_pattern, line) - if ( match is not None ): - config[match.group(1)] = match.group(2) - - # Check to make sure we have a valid config - if ( not checkConfig( config ) ): - return 3 - - # Seek back to the beginning of the file - fp.seek(0) - - # Load the package dependency information - packages = {} - dependencies = [] - lineNumber = 0 - for line in fp: - ++lineNumber - line = line.strip() - if ( line == "" or line[0] == '#' ): - continue - - match = re.match( config_pattern, line ) - if ( match is not None ): - continue - - row = [] - for section in line.split( "|" ): - package = createPackage( section ) - if ( package is None ): - continue - - packages[ package.name ] = package - row.append( package ) - - dependencies.append( row ) - - if getArch() == 'amd64': - for synthetic in ( - 'libc6', - 'libgl1-mesa-dri', - 'libgl1-mesa-glx', - ): - package = createPackage(synthetic + ':amd64') - if package is not None: - packages[package.name] = package - dependencies.append([package]) - - # Print package dependency information for debug - """ - for row in dependencies: - print " | ".join( [ str(package) for package in row ] ) - """ - - # Get the installed package versions - # Make sure COLUMNS isn't set, or dpkg will truncate its output - if ( "COLUMNS" in os.environ ): - del os.environ[ "COLUMNS" ] - - process = subprocess.Popen( ['dpkg', '-l'] + list( packages.keys() ), stdout=subprocess.PIPE, stderr=subprocess.PIPE ) - installed_pattern = re.compile( r"^\Si\s+([^\s]+)\s+([^\s]+)" ) - for line in process.stdout: - line = line.decode( "utf-8" ).strip() - match = re.match( installed_pattern, line ) - if ( match is None ): - continue - - name = match.group(1) - if ( name not in packages ): - name = getFullPackageName( name ) - packages[ name ].setInstalled( match.group(2) ) - - # See which ones need to be installed - needed = [] - for row in dependencies: - if ( len(row) == 0 ): - continue - - satisfied = False - for dep in row: - if ( dep.isAvailable() ): - satisfied = True - break - if ( not satisfied ): - needed.append( row[0] ) - - # If we have anything to install, do it! - if ( len(needed) > 0 ): - for package in needed: - if package.installed: - print("Package %s is installed with version '%s' but doesn't match requirements: %s" % (package.name, package.installed, package), file=sys.stderr) - else: - print("Package %s needs to be installed" % package.name, file=sys.stderr) - - return updatePackages( needed ) - else: - return 0 + # Check the command line arguments + if len(sys.argv) < 2: + sys.stderr.write("Usage: %s dependencies.txt\n" % sys.argv[0]) + return 1 + + # Make sure we can open the file + try: + fp = open(sys.argv[1]) + except Exception as e: + sys.stderr.write("Couldn't open file: %s\n" % e) + return 2 + + # Look for configuration variables + config_pattern = re.compile(r"(\w+)\s*=\s*(\w+)") + for line in fp: + line = line.strip() + if line == "" or line[0] == '#': + continue + + match = re.match(config_pattern, line) + if match is not None: + config[match.group(1)] = match.group(2) + + # Check to make sure we have a valid config + if not check_config(config): + return 3 + + # Seek back to the beginning of the file + fp.seek(0) + + # Load the package dependency information + packages = {} + dependencies = [] + for line in fp: + line = line.strip() + if line == "" or line[0] == '#': + continue + + match = re.match(config_pattern, line) + if match is not None: + continue + + row = [] + for section in line.split("|"): + package = create_package(section) + if package is None: + continue + + packages[package.name] = package + row.append(package) + + dependencies.append(row) + + if get_arch() == 'amd64': + for synthetic in ( + 'libc6', + 'libgl1-mesa-dri', + 'libgl1-mesa-glx', + ): + package = create_package(synthetic + ':amd64') + if package is not None: + packages[package.name] = package + dependencies.append([package]) + + # Print package dependency information for debug + """ + for row in dependencies: + print " | ".join( [ str(package) for package in row ] ) + """ + + # Get the installed package versions + # Make sure COLUMNS isn't set, or dpkg will truncate its output + if "COLUMNS" in os.environ: + del os.environ["COLUMNS"] + + process = subprocess.Popen(['dpkg', '-l'] + list(packages.keys()), + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + installed_pattern = re.compile(r"^\Si\s+([^\s]+)\s+([^\s]+)") + for line in process.stdout: + line = line.decode("utf-8").strip() + match = re.match(installed_pattern, line) + if match is None: + continue + + name = match.group(1) + if name not in packages: + name = get_full_package_name(name) + packages[name].set_installed(match.group(2)) + + # See which ones need to be installed + needed = [] + for row in dependencies: + if len(row) == 0: + continue + + satisfied = False + for dep in row: + if dep.is_available(): + satisfied = True + break + if not satisfied: + needed.append(row[0]) + + # If we have anything to install, do it! + if len(needed) > 0: + for package in needed: + if package.installed: + print("Package %s is installed with version '%s' but doesn't " + "match requirements: %s" % ( + package.name, package.installed, package), + file=sys.stderr) + else: + print("Package %s needs to be installed" % package.name, + file=sys.stderr) + + return update_packages(needed) + else: + return 0 if __name__ == "__main__": - sys.exit(main()) + sys.exit(main()) Binary files old/steam-launcher/bootstraplinux_ubuntu12_32.tar.xz and new/steam-launcher/bootstraplinux_ubuntu12_32.tar.xz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/client-versions.json new/steam-launcher/client-versions.json --- old/steam-launcher/client-versions.json 2020-03-19 18:14:14.000000000 +0100 +++ new/steam-launcher/client-versions.json 2020-06-24 12:36:49.000000000 +0200 @@ -1,4 +1,4 @@ { - "client_version": "1581460722", - "runtime_version": "0.20200204.0" + "client_version": "1591251555", + "runtime_version": "0.20200505.0" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/debian/changelog new/steam-launcher/debian/changelog --- old/steam-launcher/debian/changelog 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/debian/changelog 2020-06-24 12:36:09.000000000 +0200 @@ -1,3 +1,69 @@ +steam (1:1.0.0.64) beta; urgency=medium + + [ Simon McVittie ] + * steamdeps: Recognise xenial as a LTS HWE stack. + Ubuntu 14.04.6 LTS comes with a backported Ubuntu 16.04.x graphics stack, + so we need to install libgl1-mesa-glx-lts-xenial and other xenial-derived + packages instead of the original Ubuntu 14.04.0 versions. (T21844) + * Remove Recommends: jockey-common. + According to steam-for-linux#6634, this was the "Additional Drivers" + module in older Ubuntu, which is no longer present in any supported + Ubuntu release. Thanks to @BryanQuigley + + [ Ludovico de Nittis ] + * steam.list: Download updates via https (T21740) + In older versions of apt (lower than 1.6) we need to install + apt-transport-https to use https repositories, so do that. + * steam.list: Switch the suite from precise to stable + (Fixes: steam-for-linux#4436) + * steam.list: Add commented-out apt sources for the beta launcher + * bin_steamdeps: use python-apt for "is_provided" check. + `apt-cache showpkg` output was intended to be human readable. + In the apt version shipped with Ubuntu 20.04 they added additional + information to the "Reverse Provides" field, and that could break our + parsing. + Instead, using python-apt, is safer and we will be able to avoid these + kind of problems in the future. + (T21880) + * bin_steamdeps: use --wait option for gnome-terminal if it is available. + The --disable-factory option is no longer available upstream and in + Debian, although Ubuntu patches it back in. (T22095) + * bin_steamdeps: remove deprecated '-e' option in gnome-terminal + + -- Simon McVittie <[email protected]> Wed, 24 Jun 2020 11:21:03 +0100 + +steam (1:1.0.0.63) beta; urgency=medium + + [ Ludovico de Nittis ] + * debian/steam-launcher.postinst: Notify udevd to reload its rules. + This means the steam-devices rules should take effect immediately, + instead of being deferred until after the next reboot. (T19535) + * bin_steamdeps.py: Remove unused, misleading lineNumber variable + * bin_steamdeps.py: Conform to PEP-8 + + [ Arnaud Rebillout ] + * bin_steam.sh: Don't overwrite steam.desktop if it's a symlink. + In a pre-configured distro like SteamOS, ~/Desktop/steam.desktop + might already be a symlink to /usr/share/applications/steam.desktop, + in which case overwriting it is pointless. (T21633) + + [ Simon McVittie ] + * Update steam-devices subproject up to 2020-06-05 + - Add HORIPAD for Nintendo Switch (thanks, @BrokenGale) + (Fixes: steam-for-linux#6944, steam-devices#7) + - Add ASTRO C40 controller (thanks, @exhumer2) + (Fixes: steam-devices#5) + - Add PowerA Nintendo Switch Controller (thanks, @blazingkin) + (Fixes: steam-devices#6) + - Add a workaround for PowerA Wireless Controller + (thanks, Andrey Smirnov) (Fixes: steam-devices#9; T21767) + * Update python-vdf subproject to version 3.3 + * Bootstrap using updated Steam client: + - Client timestamp 1591251555 (2020-06-04) + - Steam Runtime version 0.20200505.0 + + -- Simon McVittie <[email protected]> Tue, 09 Jun 2020 11:32:58 +0100 + steam (1:1.0.0.62) beta; urgency=medium * build: Adapt for newer Steam Runtime builds. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/debian/control new/steam-launcher/debian/control --- old/steam-launcher/debian/control 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/debian/control 2020-06-24 12:36:09.000000000 +0200 @@ -16,18 +16,18 @@ Breaks: steam64 Depends: ${misc:Depends}, ${python3:Depends}, - apt, + apt (>= 1.6) | apt-transport-https, ca-certificates, curl, file, libc6 (>= 2.15), libnss3 (>= 2:3.26), python3, + python3-apt, xterm | gnome-terminal | konsole | x-terminal-emulator, xz-utils, zenity -Recommends: jockey-common, - sudo, +Recommends: sudo, xdg-utils | steamos-base-files, Description: Launcher for the Steam software distribution service Steam is a software distribution service with an online store, automated diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/debian/steam-launcher.postinst new/steam-launcher/debian/steam-launcher.postinst --- old/steam-launcher/debian/steam-launcher.postinst 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/debian/steam-launcher.postinst 2020-06-24 12:36:09.000000000 +0200 @@ -3,6 +3,14 @@ # # see: dh_installdeb(1) +# Trigger an update to let our new udev rules be immediately effective without +# requiring a system reboot. +# Usually `--reload-rules` is unnecessary, but it doesn't do any harm. +udevadm control --reload-rules || true +udevadm trigger --action=change --sysname-match=uinput || true +udevadm trigger --action=change --subsystem-match=usb --attr-match=idVendor=28de || true +udevadm trigger --action=change --subsystem-match=hidraw || true + # popup update notification for the user to run Steam and complete the per-user install PACKAGE=steam UPDATENOTIFIERDIR=/var/lib/update-notifier/user.d diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/steam.list new/steam-launcher/steam.list --- old/steam-launcher/steam.list 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/steam.list 2020-06-24 12:36:09.000000000 +0200 @@ -1,2 +1,6 @@ -deb [arch=amd64,i386] http://repo.steampowered.com/steam/ precise steam -deb-src [arch=amd64,i386] http://repo.steampowered.com/steam/ precise steam +deb [arch=amd64,i386] https://repo.steampowered.com/steam/ stable steam +deb-src [arch=amd64,i386] https://repo.steampowered.com/steam/ stable steam + +# Uncomment these lines to try the beta version of the Steam launcher +#deb [arch=amd64,i386] https://repo.steampowered.com/steam/ beta steam +#deb-src [arch=amd64,i386] https://repo.steampowered.com/steam/ beta steam diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/subprojects/python-vdf/.scrutinizer.yml new/steam-launcher/subprojects/python-vdf/.scrutinizer.yml --- old/steam-launcher/subprojects/python-vdf/.scrutinizer.yml 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/subprojects/python-vdf/.scrutinizer.yml 2020-06-24 12:36:09.000000000 +0200 @@ -1,11 +1,17 @@ -checks: - python: - code_rating: true - duplicate_code: true filter: excluded_paths: - 'tests/*' - 'vdf2json/*' tools: external_code_coverage: - runs: 9 + timeout: 200 + runs: 8 + +build: + nodes: + analysis: + tests: + override: + - command: py-scrutinizer-run + idle_timeout: 300 + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/subprojects/python-vdf/.travis.yml new/steam-launcher/subprojects/python-vdf/.travis.yml --- old/steam-launcher/subprojects/python-vdf/.travis.yml 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/subprojects/python-vdf/.travis.yml 2020-06-24 12:36:09.000000000 +0200 @@ -1,23 +1,24 @@ language: python -python: - - "2.7" - - "3.4" - - "3.5" - - "3.6" - - "nightly" - - "pypy" - - "pypy3" -matrix: +os: linux + +jobs: include: + - python: 2.7 + - python: 3.4 + - python: 3.5 + - python: 3.6 - python: 3.7 - dist: xenial - sudo: true + - python: 3.8 + - python: "pypy" + - python: "pypy3" install: - - make init - - pip install coveralls==1.1 + - pip install -r requirements.txt + - pip install coveralls - pip install scrutinizer-ocular +before_script: + - rm -f .coverage vdf/*.pyc tests/*.pyc script: - make test + - PYTHONHASHSEED=0 python -m pytest --cov=vdf tests after_success: - coveralls - ocular --data-file ".coverage" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/subprojects/python-vdf/requirements.txt new/steam-launcher/subprojects/python-vdf/requirements.txt --- old/steam-launcher/subprojects/python-vdf/requirements.txt 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/subprojects/python-vdf/requirements.txt 2020-06-24 12:36:09.000000000 +0200 @@ -1,3 +1,3 @@ mock -pytest==3.3.0 -pytest-cov==2.6.0 +pytest +pytest-cov diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/subprojects/python-vdf/tests/test_binary_vdf.py new/steam-launcher/subprojects/python-vdf/tests/test_binary_vdf.py --- old/steam-launcher/subprojects/python-vdf/tests/test_binary_vdf.py 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/subprojects/python-vdf/tests/test_binary_vdf.py 2020-06-24 12:36:09.000000000 +0200 @@ -2,6 +2,7 @@ import unittest import vdf +from io import BytesIO from collections import OrderedDict u = str if sys.version_info >= (3,) else unicode @@ -48,16 +49,34 @@ def test_loads_empty(self): self.assertEqual(vdf.binary_loads(b''), {}) + self.assertEqual(vdf.binary_load(BytesIO(b'')), {}) def test_dumps_empty(self): self.assertEqual(vdf.binary_dumps({}), b'') + buf = BytesIO() + vdf.binary_dump({}, buf) + + self.assertEqual(buf.getvalue(), b'') + def test_dumps_unicode(self): self.assertEqual(vdf.binary_dumps({u('a'): u('b')}), b'\x01a\x00b\x00\x08') def test_dumps_unicode_alternative(self): self.assertEqual(vdf.binary_dumps({u('a'): u('b')}, alt_format=True), b'\x01a\x00b\x00\x0b') + def test_dump_params_invalid(self): + with self.assertRaises(TypeError): + vdf.binary_dump([], BytesIO()) + with self.assertRaises(TypeError): + vdf.binary_dump({}, b'aaaa') + + def test_dumps_params_invalid(self): + with self.assertRaises(TypeError): + vdf.binary_dumps([]) + with self.assertRaises(TypeError): + vdf.binary_dumps(b'aaaa') + def test_dumps_key_invalid_type(self): with self.assertRaises(TypeError): vdf.binary_dumps({1:1}) @@ -74,6 +93,24 @@ with self.assertRaises(SyntaxError): vdf.binary_loads(b'\x00a\x00\x00b\x00\x08\x08', alt_format=True) + def test_load_params_invalid(self): + with self.assertRaises(TypeError): + vdf.binary_load(b'aaaa') + with self.assertRaises(TypeError): + vdf.binary_load(1234) + with self.assertRaises(TypeError): + vdf.binary_load(BytesIO(b'aaaa'), b'bbbb') + + def test_loads_params_invalid(self): + with self.assertRaises(TypeError): + vdf.binary_loads([]) + with self.assertRaises(TypeError): + vdf.binary_loads(11111) + with self.assertRaises(TypeError): + vdf.binary_loads(BytesIO()) + with self.assertRaises(TypeError): + vdf.binary_load(b'', b'bbbb') + def test_loads_unbalanced_nesting(self): with self.assertRaises(SyntaxError): vdf.binary_loads(b'\x00a\x00\x00b\x00\x08') @@ -108,6 +145,27 @@ self.assertEqual(vdf.binary_loads(test, merge_duplicate_keys=False), result) + def test_raise_on_remaining(self): + # default binary_loads is to raise + with self.assertRaises(SyntaxError): + vdf.binary_loads(b'\x01key\x00value\x00\x08' + b'aaaa') + + # do not raise + self.assertEqual(vdf.binary_loads(b'\x01key\x00value\x00\x08' + b'aaaa', raise_on_remaining=False), {'key': 'value'}) + + def test_raise_on_remaining_with_file(self): + buf = BytesIO(b'\x01key\x00value\x00\x08' + b'aaaa') + + # binary_load doesn't raise by default + self.assertEqual(vdf.binary_load(buf), {'key': 'value'}) + self.assertEqual(buf.read(), b'aaaa') + + # raise when extra data remains + buf.seek(0) + with self.assertRaises(SyntaxError): + vdf.binary_load(buf, raise_on_remaining=True) + self.assertEqual(buf.read(), b'aaaa') + def test_vbkv_loads_empty(self): with self.assertRaises(ValueError): vdf.vbkv_loads(b'') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/subprojects/python-vdf/tests/test_vdf.py new/steam-launcher/subprojects/python-vdf/tests/test_vdf.py --- old/steam-launcher/subprojects/python-vdf/tests/test_vdf.py 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/subprojects/python-vdf/tests/test_vdf.py 2020-06-24 12:36:09.000000000 +0200 @@ -84,6 +84,17 @@ def tearDown(self): self.f.close() + def test_dump_params_invalid(self): + # pretty/escaped only accept bool + with self.assertRaises(TypeError): + vdf.dump({'a': 1}, StringIO(), pretty=1) + with self.assertRaises(TypeError): + vdf.dumps({'a': 1}, pretty=1) + with self.assertRaises(TypeError): + vdf.dump({'a': 1}, StringIO(), escaped=1) + with self.assertRaises(TypeError): + vdf.dumps({'a': 1}, escaped=1) + def test_routine_dumps_asserts(self): for x in [5, 5.5, 1.0j, True, None, (), {}, lambda: 0, sys.stdin, self.f]: for y in [5, 5.5, 1.0j, None, [], (), {}, lambda: 0, sys.stdin, self.f]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/subprojects/python-vdf/vdf/__init__.py new/steam-launcher/subprojects/python-vdf/vdf/__init__.py --- old/steam-launcher/subprojects/python-vdf/vdf/__init__.py 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/subprojects/python-vdf/vdf/__init__.py 2020-06-24 12:36:09.000000000 +0200 @@ -1,14 +1,21 @@ """ Module for deserializing/serializing to and from VDF """ -__version__ = "3.2" +__version__ = "3.3" __author__ = "Rossen Georgiev" import re import sys import struct from binascii import crc32 +from io import BytesIO from io import StringIO as unicodeIO + +try: + from collections.abc import Mapping +except: + from collections import Mapping + from vdf.vdict import VDFDict # Py2 & Py3 compatibility @@ -71,7 +78,7 @@ same key into one instead of overwriting. You can se this to ``False`` if you are using ``VDFDict`` and need to preserve the duplicates. """ - if not issubclass(mapper, dict): + if not issubclass(mapper, Mapping): raise TypeError("Expected mapper to be subclass of dict, got %s" % type(mapper)) if not hasattr(fp, 'readline'): raise TypeError("Expected fp to be a file-like object supporting line iteration") @@ -195,7 +202,7 @@ """ Serialize ``obj`` to a VDF formatted ``str``. """ - if not isinstance(obj, dict): + if not isinstance(obj, Mapping): raise TypeError("Expected data to be an instance of``dict``") if not isinstance(pretty, bool): raise TypeError("Expected pretty to be of type bool") @@ -210,7 +217,7 @@ Serialize ``obj`` as a VDF formatted stream to ``fp`` (a ``.write()``-supporting file-like object). """ - if not isinstance(obj, dict): + if not isinstance(obj, Mapping): raise TypeError("Expected data to be an instance of``dict``") if not hasattr(fp, 'write'): raise TypeError("Expected fp to have write() method") @@ -234,7 +241,7 @@ if escaped and isinstance(key, string_type): key = _escape(key) - if isinstance(value, dict): + if isinstance(value, Mapping): yield '%s"%s"\n%s{\n' % (line_indent, key, line_indent) for chunk in _dump_gen(value, pretty, escaped, level+1): yield chunk @@ -275,9 +282,9 @@ BIN_INT64 = b'\x0A' BIN_END_ALT = b'\x0B' -def binary_loads(s, mapper=dict, merge_duplicate_keys=True, alt_format=False): +def binary_loads(b, mapper=dict, merge_duplicate_keys=True, alt_format=False, raise_on_remaining=True): """ - Deserialize ``s`` (``bytes`` containing a VDF in "binary form") + Deserialize ``b`` (``bytes`` containing a VDF in "binary form") to a Python object. ``mapper`` specifies the Python object used after deserializetion. ``dict` is @@ -288,9 +295,27 @@ same key into one instead of overwriting. You can se this to ``False`` if you are using ``VDFDict`` and need to preserve the duplicates. """ - if not isinstance(s, bytes): - raise TypeError("Expected s to be bytes, got %s" % type(s)) - if not issubclass(mapper, dict): + if not isinstance(b, bytes): + raise TypeError("Expected s to be bytes, got %s" % type(b)) + + return binary_load(BytesIO(b), mapper, merge_duplicate_keys, alt_format, raise_on_remaining) + +def binary_load(fp, mapper=dict, merge_duplicate_keys=True, alt_format=False, raise_on_remaining=False): + """ + Deserialize ``fp`` (a ``.read()``-supporting file-like object containing + binary VDF) to a Python object. + + ``mapper`` specifies the Python object used after deserializetion. ``dict` is + used by default. Alternatively, ``collections.OrderedDict`` can be used if you + wish to preserve key order. Or any object that acts like a ``dict``. + + ``merge_duplicate_keys`` when ``True`` will merge multiple KeyValue lists with the + same key into one instead of overwriting. You can se this to ``False`` if you are + using ``VDFDict`` and need to preserve the duplicates. + """ + if not hasattr(fp, 'read') or not hasattr(fp, 'tell') or not hasattr(fp, 'seek'): + raise TypeError("Expected fp to be a file-like object with tell()/seek() and read() returning bytes") + if not issubclass(mapper, Mapping): raise TypeError("Expected mapper to be subclass of dict, got %s" % type(mapper)) # helpers @@ -299,17 +324,29 @@ int64 = struct.Struct('<q') float32 = struct.Struct('<f') - def read_string(s, idx, wide=False): + def read_string(fp, wide=False): + buf, end = b'', -1 + offset = fp.tell() + + # locate string end + while end == -1: + chunk = fp.read(64) + + if chunk == b'': + raise SyntaxError("Unterminated cstring (offset: %d)" % offset) + + buf += chunk + end = buf.find(b'\x00\x00' if wide else b'\x00') + if wide: - end = s.find(b'\x00\x00', idx) - if (end - idx) % 2 != 0: - end += 1 - else: - end = s.find(b'\x00', idx) + end += end % 2 + + # rewind fp + fp.seek(end - len(buf) + (2 if wide else 1), 1) + + # decode string + result = buf[:end] - if end == -1: - raise SyntaxError("Unterminated cstring (offset: %d)" % idx) - result = s[idx:end] if wide: result = result.decode('utf-16') elif bytes is not str: @@ -319,23 +356,20 @@ result.decode('ascii') except: result = result.decode('utf-8', 'replace') - return result, end + (2 if wide else 1) + + return result stack = [mapper()] - idx = 0 CURRENT_BIN_END = BIN_END if not alt_format else BIN_END_ALT - while len(s) > idx: - t = s[idx:idx+1] - idx += 1 - + for t in iter(lambda: fp.read(1), b''): if t == CURRENT_BIN_END: if len(stack) > 1: stack.pop() continue break - key, idx = read_string(s, idx) + key = read_string(fp) if t == BIN_NONE: if merge_duplicate_keys and key in stack[-1]: @@ -345,11 +379,11 @@ stack[-1][key] = _m stack.append(_m) elif t == BIN_STRING: - stack[-1][key], idx = read_string(s, idx) + stack[-1][key] = read_string(fp) elif t == BIN_WIDESTRING: - stack[-1][key], idx = read_string(s, idx, wide=True) + stack[-1][key] = read_string(fp, wide=True) elif t in (BIN_INT32, BIN_POINTER, BIN_COLOR): - val = int32.unpack_from(s, idx)[0] + val = int32.unpack(fp.read(int32.size))[0] if t == BIN_POINTER: val = POINTER(val) @@ -357,21 +391,20 @@ val = COLOR(val) stack[-1][key] = val - idx += int32.size elif t == BIN_UINT64: - stack[-1][key] = UINT_64(uint64.unpack_from(s, idx)[0]) - idx += uint64.size + stack[-1][key] = UINT_64(uint64.unpack(fp.read(int64.size))[0]) elif t == BIN_INT64: - stack[-1][key] = INT_64(int64.unpack_from(s, idx)[0]) - idx += int64.size + stack[-1][key] = INT_64(int64.unpack(fp.read(int64.size))[0]) elif t == BIN_FLOAT32: - stack[-1][key] = float32.unpack_from(s, idx)[0] - idx += float32.size + stack[-1][key] = float32.unpack(fp.read(float32.size))[0] else: - raise SyntaxError("Unknown data type at offset %d: %s" % (idx-1, repr(t))) + raise SyntaxError("Unknown data type at offset %d: %s" % (fp.tell() - 1, repr(t))) - if len(s) != idx or len(stack) != 1: - raise SyntaxError("Binary VDF ended at offset %d, but length is %d" % (idx, len(s))) + if len(stack) != 1: + raise SyntaxError("Reached EOF, but Binary VDF is incomplete") + if raise_on_remaining and fp.read(1) != b'': + fp.seek(-1, 1) + raise SyntaxError("Binary VDF ended at offset %d, but there is more data remaining" % (fp.tell() - 1)) return stack.pop() @@ -379,7 +412,21 @@ """ Serialize ``obj`` to a binary VDF formatted ``bytes``. """ - return b''.join(_binary_dump_gen(obj, alt_format=alt_format)) + buf = BytesIO() + binary_dump(obj, buf, alt_format) + return buf.getvalue() + +def binary_dump(obj, fp, alt_format=False): + """ + Serialize ``obj`` to a binary VDF formatted ``bytes`` and write it to ``fp`` filelike object + """ + if not isinstance(obj, Mapping): + raise TypeError("Expected obj to be type of Mapping") + if not hasattr(fp, 'write'): + raise TypeError("Expected fp to have write() method") + + for chunk in _binary_dump_gen(obj, alt_format=alt_format): + fp.write(chunk) def _binary_dump_gen(obj, level=0, alt_format=False): if level == 0 and len(obj) == 0: @@ -396,7 +443,7 @@ else: raise TypeError("dict keys must be of type str, got %s" % type(key)) - if isinstance(value, dict): + if isinstance(value, Mapping): yield BIN_NONE + key + BIN_NONE for chunk in _binary_dump_gen(value, level+1, alt_format=alt_format): yield chunk diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/subprojects/steam-devices/60-steam-input.rules new/steam-launcher/subprojects/steam-devices/60-steam-input.rules --- old/steam-launcher/subprojects/steam-devices/60-steam-input.rules 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/subprojects/steam-devices/60-steam-input.rules 2020-06-24 12:36:09.000000000 +0200 @@ -31,6 +31,16 @@ # Nintendo Switch Pro Controller over bluetooth hidraw KERNEL=="hidraw*", KERNELS=="*057E:2009*", MODE="0660", TAG+="uaccess" +# PowerA Wired Controller for Nintendo Switch +KERNEL=="hidraw*", ATTRS{idVendor}=="20d6", ATTRS{idProduct}=="a711", MODE="0660", TAG+="uaccess" + +# PowerA Wireless Controller for Nintendo Switch we have to use +# ATTRS{name} since VID/PID are reported as zeros. We use /bin/sh +# instead of udevadm directly becuase we need to use '*' glob at the +# end of "hidraw" name since we don't know the index it'd have. +# +KERNEL=="input*", ATTRS{name}=="Lic Pro Controller", RUN{program}+="/bin/sh -c \"udevadm test-builtin uaccess /sys/%p/../../hidraw/hidraw*\"" + # Nacon PS4 Revolution Pro Controller KERNEL=="hidraw*", ATTRS{idVendor}=="146b", ATTRS{idProduct}=="0d01", MODE="0660", TAG+="uaccess" @@ -61,6 +71,9 @@ # HORIPAD 4 FPS Plus KERNEL=="hidraw*", ATTRS{idVendor}=="0f0d", ATTRS{idProduct}=="0066", MODE="0660", TAG+="uaccess" +# HORIPAD for Nintendo Switch +KERNEL=="hidraw*", ATTRS{idVendor}=="0f0d", ATTRS{idProduct}=="00c1", MODE="0660", TAG+="uaccess" + # Armor Armor 3 Pad PS4 KERNEL=="hidraw*", ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="0e10", MODE="0660", TAG+="uaccess" @@ -75,3 +88,6 @@ # NVIDIA Shield Controller (2017 - NVIDIA_Controller_v01.04 over bluetooth hidraw) KERNEL=="hidraw*", KERNELS=="*0955:7214*", MODE="0660", TAG+="uaccess" + +# Astro C40 +KERNEL=="hidraw*", ATTRS{idVendor}=="9886", ATTRS{idProduct}=="0025", MODE="0660", TAG+="uaccess" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/tests/pycodestyle.sh new/steam-launcher/tests/pycodestyle.sh --- old/steam-launcher/tests/pycodestyle.sh 2020-03-19 18:13:39.000000000 +0100 +++ new/steam-launcher/tests/pycodestyle.sh 2020-06-24 12:36:09.000000000 +0200 @@ -23,13 +23,7 @@ echo "not ok 1 # TODO $PYCODESTYLE issues reported" fi -# bin_steamdeps.py has unusual whitespace so for now we ignore: -# E117 over-indented -# W191 indentation contains tabs -# E201, E202 whitespace around operators -# E501 long lines if "${PYCODESTYLE}" \ - --ignore=E117,W191,E201,E202,E501 \ ./*.py \ >&2; then echo "ok 2 - $PYCODESTYLE reported no issues"
