Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package steam for openSUSE:Factory:NonFree checked in at 2024-10-02 21:31:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory:NonFree/steam (Old) and /work/SRC/openSUSE:Factory:NonFree/.steam.new.19354 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "steam" Wed Oct 2 21:31:13 2024 rev:59 rq:1204796 version:1.0.0.81 Changes: -------- --- /work/SRC/openSUSE:Factory:NonFree/steam/steam.changes 2024-06-13 15:36:55.419575274 +0200 +++ /work/SRC/openSUSE:Factory:NonFree/.steam.new.19354/steam.changes 2024-10-02 21:31:15.133062868 +0200 @@ -1,0 +2,8 @@ +Mon Sep 30 15:13:31 UTC 2024 - Callum Farmer <gmbr3@opensuse.org> + +- Update to version 1.0.0.81: + - Client timestamp 1721173382 (2024-07-16) + - Steam Runtime (scout) version 0.20240610.91380 +- Update RPM constructs (autosetup/patch) + +------------------------------------------------------------------- Old: ---- steam-streaming.xml steam_1.0.0.79.tar.gz New: ---- steam_1.0.0.81.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ steam.spec ++++++ --- /var/tmp/diff_new_pack.QpDD9e/_old 2024-10-02 21:31:17.441158820 +0200 +++ /var/tmp/diff_new_pack.QpDD9e/_new 2024-10-02 21:31:17.453159318 +0200 @@ -36,15 +36,14 @@ %endif \ %{nil} Name: steam -Version: 1.0.0.79 +Version: 1.0.0.81 Release: 0 Summary: Installer for Valve's digital software distribution service # "Limited Installation License" License: SUSE-Freeware Group: Amusements/Games/Other URL: https://www.steampowered.com/ -Source0: https://repo.steampowered.com/steam/pool/steam/s/steam/steam_%{version}.tar.gz -Source2: %{name}-streaming.xml +Source0: https://repo.steampowered.com/steam/archive/stable/%{name}_%{version}.tar.gz # PATCH-FIX-OPENSUSE steam-path-fix.patch bnc#1025841 Patch0: steam-path-fix.patch Patch1: gpu-offload.patch @@ -125,16 +124,14 @@ %dependency libICE6 %dependency libSM6 %dependency libusb-1_0-0 +%dependency libpipewire-0_3-0 %booldependency libgbm1 %if 0%{?suse_version} >= 1600 || 0%{?sle_version} >= 150600 %dependency libavif16 %endif -%if 0%{?suse_version} >= 1550 +%if 0%{?suse_version} >= 1600 || 0%{?sle_version} >= 150500 %booldependency libnm0 %endif -%if 0%{?suse_version} >= 1550 || 0%{?sle_version} >= 150300 -%dependency libpipewire-0_3-0 -%endif %description Steam is a software distribution service with an online store, automated @@ -145,12 +142,12 @@ complete the installation of the client for the current user. %prep -%setup -q -n steam-launcher +%autosetup -N -n steam-launcher %if 0%{?suse_version} < 1550 -%patch0 -p1 +%patch -P 0 -p1 %endif %if 0%{?suse_version} < 1550 && 0%{?sle_version} < 150400 -%patch1 -p1 +%patch -P 1 -p1 %endif @@ -160,20 +157,13 @@ %install make DESTDIR=%{buildroot} install-bin install-docs install-icons install-bootstrap install-desktop install-appdata -%if 0%{?suse_version} < 1550 && 0%{?sle_version} < 150300 -install -Dm0644 %{SOURCE2} %{buildroot}%{_prefix}/lib/firewalld/services/steam-streaming.xml -%endif + find %{buildroot} -type f -exec sed -i 's|#!%{_bindir}/env |#!%{_bindir}/|g' {} \; # Remove steamdeps as it is apt specific rm -f %{buildroot}%{_bindir}/%{name}deps %fdupes -s %{buildroot} -%if 0%{?suse_version} < 1550 && 0%{?sle_version} < 150300 -%post -%firewalld_reload -%endif - %files %{_bindir}/* %{_prefix}/lib/%{name} @@ -187,9 +177,4 @@ %doc debian/changelog %{_mandir}/man6/%{name}.6%{?ext_man} %{_datadir}/metainfo/* -%if 0%{?suse_version} < 1550 && 0%{?sle_version} < 150300 -%dir %{_prefix}/lib/firewalld -%dir %{_prefix}/lib/firewalld/services -%{_prefix}/lib/firewalld/services/steam-streaming.xml -%endif ++++++ steam_1.0.0.79.tar.gz -> steam_1.0.0.81.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 2024-02-08 16:05:57.000000000 +0100 +++ new/steam-launcher/bin_steam.sh 2024-08-15 19:38:56.000000000 +0200 @@ -21,7 +21,7 @@ echo "bin_steam.sh[$$]: $*" >&2 || : } -export STEAMSCRIPT_VERSION=1.0.0.79 +export STEAMSCRIPT_VERSION=1.0.0.81 # Set up domain for script localization export TEXTDOMAIN=steam @@ -169,6 +169,22 @@ fi } +function forward_command_line() +{ + if ! [ -p "$STEAMCONFIG/steam.pipe" ]; then + return 1 + fi + + local runtime="$STEAMCONFIG/root/ubuntu12_32/steam-runtime" + local remote="$runtime/amd64/usr/bin/steam-runtime-steam-remote" + + if [ -x "$remote" ] && "$remote" "$@" 2>/dev/null; then + return 0 + else + return 1 + fi +} + # Don't allow running as root if [ "$(id -u)" == "0" ]; then show_message --error $"Cannot run as root user" @@ -178,6 +194,12 @@ # Look for the Steam data files setup_variables +# If Steam is already running, try to forward the command-line to it. +# If successful, there's nothing more to do. +if forward_command_line "$@"; then + exit 0 +fi + if ! check_bootstrap "$LAUNCHSTEAMDIR"; then # See if we just need to recreate the data link if check_bootstrap "$DEFAULTSTEAMDIR"; then @@ -198,8 +220,13 @@ exit 1 fi +# Leave a copy of the bootstrap tarball in ~/.steam so that Steam can +# re-bootstrap itself if required +if ! cmp -s "$LAUNCHSTEAMBOOTSTRAPFILE" "$LAUNCHSTEAMDIR/bootstrap.tar.xz"; then + cp "$LAUNCHSTEAMBOOTSTRAPFILE" "$LAUNCHSTEAMDIR/bootstrap.tar.xz" +fi + # go to the install directory and run the client -cp "$LAUNCHSTEAMBOOTSTRAPFILE" "$LAUNCHSTEAMDIR/bootstrap.tar.xz" cd "$LAUNCHSTEAMDIR" exec "$LAUNCHSTEAMDIR/$STEAMBOOTSTRAP" "$@" 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/buildutils/add-client-files.py new/steam-launcher/buildutils/add-client-files.py --- old/steam-launcher/buildutils/add-client-files.py 2024-02-08 16:03:22.000000000 +0100 +++ new/steam-launcher/buildutils/add-client-files.py 2024-08-15 19:36:26.000000000 +0200 @@ -184,11 +184,11 @@ strict=True, ) runtimedir = os.path.join(tmpdir, 'client', 'ubuntu12_32') - client.download_runtime(datadir=runtimedir, strict=True) - client.extract_runtime(runtimedir=runtimedir, destdir=tmpdir) + client.download_scout(datadir=runtimedir, strict=True) + client.extract_scout(runtimedir=runtimedir, destdir=tmpdir) self.client_version = client.version - self.resolved_runtime = client.runtime_version + self.resolved_runtime = client.scout_version assert os.path.exists( os.path.join(tmpdir, 'client', 'steam.sh') @@ -206,7 +206,7 @@ previous scout build. """ path = os.path.join( - tmpdir, 'client', 'ubuntu12_32', 'steam-runtime.tar.xz.part0', + tmpdir, 'client', 'ubuntu12_32', 'steam-runtime.tar.xz', ) if self.runtime_version is None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/buildutils/buildutils.py new/steam-launcher/buildutils/buildutils.py --- old/steam-launcher/buildutils/buildutils.py 2024-02-08 16:03:22.000000000 +0100 +++ new/steam-launcher/buildutils/buildutils.py 2024-08-15 19:36:26.000000000 +0200 @@ -25,8 +25,12 @@ import hashlib import io import logging +import netrc import os +import re import shutil +import ssl +import subprocess import tarfile import tempfile import typing @@ -35,10 +39,8 @@ import zipfile from contextlib import suppress -import vdf - -logger = logging.getLogger('buildutils-lib') +logger = logging.getLogger('runtimeutil') class HashingWriter(io.BufferedIOBase): @@ -48,7 +50,6 @@ self.size = 0 def write(self, blob): - blob = bytes(blob) self.size += len(blob) self._sha256.update(blob) self._writer.write(blob) @@ -65,19 +66,65 @@ return self._writer.__exit__(*rest) -def verbose_urlopen( - url # type: str -): - # type: (...) -> typing.BinaryIO +def netrc_password_manager( + path: typing.Union[os.PathLike, str], +) -> urllib.request.HTTPPasswordMgr: + """ + Load a file in .netrc format from the given file. + Return a HTTPPasswordMgr that will present passwords from that file. + """ + loader = netrc.netrc(str(path)) + + password_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm() + + for host in loader.hosts: + triple = loader.authenticators(host) + + if triple is None: + continue + + login, _, password = triple + password_manager.add_password( + None, # type: ignore + 'https://' + host, + login, + password, + ) + + return password_manager + +def verbose_urlopen( + url: str, + *, + opener: typing.Optional[urllib.request.OpenerDirector] = None, +) -> typing.BinaryIO: logger.info('Requesting <%s>...', url) try: - return urllib.request.urlopen(url) + if opener is None: + return urllib.request.urlopen(url) + else: + return opener.open(url) except urllib.error.URLError: logger.error('Error opening <%s>:', url) raise +def slugify(s: str) -> str: + """Convert s into a (possibly empty) string suitable for use in + filenames, URLs etc. + """ + ret = [] + + for c in s: + if ord(c) < 128 and c.isalnum(): + ret.append(c.lower()) + else: + ret.append('-') + + return re.sub(r'-+', '-', ''.join(ret).strip('-')) + + class SteamClient: def __init__( self, @@ -91,9 +138,9 @@ self.datetime = None # type: typing.Optional[datetime.datetime] self.manifest_content = { } # type: typing.Dict[str, typing.Dict[str, typing.Any]] - self.have_runtime_manifest = False - self.runtime_version = None # type: typing.Optional[str] - self.runtime_version_marker = None # type: typing.Optional[str] + self.have_scout_manifest = False + self.scout_version = None # type: typing.Optional[str] + self.scout_version_marker = None # type: typing.Optional[str] def download_manifest( self, @@ -112,7 +159,9 @@ with open( os.path.join(datadir, 'manifest.vdf'), 'wb' ) as writer: - shutil.copyfileobj(http_reader, writer) + # mypy can't figure out that this is + # copyfileobj(BinaryIO -> BinaryIO) + shutil.copyfileobj(http_reader, writer) # type: ignore self.load_manifest(datadir) @@ -162,7 +211,9 @@ value['size'], hasher.size) if strict: - raise ValueError('sha256 mismatch') + raise ValueError( + 'size mismatch (sha256 collision?!)' + ) for basename in names: with zipfile.ZipFile( @@ -172,23 +223,51 @@ part.filename = part.filename.replace('\\', '/') unzip.extract(part, path=datadir) - def download_runtime( + def download_scout( self, datadir: str, strict: bool = False, ) -> None: - names = [] # type: typing.List[str] + self.download_runtime(1, datadir=datadir, strict=strict) + + def download_runtime( + self, + major_version: typing.Union[int, str], + datadir: str, + strict: bool = False, + ) -> bool: + zip_name = '' + zip_part_names: typing.List[str] = [] + + suite = RuntimeArchive.CODENAMED_SUITE_VERSIONS.get( + str(major_version), + f'steamrt{major_version}', + ) with tempfile.TemporaryDirectory() as tempdir: for name, value in sorted( self.manifest_content['ubuntu12'].items(), key=lambda i: i[0] ): - if (name.startswith('runtime_part') - and name.endswith('_ubuntu12')): + is_whole = (name == f'runtime_{suite}_ubuntu12') + is_part = False + + if suite == 'scout': + is_part = ( + name.startswith('runtime_part') + and name.endswith('_ubuntu12') + ) + + if is_whole or is_part: basename = value['file'] assert '/' not in basename, basename - names.append(basename) + + if is_whole: + assert not zip_name, (zip_name, basename) + zip_name = basename + else: + zip_part_names.append(basename) + with verbose_urlopen( '{}/{}'.format(self.uri, basename) ) as downloader: @@ -219,23 +298,63 @@ if strict: raise ValueError('sha256 mismatch') + tar_name = { + 'scout': 'steam-runtime.tar.xz', + 'sniper': 'SteamLinuxRuntime_sniper.tar.xz', + }.get(suite, f'SteamLinuxRuntime_{major_version}.tar.xz') + + look_for = { + 'scout': [f'ubuntu12_32/{tar_name}'], + 'sniper': [ + f'ubuntu12_64/{tar_name}', + f'ubuntu12_64/steam-runtime-{suite}.tar.xz', + ], + }.get(suite, [f'ubuntu12_64/{tar_name}']) + + found_parts = False + with open( - os.path.join(datadir, 'steam-runtime.tar.xz'), 'wb' + os.path.join(datadir, tar_name), 'wb' ) as tar_writer: - for basename in names: + if zip_name: + with zipfile.ZipFile( + os.path.join(tempdir, zip_name), 'r' + ) as unzip: + for part in unzip.infolist(): + if part.filename.replace('\\', '/') in look_for: + with unzip.open(part) as part_reader: + shutil.copyfileobj( + part_reader, + tar_writer + ) # type: ignore + return True + + raise AssertionError(f'{suite} not found in {zip_name}') + + # Fallback: scout used to be shipped split into parts + for basename in zip_part_names: with zipfile.ZipFile( os.path.join(tempdir, basename), 'r' ) as unzip: for part in unzip.infolist(): if '.tar.xz.part' in part.filename: with unzip.open(part) as part_reader: + # mypy can't figure out that this + # is copyfileobj(BinaryIO -> BinaryIO) shutil.copyfileobj( - part_reader, tar_writer) + part_reader, + tar_writer + ) # type: ignore + found_parts = True + + return found_parts def load_manifest( self, datadir: str, ) -> None: + import vdf + with open( os.path.join(datadir, 'manifest.vdf'), 'r' ) as text_reader: @@ -263,7 +382,7 @@ self.datetime.strftime('%Y-%m-%d %H:%M:%S%z'), ) - def extract_runtime( + def extract_scout( self, runtimedir: str, destdir: str, @@ -303,7 +422,7 @@ tar_reader.extract(info, path=destdir) if info.name == 'steam-runtime/manifest.deb822.gz': - self.have_runtime_manifest = True + self.have_scout_manifest = True continue @@ -316,7 +435,7 @@ ) as text_reader: marker = text_reader.read().strip() - self.runtime_version_marker = marker + self.scout_version_marker = marker version_bits = marker.split('_') if len(version_bits) != 2 or version_bits[0] != 'steam-runtime': @@ -324,5 +443,411 @@ 'Unexpected format for runtime version: %s', marker, ) else: - self.runtime_version = version_bits[-1] - logger.info('Runtime version %s', self.runtime_version) + self.scout_version = version_bits[-1] + logger.info('scout runtime version %s', self.scout_version) + + def get_container_runtime_version( + self, + major_version: typing.Union[int, str], + runtimedir: str, + ) -> typing.Optional[str]: + suite = RuntimeArchive.CODENAMED_SUITE_VERSIONS.get( + str(major_version), + f'steamrt{major_version}', + ) + + if suite == 'sniper': + top_dir = f'SteamLinuxRuntime_{suite}' + else: + top_dir = f'SteamLinuxRuntime_{major_version}' + + with suppress(FileNotFoundError): + shutil.rmtree(os.path.join(runtimedir, top_dir)) + + with suppress(FileExistsError): + os.mkdir(os.path.join(runtimedir, top_dir)) + + candidates = ( + top_dir + '.tar.xz', + f'steam-runtime-{suite}.tar.xz', + ) + + for candidate in candidates: + if os.path.exists(os.path.join(runtimedir, candidate)): + tarball = candidate + break + + candidate = os.path.join('ubuntu12_64', candidate) + + if os.path.exists(os.path.join(runtimedir, candidate)): + tarball = candidate + break + else: + logger.warning('One of %r not found', candidates) + return None + + text = '' + + # For whatever reason, the initial steam-runtime-sniper.tar.xz + # was actually bz2-compressed, so let tarfile auto-detect + with tarfile.open( + os.path.join(runtimedir, tarball), + mode='r:*', + ) as tar_reader: + for info in tar_reader: + if not info.isfile(): + continue + + if info.name in ( + f'{top_dir}/VERSIONS.txt', + f'steam-runtime-{suite}/VERSIONS.txt', + ): + extractor = tar_reader.extractfile(info) + assert extractor is not None + + with extractor as member_reader: + text = member_reader.read().decode('utf-8') + + for line in text.splitlines(): + if line.startswith('depot\t'): + return line.split('\t')[1] + elif line.startswith(f'{suite}\t'): + return line.split('\t')[1] + + return None + + +class QuietError(Exception): + """ + An error that usually doesn't provoke a traceback. + """ + + +def build_opener( + *, + handlers: typing.Iterable[urllib.request.BaseHandler] = [], + password_manager: typing.Optional[urllib.request.HTTPPasswordMgr] = None, + ssl_context: typing.Optional[ssl.SSLContext] = None +) -> urllib.request.OpenerDirector: + hs = list(handlers) + + if ssl_context is not None: + hs.append(urllib.request.HTTPSHandler(context=ssl_context)) + + if password_manager is not None: + hs.append(urllib.request.HTTPBasicAuthHandler(password_manager)) + + return urllib.request.build_opener(*hs) + + +class PinnedRuntimeVersion: + def __init__(self, v: str, archive: 'RuntimeArchive') -> None: + if not v or not v[0].isdigit(): + raise ValueError( + 'Runtime version {!r} does not start with a digit'.format(v) + ) + + for c in v: + if c != '.' and not c.isdigit(): + raise ValueError( + 'Runtime version {!r} contains non-dot, non-digit'.format( + v + ) + ) + + self.version = v + self.archive = archive + + def __eq__(self, other): + return ( + isinstance(other, PinnedRuntimeVersion) + and self.version == other.version + and self.archive is other.archive + ) + + def __lt__(self, other): + if not isinstance(other, PinnedRuntimeVersion): + raise TypeError( + 'Cannot compare {!r} with {!r}'.format(self, other) + ) + + if self.archive is not other.archive: + raise TypeError( + 'Cannot compare {!r} with {!r}'.format(self, other) + ) + + return self.version < other.version + + def __le__(self, other): + if not isinstance(other, PinnedRuntimeVersion): + raise TypeError( + 'Cannot compare {!r} with {!r}'.format(self, other) + ) + + return self == other or self < other + + def __gt__(self, other): + if not isinstance(other, PinnedRuntimeVersion): + raise TypeError( + 'Cannot compare {!r} with {!r}'.format(self, other) + ) + + return other < self + + def __ge__(self, other): + if not isinstance(other, PinnedRuntimeVersion): + raise TypeError( + 'Cannot compare {!r} with {!r}'.format(self, other) + ) + + return self == other or other < self + + def __hash__(self): + return hash(self.version) + + def __str__(self) -> str: + return self.version + + def __repr__(self) -> str: + return '<PinnedRuntimeVersion {!r} in {!r}>'.format( + self.version, + self.archive, + ) + + def get_uri(self, filename: str) -> str: + return self.archive.get_uri(self.version, filename) + + def open(self, filename: str) -> typing.BinaryIO: + return self.archive.open(self.version, filename) + + def fetch( + self, + filename: str, + destdir: str, + *, + log_level: typing.Optional[int] = None, + must_exist: bool = True + ) -> None: + self.archive.fetch( + self.version, filename, destdir, + log_level=log_level, must_exist=must_exist, + ) + + +class RuntimeArchive: + DEFAULT_IMAGES_URI = ( + 'https://repo.steampowered.com/IMAGES_DIR/snapshots' + ) + DEFAULT_SSH_HOST = None # type: typing.Optional[str] + DEFAULT_SSH_ROOT = None # type: typing.Optional[str] + + # Older branches of the Steam Runtime have a Team Fortress 2 character + # class as a codename. Newer branches are just called 'steamrt5' and + # so on. + SUITE_CODENAMES = { + 'scout': '1', + 'soldier': '2', + 'sniper': '3', + 'medic': '4', + } + CODENAMED_SUITE_VERSIONS = { + '1': 'scout', + '2': 'soldier', + '3': 'sniper', + '4': 'medic', + } + + def __init__( + self, + suite: str, + *, + images_uri: typing.Optional[str] = None, + opener: typing.Optional[urllib.request.OpenerDirector] = None, + password_manager: typing.Optional[ + urllib.request.HTTPPasswordMgr + ] = None, + ssh_host: typing.Optional[str] = None, + ssh_path: typing.Optional[str] = None, + ssh_root: typing.Optional[str] = None, + ssh_user: typing.Optional[str] = None, + ssl_context: typing.Optional[ssl.SSLContext] = None + ) -> None: + cls = self.__class__ + + self.suite = suite + + if ssh_host is None: + ssh_host = cls.DEFAULT_SSH_HOST + + if images_uri is None: + if suite in cls.SUITE_CODENAMES: + topdir = f'steamrt-{suite}' + images_dir = f'steamrt-images-{suite}' + else: + topdir = images_dir = suite + + images_uri = ( + cls.DEFAULT_IMAGES_URI + ).replace( + 'SUITE', suite + ).replace( + 'TOPDIR', topdir + ).replace( + 'IMAGES_DIR', images_dir + ) + + self.images_uri = images_uri + + if ssl_context is None: + ssl_context = cls.create_ssl_context() + + if opener is None: + opener = build_opener( + password_manager=password_manager, + ssl_context=ssl_context, + ) + + self.opener = opener + + if ssh_host is not None: + if ssh_root is None: + ssh_root = cls.DEFAULT_SSH_ROOT + + if ssh_root is None: + ssh_root = f'/srv/{ssh_host}/www' + + if ssh_path is None: + if suite in cls.SUITE_CODENAMES: + ssh_path = f'steamrt-{suite}' + else: + ssh_path = suite + + if not ssh_path.startswith('/'): + ssh_path = f'{ssh_root}/{ssh_path}' + + if ssh_user is None: + self.ssh_target = ssh_host # type: typing.Optional[str] + else: + self.ssh_target = ssh_user + '@' + ssh_host + else: + self.ssh_target = None + + self.ssh_path = ssh_path + + @classmethod + def create_ssl_context(cls) -> ssl.SSLContext: + return ssl.create_default_context() + + def __repr__(self) -> str: + return '<RuntimeArchive {!r}>'.format(self.suite) + + def get_uri( + self, + version: str, + filename: str, + ) -> str: + return '{}/{}/{}'.format(self.images_uri, version, filename) + + def open( + self, + version: str, + filename: str, + *, + log_level: int = logging.ERROR, + ) -> typing.BinaryIO: + """ + Open and stream the given file in the given version of this + runtime. Unlike fetch(), this always uses http or https. + + If we cannot open it, log a message at level log_level and reraise + the exception. + """ + uri = self.get_uri(version, filename) + + logger.info('Requesting <%s>...', uri) + try: + return self.opener.open(uri) + except urllib.error.URLError: + if log_level > logging.NOTSET: + logger.log(log_level, 'Error opening <%s>:', uri) + raise + + def pin_version( + self, + version: str, + *, + log_level: int = logging.ERROR, + ) -> PinnedRuntimeVersion: + """ + Get the "pinned" version corresponding to the given + symbolic version. + If it's a version number rather than a symbolic version, + just return it as a PinnedRuntimeVersion. + """ + with self.open( + version, 'VERSION.txt', log_level=log_level + ) as http_reader: + return PinnedRuntimeVersion( + http_reader.read().decode('ascii').strip(), + self, + ) + + def fetch( + self, + version: str, + filename: str, + destdir: str, + *, + log_level: typing.Optional[int] = None, + must_exist: bool = True, + rsync: bool = True, + ) -> None: + """ + Download the given file from the given version of this runtime. + Write it to a file of the same basename in destdir. + + Use rsync for an incremental transfer if possible, unless @rsync + is false. + """ + ssh_target = self.ssh_target + ssh_path = self.ssh_path + + if log_level is None: + if must_exist: + log_level = logging.ERROR + else: + log_level = logging.INFO + + if ( + ssh_target is not None + and ssh_path is not None + and must_exist + and rsync + ): + path = f'{ssh_path}/{version}/{filename}' + logger.info('Downloading %r...', path) + subprocess.run([ + 'rsync', + '--archive', + '--partial', + '--progress', + ssh_target + ':' + path, + os.path.join(destdir, filename), + ], check=True) + else: + try: + with self.open( + version, filename, + log_level=log_level, + ) as response, open( + os.path.join(destdir, filename), 'wb', + ) as writer: + # mypy can't figure out that this is + # copyfileobj(BinaryIO -> BinaryIO) + shutil.copyfileobj(response, writer) # type: ignore + except urllib.error.URLError: + with suppress(FileNotFoundError): + os.remove(os.path.join(destdir, filename)) + + if must_exist: + raise 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 2024-02-08 16:05:56.000000000 +0100 +++ new/steam-launcher/client-versions.json 2024-08-15 19:38:55.000000000 +0200 @@ -1,4 +1,4 @@ { - "client_version": "1705108172", - "runtime_version": "0.20231127.68515" + "client_version": "1721173382", + "runtime_version": "0.20240610.91380" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/com.valvesoftware.Steam.metainfo.xml new/steam-launcher/com.valvesoftware.Steam.metainfo.xml --- old/steam-launcher/com.valvesoftware.Steam.metainfo.xml 2024-02-08 16:03:22.000000000 +0100 +++ new/steam-launcher/com.valvesoftware.Steam.metainfo.xml 2024-08-15 19:36:26.000000000 +0200 @@ -32,6 +32,8 @@ </screenshots> <launchable type="desktop-id">steam.desktop</launchable> <releases> + <release version="1.0.0.81" date="2024-08-15"/> + <release version="1.0.0.80" date="2024-04-22"/> <release version="1.0.0.79" date="2024-02-08"/> <release version="1.0.0.78" date="2023-05-09"/> <release version="1.0.0.77" date="2023-05-09"/> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/debian/README.source new/steam-launcher/debian/README.source --- old/steam-launcher/debian/README.source 2024-02-08 16:03:22.000000000 +0100 +++ new/steam-launcher/debian/README.source 1970-01-01 01:00:00.000000000 +0100 @@ -1,124 +0,0 @@ -Notes for maintainers -===================== - -Incorporating binaries from the Steam client --------------------------------------------- - -The bootstrap tarball contains a small subset of the Steam client. -It is not maintained in this repository, and is ignored by our .gitignore. - -To fetch it, run buildutils/add-client-files.py. By default, it will -download files from the latest public general-availability Steam client. -There are many options: run buildutils/add-client-files.py --help for -an up-to-date list. - -Use --client-manifest=steam_client_publicbeta_ubuntu12 if you would prefer -to update the bootstrapper from the latest public beta Steam client. - ---client-dir=/path/to/client (or --client-dir=/path/to/.steam/steam) gets -the client files directly from a Steam client installation. - ---client-tarball-uri gets the client files from a tarball, which must -have a top-level directory (its name is ignored) containing filenames -like `steam.sh` and `ubuntu12_32`, for example: - - client-2020-02-24/ - steam.sh - ubuntu12_32/ - steam - steam-runtime.tar.xz.part0 - ... - ... - -(For details of the minimal files that must be present in the tarball, -see the source code!) - -You can specify an option like --runtime-version=0.20200204.0 to delete the -Steam Runtime from the client and replace it with a suitable Steam Runtime -before packing the bootstrap tarball. In particular, you must provide this -option if the runtime is missing from your client. - -Updating subprojects --------------------- - -To update the udev rules from steam-devices: - - # only necessary the first time - git remote add --no-tags steam-devices https://github.com/ValveSoftware/steam-devices - # merge the upstream changes into our subtree - git subtree merge -P subprojects/steam-devices steam-devices/master - # review the changes - git diff HEAD~ - -Updating PGP keys ------------------ - -Historically `steam.gpg` was regenerated with: - - gpg \ - --homedir=$(CURDIR)/gpg \ - --no-default-keyring \ - --keyring=$(CURDIR)/steam.gpg \ - --import steam-key.asc - -but that's probably only valid for GPG v1. In future (if we generate -new keys or uids, or update revocation dates) it would be better to use: - - gpg --export-options export-clean,export-minimal --export KEYIDS... > steam.gpg - gpg --armor --export-options export-clean,export-minimal --export KEYIDS... > steam-key.asc - -on a machine that holds the canonical version of the keys. - -Preparing a beta release ------------------------- - -* Check that the diff is appropriate - -* Download the prerelease package produced by Gitlab-CI (each commit - to git master generates a package in the `playground/steam-launcher` - beta suite), and test it on whatever distributions are appropriate - -* Update `debian/changelog` to include all the latest changes, if not - already done (`gbp dch --full` from the `git-buildpackage` package - might help) - -* Finalize the first line of the changelog, and the following - "sign-off" line starting with ` --` - (`debchange -r` from the `devscripts` package might help) - -* Update the `STEAMSCRIPT_VERSION` in `bin_steam.sh` - -* Add a `<release>` in `com.valvesoftware.Steam.metainfo.xml`, preserving - newest-first order - -* Commit the changes - -* `git tag -m 'steam-launcher vX.Y.Z.W' -a vX.Y.Z.W` - -* `git push origin master vX.Y.Z.W` - -* If all goes well, the new release will be built automatically from the - `vX.Y.Z.W` tag by Gitlab-CI, and go into the internal staging apt - repository (`steam-launcher` beta suite). - -* Last chance to test! If there's a problem, fix it and start again with - a new version number. - -* Trigger the Gitlab-CI pipeline on the default branch with - the `STEAM_LAUNCHER_CI_ACTION` CI variable set to `public`. - This will copy the staging beta to be the public beta - (and also the staging stable to the public stable). - -Putting a beta release into production --------------------------------------- - -* Trigger the Gitlab-CI pipeline on the default branch with - the `STEAM_LAUNCHER_CI_ACTION` CI variable set to `staging-stable`. - This will copy the staging beta to staging stable. - -* *Really* the last chance to test :-) - -* Trigger the Gitlab-CI pipeline on the default branch with - the `STEAM_LAUNCHER_CI_ACTION` CI variable set to `public`. - This will copy the staging stable to be the public stable - (and also the staging beta to the public beta). 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 2024-02-08 16:03:22.000000000 +0100 +++ new/steam-launcher/debian/changelog 2024-08-15 19:36:26.000000000 +0200 @@ -1,3 +1,29 @@ +steam (1:1.0.0.81) beta; urgency=medium + + * bin_steam.sh: Optimize the case where Steam is already running, + by using steam-runtime-steam-remote (if available) to forward the + command-line to the running instance (steamrt/tasks#496) + * bin_steam.sh: Don't copy bootstrap.tar.xz if it already matches + (steamrt/tasks#496) + * Build using updated Steam client: + - Client timestamp 1721173382 (2024-07-16) + - Steam Runtime (scout) version 0.20240610.91380 + * Update steam-devices subproject up to 2024-05-22: + - Performance Designed Products Victrix Pro FS-12 + (steam-devices#47, thanks to @notpentadactyl) + * buildutil: Internal changes (steamrt/tasks#468) + * CI: Make tests more realistic + + -- Simon McVittie <smcv@collabora.com> Thu, 15 Aug 2024 18:36:00 +0100 + +steam (1:1.0.0.80) beta; urgency=medium + + * Build using updated Steam client: + - Client timestamp 1709846872 (2024-03-07) + - Steam Runtime (scout) version 0.20240304.79797 + + -- Simon McVittie <smcv@collabora.com> Mon, 22 Apr 2024 15:08:05 +0100 + steam (1:1.0.0.79) beta; urgency=medium [ Timothee Besset ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/steam-launcher/debian/source/options new/steam-launcher/debian/source/options --- old/steam-launcher/debian/source/options 2024-02-08 16:03:22.000000000 +0100 +++ new/steam-launcher/debian/source/options 2024-08-15 19:36:26.000000000 +0200 @@ -1,5 +1,3 @@ tar-ignore=.git -tar-ignore=.gitlab-ci.yml tar-ignore=.mypy_cache tar-ignore=__pycache__ -tar-ignore=ci 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 2024-02-08 16:03:22.000000000 +0100 +++ new/steam-launcher/subprojects/steam-devices/60-steam-input.rules 2024-08-15 19:36:26.000000000 +0200 @@ -137,3 +137,6 @@ # Thrustmaster eSwap Pro KERNEL=="hidraw*", ATTRS{idVendor}=="044f", ATTRS{idProduct}=="d00e", MODE="0660", TAG+="uaccess" + +# Performance Designed Products Victrix Pro FS-12 for PS4 & PS5 +KERNEL=="hidraw*", ATTRS{idVendor}=="0e6f", ATTRS{idProduct}=="020c", MODE="0660", TAG+="uaccess"