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 <callumjfarme...@gmail.com>
+
+- 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 <s...@collabora.com>  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 <s...@collabora.com>  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"


Reply via email to