From cbdaa84bd07555936e7cd558190c96b6ec0b4526 Mon Sep 17 00:00:00 2001 From: Simon McVittie <smcv@collabora.com> Date: Thu, 18 Feb 2021 17:51:01 +0000 Subject: [PATCH] pressure-vessel-test-ui: List archives as possible runtimes Signed-off-by: Simon McVittie <smcv@collabora.com> --- pressure-vessel/pressure-vessel-test-ui | 293 +++++++++++++++++------- 1 file changed, 205 insertions(+), 88 deletions(-) diff --git a/pressure-vessel/pressure-vessel-test-ui b/pressure-vessel/pressure-vessel-test-ui index 9f9b7758d..61f9e5c20 100755 --- a/pressure-vessel/pressure-vessel-test-ui +++ b/pressure-vessel/pressure-vessel-test-ui @@ -81,6 +81,151 @@ def boolean_environment(name, default): return default +class ContainerRuntime: + def __init__( + self, + path, # type: str + home, # type: str + ): # type: (...) -> None + self.home = home + self.path = path + self.description = '' + + +class DirectoryRuntime(ContainerRuntime): + def __init__( + self, + path, # type: str + home, # type: str + ): # type: (...) -> None + super().__init__(path, home=home) + + self.description = self.__describe_runtime(path) + + def __describe_runtime( + self, + path # type: str + ): + # type: (...) -> str + + description = path + files = os.path.join(path, 'files') + metadata = os.path.join(path, 'metadata') + + if os.path.islink(files): + description = os.path.realpath(files) + + if description.startswith(self.home + '/'): + description = '~' + description[len(self.home):] + + name = None # type: typing.Optional[str] + pretty_name = None # type: typing.Optional[str] + build_id = None # type: typing.Optional[str] + variant = None # type: typing.Optional[str] + + try: + keyfile = GLib.KeyFile.new() + keyfile.load_from_file( + metadata, GLib.KeyFileFlags.NONE) + try: + build_id = keyfile.get_string('Runtime', 'x-flatdeb-build-id') + except GLib.Error: + pass + + try: + name = keyfile.get_string('Runtime', 'runtime') + except GLib.Error: + pass + else: + assert name is not None + variant = name.split('.')[-1] + except GLib.Error: + pass + + try: + with open( + os.path.join(files, 'lib', 'os-release') + ) as reader: + for line in reader: + if line.startswith('PRETTY_NAME='): + pretty_name = line.split('=', 1)[1].strip() + pretty_name = GLib.shell_unquote(pretty_name) + elif line.startswith('BUILD_ID='): + build_id = line.split('=', 1)[1].strip() + build_id = GLib.shell_unquote(build_id) + elif line.startswith('VARIANT='): + variant = line.split('=', 1)[1].strip() + variant = GLib.shell_unquote(variant) + except (GLib.Error, EnvironmentError): + pass + + if pretty_name is None: + pretty_name = name + + if pretty_name is None: + pretty_name = os.path.basename(path) + + if build_id is None: + build_id = '' + else: + build_id = ' build {}'.format(build_id) + + if variant is None: + variant = '' + else: + variant = ' {}'.format(variant) + + description = '{}{}{}\n({})'.format( + pretty_name, + variant, + build_id, + description, + ) + + return description + + +class ArchiveRuntime(ContainerRuntime): + def __init__( + self, + path, # type: str + buildid_file, # type: str + home, # type: str + ): # type: (...) -> None + super().__init__(path, home=home) + + if path.startswith(self.home + '/'): + path = '~' + path[len(self.home):] + + description = os.path.basename(path) + sdk_suffix = '' + + if description.startswith('com.valvesoftware.SteamRuntime.'): + description = description[len('com.valvesoftware.SteamRuntime.'):] + + if description.startswith('Platform-'): + description = description[len('Platform-'):] + + if description.startswith('Sdk-'): + sdk_suffix = '-sdk' + description = description[len('Sdk-'):] + + if description.startswith('amd64,i386-'): + description = description[len('amd64,i386-'):] + + if description.endswith('.tar.gz'): + description = description[:-len('.tar.gz')] + + if description.endswith('-runtime'): + description = description[:-len('-runtime')] + + with open(buildid_file) as reader: + build = reader.read().strip() + + self.deploy_id = '{}{}_{}'.format(description, sdk_suffix, build) + self.description = '{} build {}\n({})'.format(description, build, path) + + class Gui: def __init__(self): # type: (...) -> None @@ -88,7 +233,8 @@ class Gui: self.failed = False self.home = GLib.get_home_dir() - self.container_runtimes = {} # type: typing.Dict[str, str] + self.container_runtimes = { + } # type: typing.Dict[str, ContainerRuntime] for search in ( os.getenv('PRESSURE_VESSEL_RUNTIME_BASE'), @@ -115,8 +261,25 @@ class Gui: files = os.path.join(path, 'files') if os.path.isdir(files): - description = self._describe_runtime(path) - self.container_runtimes[path] = description + self.container_runtimes[path] = DirectoryRuntime( + path, + home=self.home, + ) + continue + + if member.endswith(('-runtime.tar.gz', '-sysroot.tar.gz')): + # runtime and sysroot happen to be the same length! + buildid_file = os.path.join( + source_of_runtimes, + member[:-len('-runtime.tar.gz')] + '-buildid.txt', + ) + + if os.path.exists(buildid_file): + self.container_runtimes[path] = ArchiveRuntime( + path, + buildid_file=buildid_file, + home=self.home, + ) self.window = Gtk.Window() self.window.set_default_size(600, 300) @@ -156,8 +319,8 @@ class Gui: 'None (use host system and traditional LD_LIBRARY_PATH runtime)' ) - for path, description in sorted(self.container_runtimes.items()): - self.container_runtime_combo.append(path, description) + for path, runtime in sorted(self.container_runtimes.items()): + self.container_runtime_combo.append(path, runtime.description) if self.container_runtimes: self.container_runtime_combo.set_active(1) @@ -187,6 +350,29 @@ class Gui: assert var_path is not None self.var_path = os.path.realpath(var_path) + + self.gc_runtimes_check = Gtk.CheckButton.new_with_label( + 'Clean up old runtimes' + ) + # Deliberately ignoring PRESSURE_VESSEL_GC_RUNTIMES: a lot of the + # point of this test UI is the ability to switch between runtimes, + # but if we GC non-current runtimes, that'll be really slow. + self.gc_runtimes_check.set_active(False) + self.grid.attach(self.gc_runtimes_check, 1, row, 1, 1) + row += 1 + + label = Gtk.Label.new('') + label.set_markup( + '<small><i>' + 'Normally this is enabled, but this test UI disables it by ' + 'default for quicker switching between multiple runtimes.' + '</i></small>' + ) + label.set_halign(Gtk.Align.START) + label.set_line_wrap(True) + self.grid.attach(label, 1, row, 1, 1) + row += 1 + self.copy_runtime_check = Gtk.CheckButton.new_with_label( 'Create temporary runtime copy on disk' ) @@ -415,93 +601,13 @@ class Gui: def _container_runtime_changed(self, combo): if combo.get_active_id() == '/': self.copy_runtime_check.set_sensitive(False) + self.gc_runtimes_check.set_sensitive(False) self.host_graphics_check.set_sensitive(False) else: self.copy_runtime_check.set_sensitive(True) + self.gc_runtimes_check.set_sensitive(True) self.host_graphics_check.set_sensitive(True) - def _describe_runtime( - self, - path # type: str - ): - # type: (...) -> str - - description = path - files = os.path.join(path, 'files') - metadata = os.path.join(path, 'metadata') - - if os.path.islink(files): - description = os.path.realpath(files) - - if description.startswith(self.home + '/'): - description = '~' + description[len(self.home):] - - name = None # type: typing.Optional[str] - pretty_name = None # type: typing.Optional[str] - build_id = None # type: typing.Optional[str] - variant = None # type: typing.Optional[str] - - try: - keyfile = GLib.KeyFile.new() - keyfile.load_from_file( - metadata, GLib.KeyFileFlags.NONE) - try: - build_id = keyfile.get_string('Runtime', 'x-flatdeb-build-id') - except GLib.Error: - pass - - try: - name = keyfile.get_string('Runtime', 'runtime') - except GLib.Error: - pass - else: - assert name is not None - variant = name.split('.')[-1] - except GLib.Error: - pass - - try: - with open( - os.path.join(files, 'lib', 'os-release') - ) as reader: - for line in reader: - if line.startswith('PRETTY_NAME='): - pretty_name = line.split('=', 1)[1].strip() - pretty_name = GLib.shell_unquote(pretty_name) - elif line.startswith('BUILD_ID='): - build_id = line.split('=', 1)[1].strip() - build_id = GLib.shell_unquote(build_id) - elif line.startswith('VARIANT='): - variant = line.split('=', 1)[1].strip() - variant = GLib.shell_unquote(variant) - except (GLib.Error, EnvironmentError): - pass - - if pretty_name is None: - pretty_name = name - - if pretty_name is None: - pretty_name = os.path.basename(path) - - if build_id is None: - build_id = '' - else: - build_id = ' build {}'.format(build_id) - - if variant is None: - variant = '' - else: - variant = ' {}'.format(variant) - - description = '{}{}{}\n({})'.format( - pretty_name, - variant, - build_id, - description, - ) - - return description - def run_cb(self, _ignored=None): # type: (typing.Any) -> None @@ -519,7 +625,13 @@ class Gui: elif id == '/': argv.append('--runtime=') else: - argv.append('--runtime=' + id) + runtime = self.container_runtimes[id] + + if isinstance(runtime, ArchiveRuntime): + argv.append('--runtime-archive=' + id) + argv.append('--runtime-id=' + runtime.deploy_id) + else: + argv.append('--runtime=' + id) if self.host_graphics_check.get_active(): if os.path.isdir('/run/host'): @@ -536,6 +648,11 @@ class Gui: else: argv.append('--no-copy-runtime') + if self.gc_runtimes_check.get_active(): + argv.append('--gc-runtimes') + else: + argv.append('--no-gc-runtimes') + if self.unshare_home_check.get_active(): argv.append('--unshare-home') else: -- GitLab