Newer
Older
#!/usr/bin/env python3
# Copyright © 2019-2022 Collabora Ltd.
#
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
Build the steam-container-runtime (aka SteamLinuxRuntime) depot, either
from just-built files or by downloading a previous build.
The oldest distribution we are currently testing with the CI is Ubuntu
18.04, that is shipping with Python 3.6.5.
In order to keep the compatibility with Ubuntu 18.04, this Python script
should not require a Python version newer than the 3.6.
"""
import argparse
import gzip
import json
import logging
import os
import re
import shlex
import shutil
import stat
import subprocess
import tempfile
import urllib.request
from contextlib import suppress
from pathlib import Path
from typing import (
Any,
Dict,
List,
Optional,
Sequence,
Set,
Tuple,
from debian.deb822 import (
Sources,
)
HERE = Path(__file__).resolve().parent
logger = logging.getLogger('populate-depot')
DEFAULT_PRESSURE_VESSEL_URI = (
'https://repo.steampowered.com/pressure-vessel/snapshots'
)
DEFAULT_IMAGES_URI = (
'https://repo.steampowered.com/steamrt-images-SUITE/snapshots'
)
class InvocationError(Exception):
pass
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
class PressureVesselRelease:
def __init__(
self,
*,
cache: str = '.cache',
ssh_host: str = '',
ssh_path: str = '',
uri: str = DEFAULT_PRESSURE_VESSEL_URI,
version: str = ''
) -> None:
self.cache = cache
self.pinned_version = None # type: Optional[str]
self.ssh_host = ssh_host
self.ssh_path = ssh_path
self.uri = uri
self.version = version
def get_uri(
self,
filename: str,
version: Optional[str] = None,
) -> str:
uri = self.uri
v = version or self.pinned_version or self.version or 'latest'
return f'{uri}/{v}/{filename}'
def get_ssh_path(
self,
filename: str,
version: Optional[str] = None,
) -> str:
ssh_host = self.ssh_host
ssh_path = self.ssh_path
v = version or self.pinned_version or self.version or 'latest'
if not ssh_host or not ssh_path:
raise RuntimeError('ssh host/path not configured')
return f'{ssh_path}/{v}/{filename}'
def fetch(
self,
filename: str,
opener: urllib.request.OpenerDirector,
version: Optional[str] = None,
) -> str:
dest = os.path.join(self.cache, filename)
if self.ssh_host and self.ssh_path:
path = self.get_ssh_path(filename)
logger.info('Downloading %r...', path)
subprocess.run([
'rsync',
'--archive',
'--partial',
'--progress',
self.ssh_host + ':' + path,
dest,
], check=True)
else:
uri = self.get_uri(filename)
logger.info('Downloading %r...', uri)
with opener.open(uri) as response:
with open(dest + '.new', 'wb') as writer:
shutil.copyfileobj(response, writer)
os.rename(dest + '.new', dest)
return dest
def pin_version(
self,
opener: urllib.request.OpenerDirector,
) -> str:
pinned = self.pinned_version
if pinned is None:
if self.ssh_host and self.ssh_path:
path = self.get_ssh_path(filename='VERSION.txt')
logger.info('Determining version number from %r...', path)
pinned = subprocess.run([
'ssh', self.ssh_host,
'cat {}'.format(shlex.quote(path)),
], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
else:
uri = self.get_uri(filename='VERSION.txt')
logger.info('Determining version number from %r...', uri)
with opener.open(uri) as response:
pinned = response.read().decode('utf-8').strip()
self.pinned_version = pinned
return pinned
class Runtime:
def __init__(
self,
name,
*,
suite: str,
architecture: str = 'amd64,i386',
images_uri: str = DEFAULT_IMAGES_URI,
official: bool = False,
path: Optional[str] = None,
ssh_host: str = '',
ssh_path: str = '',
) -> None:
self.architecture = architecture
self.images_uri = images_uri
self.name = name
self.official = official
self.path = path
self.suite = suite
self.ssh_host = ssh_host
self.ssh_path = ssh_path
self.version = version
self.pinned_version = None # type: Optional[str]
self.sha256 = {} # type: Dict[str, str]
os.makedirs(self.cache, exist_ok=True)
self.prefix = 'com.valvesoftware.SteamRuntime'
self.platform = self.prefix + '.Platform'
self.sdk = self.prefix + '.Sdk'
self.tarball = '{}-{}-{}-runtime.tar.gz'.format(
self.platform,
self.architecture,
self.suite,
)
self.dockerfile = '{}-{}-{}-sysroot.Dockerfile'.format(
self.sdk,
self.architecture,
self.suite,
)
self.sdk_tarball = '{}-{}-{}-runtime.tar.gz'.format(
self.sdk,
self.architecture,
self.suite,
)
self.debug_tarball = '{}-{}-{}-debug.tar.gz'.format(
self.sdk,
self.architecture,
self.suite,
)
self.sysroot_tarball = '{}-{}-{}-sysroot.tar.gz'.format(
self.sdk,
self.architecture,
self.suite,
)
self.build_id_file = '{}-{}-{}-buildid.txt'.format(
self.platform,
self.architecture,
self.suite,
)
self.sdk_build_id_file = '{}-{}-{}-buildid.txt'.format(
self.sdk,
self.architecture,
self.suite,
)
self.sources = '{}-{}-{}-sources.deb822.gz'.format(
self.sdk,
self.architecture,
self.suite,
)
def get_archives(
self,
include_sdk_debug=False,
include_sdk_runtime=False,
include_sdk_sysroot=False,
):
archives = [self.tarball]
if include_sdk_debug:
archives.append(self.debug_tarball)
if include_sdk_sysroot:
archives.append(self.dockerfile)
archives.append(self.sysroot_tarball)
if include_sdk_runtime:
archives.append(self.sdk_tarball)
return archives
def __str__(self) -> str:
return self.name
@classmethod
def from_details(
cls,
name: str,
details: Dict[str, Any],
default_architecture: str = 'amd64,i386',
default_suite: str = '',
images_uri: str = DEFAULT_IMAGES_URI,
ssh_host: str = '',
ssh_path: str = '',
):
return cls(
name,
architecture=details.get(
'architecture', default_architecture,
),
images_uri=images_uri,
official=details.get('official', False),
path=details.get('path', None),
ssh_host=ssh_host,
ssh_path=ssh_path,
suite=details.get('suite', default_suite or name),
version=details.get('version', default_version),
)
def get_uri(
self,
filename: str,
version: Optional[str] = None,
) -> str:
suite = self.suite
uri = self.images_uri.replace('SUITE', suite)
v = version or self.pinned_version or self.version or 'latest'
return f'{uri}/{v}/{filename}'
def get_ssh_path(
self,
filename: str,
version: Optional[str] = None,
) -> str:
ssh_host = self.ssh_host
suite = self.suite
ssh_path = self.ssh_path.replace('SUITE', suite)
v = version or self.pinned_version or self.version or 'latest'
if not ssh_host or not ssh_path:
raise RuntimeError('ssh host/path not configured')
return f'{ssh_path}/{v}/{filename}'
def fetch(
self,
filename: str,
opener: urllib.request.OpenerDirector,
version: Optional[str] = None,
) -> str:
dest = os.path.join(self.cache, filename)
if filename in self.sha256:
try:
with open(dest, 'rb') as reader:
hasher = hashlib.sha256()
while True:
blob = reader.read(4096)
if not blob:
break
hasher.update(blob)
digest = hasher.hexdigest()
except OSError:
pass
else:
if digest == self.sha256[filename]:
logger.info('Using cached %r', dest)
return dest
if self.ssh_host and self.ssh_path:
path = self.get_ssh_path(filename)
logger.info('Downloading %r...', path)
subprocess.run([
'rsync',
'--archive',
'--partial',
'--progress',
self.ssh_host + ':' + path,
], check=True)
else:
uri = self.get_uri(filename)
logger.info('Downloading %r...', uri)
with opener.open(uri) as response:
with open(dest + '.new', 'wb') as writer:
shutil.copyfileobj(response, writer)
os.rename(dest + '.new', dest)
return dest
def pin_version(
self,
opener: urllib.request.OpenerDirector,
) -> str:
pinned = self.pinned_version
sha256 = {} # type: Dict[str, str]
if pinned is None:
if self.ssh_host and self.ssh_path:
path = self.get_ssh_path(filename='VERSION.txt')
logger.info('Determining version number from %r...', path)
pinned = subprocess.run([
'ssh', self.ssh_host,
'cat {}'.format(shlex.quote(path)),
], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
path = self.get_ssh_path(filename='SHA256SUMS')
sha256sums = subprocess.run([
'ssh', self.ssh_host,
'cat {}'.format(shlex.quote(path)),
], stdout=subprocess.PIPE).stdout
assert sha256sums is not None
else:
uri = self.get_uri(filename='VERSION.txt')
logger.info('Determining version number from %r...', uri)
with opener.open(uri) as response:
pinned = response.read().decode('utf-8').strip()
uri = self.get_uri(filename='SHA256SUMS')
with opener.open(uri) as response:
sha256sums = response.read()
for line in sha256sums.splitlines():
sha256_bytes, name_bytes = line.split(maxsplit=1)
name = name_bytes.decode('utf-8')
if name.startswith('*'):
name = name[1:]
sha256[name] = sha256_bytes.decode('ascii')
self.sha256 = sha256
self.pinned_version = pinned
return pinned
RUN_IN_DIR_SOURCE = '''\
#!/bin/sh
# {source_for_generated_file}
set -eu
me="$(readlink -f "$0")"
here="${{me%/*}}"
me="${{me##*/}}"
dir={escaped_dir}
pressure_vessel="${{PRESSURE_VESSEL_PREFIX:-"${{here}}/pressure-vessel"}}"
export PRESSURE_VESSEL_COPY_RUNTIME=1
export PRESSURE_VESSEL_GC_LEGACY_RUNTIMES=1
export PRESSURE_VESSEL_RUNTIME="${{dir}}"
unset PRESSURE_VESSEL_RUNTIME_ARCHIVE
export PRESSURE_VESSEL_RUNTIME_BASE="${{here}}"
if [ -z "${{PRESSURE_VESSEL_VARIABLE_DIR-}}" ]; then
export PRESSURE_VESSEL_VARIABLE_DIR="${{here}}/var"
fi
exec "${{pressure_vessel}}/bin/pressure-vessel-unruntime" "$@"
'''
RUN_IN_ARCHIVE_SOURCE = '''\
#!/bin/sh
# {source_for_generated_file}
set -eu
me="$(readlink -f "$0")"
here="${{me%/*}}"
me="${{me##*/}}"
archive={escaped_runtime}-{escaped_arch}-{escaped_suite}-runtime.tar.gz
pressure_vessel="${{PRESSURE_VESSEL_PREFIX:-"${{here}}/pressure-vessel"}}"
export PRESSURE_VESSEL_COPY_RUNTIME=1
export PRESSURE_VESSEL_GC_LEGACY_RUNTIMES=1
unset PRESSURE_VESSEL_RUNTIME
export PRESSURE_VESSEL_RUNTIME_ARCHIVE="${{archive}}"
export PRESSURE_VESSEL_RUNTIME_BASE="${{here}}"
if [ -z "${{PRESSURE_VESSEL_VARIABLE_DIR-}}" ]; then
export PRESSURE_VESSEL_VARIABLE_DIR="${{here}}/var"
fi
exec "${{pressure_vessel}}/bin/pressure-vessel-unruntime" "$@"
def __init__(
self,
name: str = '',
sort_weight: int = 0,
) -> None:
self.name = name
self.version = ''
self.runtime = ''
self.runtime_version = ''
self.sort_weight = sort_weight
self.comment = ''
def __str__(self) -> str:
ret = '{} version {!r}'.format(self.name, self.version)
if self.runtime or self.runtime_version:
ret = ret + ' (from {} version {})'.format(
self.runtime or '(unknown runtime)',
self.runtime_version or '(unknown)',
)
return ret
def to_sort_key(self) -> Tuple[int, str]:
return (self.sort_weight, self.to_tsv())
def to_tsv(self) -> str:
if self.comment:
comment = '# ' + self.comment
else:
comment = ''
return '\t'.join((
self.name, self.version,
self.runtime, self.runtime_version,
comment,
)) + '\n'
class Main:
def __init__(
self,
architecture: str = 'amd64,i386',
credential_envs: Sequence[str] = (),
credential_hosts: Sequence[str] = (),
depot: str = 'depot',
depot_version: str = '',
images_uri: str = DEFAULT_IMAGES_URI,
include_archives: bool = False,
include_sdk_debug: bool = False,
include_sdk_runtime: bool = False,
include_sdk_sysroot: bool = False,
minimize: bool = False,
pressure_vessel_archive: str = '',
pressure_vessel_from_runtime: str = '',
pressure_vessel_from_runtime_json: str = '',
pressure_vessel_guess: str = '',
pressure_vessel_official: bool = False,
pressure_vessel_ssh_host: str = '',
pressure_vessel_ssh_path: str = '',
pressure_vessel_uri: str = DEFAULT_PRESSURE_VESSEL_URI,
pressure_vessel_version: str = '',
runtime: str = 'scout',
scripts_version: str = '',
source_dir: str = str(HERE),
ssh_host: str = '',
ssh_path: str = '',
steam_app_id: str = '',
suite: str = '',
toolmanifest: bool = False,
unpack_ld_library_path: str = '',
unpack_runtime: bool = True,
unpack_sources: Sequence[str] = (),
unpack_sources_into: str = '.',
versioned_directories: bool = False,
**kwargs: Dict[str, Any],
) -> None:
openers: List[urllib.request.BaseHandler] = []
if not credential_hosts:
credential_hosts = []
host = urllib.parse.urlparse(images_uri).hostname
if host is not None:
credential_hosts.append(host)
if credential_envs:
password_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
for cred in credential_envs:
if ':' in cred:
username_env, password_env = cred.split(':', 1)
logger.info(
'Using username from $%s and password from $%s',
username_env, password_env)
username = os.environ[username_env]
password = os.environ[password_env]
else:
logger.info(
'Using username and password from $%s', cred)
username, password = os.environ[cred].split(':', 1)
for host in credential_hosts:
password_manager.add_password(
None, # type: ignore
host,
username,
password,
)
openers.append(
urllib.request.HTTPBasicAuthHandler(password_manager)
)
self.opener = urllib.request.build_opener(*openers)
self.cache = cache
self.default_architecture = architecture
self.default_suite = suite
self.default_version = version
self.depot = os.path.abspath(depot)
self.depot_version = depot_version
self.images_uri = images_uri
self.include_archives = include_archives
self.include_sdk_debug = include_sdk_debug
self.include_sdk_runtime = include_sdk_runtime
self.include_sdk_sysroot = include_sdk_sysroot
self.minimize = minimize
self.pressure_vessel_ssh_host = pressure_vessel_ssh_host or ssh_host
self.pressure_vessel_ssh_path = pressure_vessel_ssh_path
self.pressure_vessel_uri = pressure_vessel_uri
self.scripts_version = scripts_version
self.source_dir = source_dir
self.ssh_host = ssh_host
self.ssh_path = ssh_path
self.steam_app_id = steam_app_id
self.toolmanifest = toolmanifest
self.unpack_ld_library_path = unpack_ld_library_path
self.unpack_runtime = unpack_runtime
self.unpack_sources = unpack_sources
self.unpack_sources_into = unpack_sources_into
self.versioned_directories = versioned_directories
n_sources = 0
for source in (
pressure_vessel_archive,
pressure_vessel_from_runtime,
pressure_vessel_from_runtime_json,
pressure_vessel_guess,
pressure_vessel_version,
):
if source:
n_sources += 1
if n_sources == 0:
pressure_vessel_version = 'latest'
elif n_sources > 1:
raise RuntimeError(
'Cannot combine more than one of '
'--pressure-vessel, '
'--pressure-vessel-archive, '
'--pressure-vessel-from-runtime, '
'--pressure-vessel-from-runtime-json and '
'--pressure-vessel-version'
os.makedirs(self.cache, exist_ok=True)
if not (self.include_archives or self.unpack_runtime):
raise RuntimeError(
'Cannot use both --no-include-archives and '
'--no-unpack-runtime'
if '=' in runtime:
name, rhs = runtime.split('=', 1)
if rhs.startswith('{'):
details = json.loads(rhs)
with open(rhs, 'rb') as reader:
details = json.load(reader)
else:
name = runtime
details = {}
self.runtime = self.new_runtime(name, details)
self.versions = [] # type: List[ComponentVersion]
if pressure_vessel_guess:
if self.runtime.name == pressure_vessel_guess:
pressure_vessel_from_runtime = pressure_vessel_guess
elif pressure_vessel_guess.startswith('{'):
pressure_vessel_from_runtime_json = pressure_vessel_guess
elif os.path.isdir(pressure_vessel_guess):
pressure_vessel_archive = os.path.join(
pressure_vessel_guess, 'pressure-vessel-bin.tar.gz',
)
elif (
os.path.isfile(pressure_vessel_guess)
and pressure_vessel_guess.endswith('.tar.gz')
):
pressure_vessel_archive = pressure_vessel_guess
else:
pressure_vessel_from_runtime = pressure_vessel_guess
self.pressure_vessel_runtime = None # type: Optional[Runtime]
self.pressure_vessel_version = ''
if pressure_vessel_version:
self.pressure_vessel_version = pressure_vessel_version
elif pressure_vessel_archive:
self.pressure_vessel_runtime = self.new_runtime(
'scout',
{
'official': pressure_vessel_official,
'path': pressure_vessel_archive,
},
default_suite='scout',
)
elif self.runtime.name == pressure_vessel_from_runtime:
self.pressure_vessel_runtime = self.runtime
elif pressure_vessel_from_runtime:
self.pressure_vessel_runtime = self.new_runtime(
pressure_vessel_from_runtime, {},
default_suite=pressure_vessel_from_runtime,
)
elif pressure_vessel_from_runtime_json:
self.pressure_vessel_runtime = self.new_runtime(
'scout',
json.loads(pressure_vessel_from_runtime_json),
default_suite='scout',
)
def new_runtime(
self,
name: str,
details: Dict[str, Any],
default_suite: str = '',
) -> Runtime:
return Runtime.from_details(
name,
details,
default_architecture=self.default_architecture,
default_suite=default_suite or self.default_suite,
default_version=self.default_version,
images_uri=self.images_uri,
ssh_host=self.ssh_host,
ssh_path=self.ssh_path,
def merge_dir_into_depot(
self,
source_root: str,
):
for (dirpath, dirnames, filenames) in os.walk(source_root):
relative_path = os.path.relpath(dirpath, source_root)
for member in dirnames:
os.makedirs(
os.path.join(self.depot, relative_path, member),
exist_ok=True,
)
for member in filenames:
source = os.path.join(dirpath, member)
merged = os.path.join(self.depot, relative_path, member)
with suppress(FileNotFoundError):
os.unlink(merged)
os.makedirs(os.path.dirname(merged), exist_ok=True)
shutil.copy(source, merged)
def run(self) -> None:
if self.layered:
self.do_layered_runtime()
else:
self.do_container_runtime()
def do_layered_runtime(self) -> None:
if self.runtime.name != 'scout':
raise InvocationError('Can only layer scout onto soldier')
if self.unpack_ld_library_path:
raise InvocationError(
'Cannot use --unpack-ld-library-path with --layered'
)
if self.include_archives:
raise InvocationError(
'Cannot use --include-archives with --layered'
)
if (
self.include_sdk_debug
or self.include_sdk_runtime
or self.include_sdk_sysroot
):
'Cannot use --include-sdk-* with --layered'
)
if self.unpack_sources:
raise InvocationError(
'Cannot use --unpack-source with --layered'
)
self.merge_dir_into_depot(
os.path.join(self.source_dir, 'runtimes', 'scout-on-soldier')
)
if self.runtime.version:
self.unpack_ld_library_path = self.depot
self.download_scout_tarball(self.runtime)
local_version = ComponentVersion('LD_LIBRARY_PATH')
version = self.runtime.pinned_version
assert version is not None
local_version.version = version
local_version.runtime = 'scout'
local_version.runtime_version = version
local_version.comment = 'steam-runtime/'
self.versions.append(local_version)
else:
unspecified_version = ComponentVersion('LD_LIBRARY_PATH')
unspecified_version.version = '-'
unspecified_version.runtime = 'scout'
unspecified_version.runtime_version = '-'
unspecified_version.comment = (
'see ~/.steam/root/ubuntu12_32/steam-runtime/version.txt'
)
self.versions.append(unspecified_version)
self.write_component_versions()
def ensure_ref(self, path: str) -> None:
'''
Create $path/files/.ref as an empty regular file.
This is useful because pressure-vessel would create this file
during processing. If it gets committed to the depot, then Steampipe
will remove it when superseded.
'''
ref = os.path.join(path, 'files', '.ref')
try:
statinfo = os.stat(ref, follow_symlinks=False)
except FileNotFoundError:
with open(ref, 'x'):
pass
else:
if statinfo.st_size > 0 or not stat.S_ISREG(statinfo.st_mode):
raise RuntimeError(
'Expected {} to be an empty regular file'.format(path)
)
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
@staticmethod
def prune_runtime(directory: Path) -> None:
"""
Remove files that are considered to be unnecessary
"""
usr_share = directory / 'files' / 'share'
doc = usr_share / 'doc'
# This is a fairly generic list of files that are safe to be removed.
# Please keep it in sync with prune_files() of steam-runtime.git's
# build-runtime.py
paths: list[Path] = [
# Nvidia cg toolkit manuals, tutorials and documentation
doc / 'nvidia-cg-toolkit' / 'html',
*doc.glob('nvidia-cg-toolkit/*.pdf.gz'),
# Sample code
*doc.glob('**/examples'),
# Debian bug reporting scripts
usr_share / 'bug',
# Debian documentation metadata
usr_share / 'doc-base',
# Debian QA metadata
usr_share / 'lintian',
# Programs and utilities manuals
usr_share / 'man',
# Remove the localized messages that are likely never going to be
# seen. Keep only "en", because that's the default language we are
# using.
*[x for x in usr_share.glob('locale/*') if x.name != 'en'],
]
for path in paths:
if path.is_dir():
shutil.rmtree(path)
else:
with suppress(FileNotFoundError):
path.unlink()
def do_container_runtime(self) -> None:
pv_version = ComponentVersion('pressure-vessel')
self.merge_dir_into_depot(os.path.join(self.source_dir, 'common'))
root = os.path.join(self.source_dir, 'runtimes', self.runtime.name)
if os.path.exists(root):
self.merge_dir_into_depot(root)
pressure_vessel_runtime = self.pressure_vessel_runtime
if self.pressure_vessel_version:
logger.info(
'Downloading standalone pressure-vessel release'
pv_version.version = self.download_pressure_vessel_standalone(
self.pressure_vessel_version
)
else:
assert pressure_vessel_runtime is not None
if pressure_vessel_runtime.path:
self.use_local_pressure_vessel(pressure_vessel_runtime.path)
if pressure_vessel_runtime.official:
pv_version.comment = 'pressure-vessel-bin.tar.gz'
else:
pv_version.comment = 'from local file'
else:
pv_version.comment = (
self.download_pressure_vessel_from_runtime(
pressure_vessel_runtime
)
)
for path in ('metadata/VERSION.txt', 'sources/VERSION.txt'):
full = os.path.join(self.depot, 'pressure-vessel', path)
if os.path.exists(full):
v = text_reader.read().rstrip('\n')
if pv_version.version:
if pv_version.version != v:
raise RuntimeError(
'Inconsistent version! '
'{} says {}, but expected {}'.format(
path, v, pv_version.version,
)
)
else:
pv_version.version = v
if pressure_vessel_runtime is not None:
pv_version.runtime = pressure_vessel_runtime.suite or ''
pv_version.runtime_version = (
pressure_vessel_runtime.pinned_version or ''
)
self.versions.append(pv_version)
if self.unpack_ld_library_path and pressure_vessel_runtime is None:
if self.runtime.name == 'scout':
scout = self.runtime
else:
scout = self.new_runtime(
'scout',
dict(version='latest'),
default_suite='scout',
)
logger.info(
'Downloading LD_LIBRARY_PATH Steam Runtime from scout into %r',
self.unpack_ld_library_path)
self.download_scout_tarball(scout)
elif self.unpack_ld_library_path:
assert pressure_vessel_runtime is not None
logger.info(
'Downloading LD_LIBRARY_PATH Steam Runtime from same place '
'as pressure-vessel into %r',
self.unpack_ld_library_path)
self.download_scout_tarball(pressure_vessel_runtime)
if self.unpack_sources:
logger.info(
'Will download %s source code into %r',
', '.join(self.unpack_sources), self.unpack_sources_into)
os.makedirs(self.unpack_sources_into, exist_ok=True)
os.makedirs(
os.path.join(self.unpack_sources_into, self.runtime.name),
exist_ok=True,
)
for runtime in (self.runtime,): # too much to reindent right now
if runtime.path:
logger.info(
'Using runtime from local directory %r',
runtime.path)
self.use_local_runtime(runtime)
else:
logger.info(
'Downloading runtime from %s',
self.download_runtime(runtime)
component_version = ComponentVersion(runtime.name)
if runtime.path: