def deploy(self): """Prepare remote for deployment Sync the appstream and metadata from the remote. If the deploy URL differs from the pull URL, it's adjusted here, too. """ self._modify_remote_for_deployment() # Set the flatpak remote collection ID if it's enabled and the # remote has a collection ID # Temporarily(?) disable P2P for eos-runtimes (which are legacy). See: # https://phabricator.endlessm.com/T22756#602959 # https://github.com/flatpak/flatpak/issues/1832 if self.enable_p2p_updates and self.name != 'eos-runtimes': repo = self.manager.get_repo() collection_id = fetch_remote_collection_id(repo, self.name) if collection_id is not None: self._set_collection_id(collection_id) # Fetch the deployed remote's appstream and metadata # NOTE: This is done after adding the collection ID so that the # ostree-metadata will be pulled as well, which enables using USB # updates without ever going online logger.info('Updating appstream data for remote %s', self.name) eib.retry(self.installation.update_appstream_sync, self.name, self.arch) logger.info('Updating metadata for remote %s', self.name) eib.retry(self.installation.update_remote_sync, self.name) # Reset any configuration defined metadata self.reset_metadata()
def pull(self, commit_only=False, cache_repo_path=None): """Pull all refs to install Use OSTree to pull all the needed refs to a repository. If commit_only is True, the commit checksums are pulled without creating repository refs. If cache_repo_path points to an ostree repo, it will be used as a local object cache. """ if self.install_refs is None: raise FlatpakError('Must run resolve_refs before pull') # Open the OSTree repo directly repo = self.get_repo() # Figure out common pull options localcache_repos = (cache_repo_path,) if cache_repo_path else () common_pull_options = { 'depth': GLib.Variant('i', 0), 'disable-static-deltas': GLib.Variant('b', True), 'localcache-repos': GLib.Variant('as', localcache_repos), 'inherit-transaction': GLib.Variant('b', True), } repo.prepare_transaction() try: # Pull refs one at a time for ref, install_ref in sorted(self.install_refs.items()): remote = install_ref.full_ref.remote.name # Pull checksum for commit only if commit_only: ref_to_pull = install_ref.full_ref.commit logger.info('Pulling %s ref %s (commit %s)', remote, ref, ref_to_pull) else: ref_to_pull = install_ref.full_ref.ref logger.info('Pulling %s ref %s', remote, ref_to_pull) options = common_pull_options.copy() options['refs'] = GLib.Variant('as', (ref_to_pull,)) if install_ref.subpaths: subdirs = self._subpaths_to_subdirs( install_ref.subpaths) logger.info('Pulling %s ref %s subdirs %s', remote, ref, ' '.join(subdirs)) options.update({ 'subdirs': GLib.Variant('as', subdirs), }) options_var = GLib.Variant('a{sv}', options) self._log_installation_free_space() eib.retry(self._do_pull, repo, remote, options_var, timeout=30) repo.commit_transaction() except: logger.error('Pull failed, aborting transaction') repo.abort_transaction() raise self.installation.drop_caches()
def add(self): """Add this remote to the installation""" # Construct the remote logger.info('Adding flatpak remote %s', self.name) remote = Flatpak.Remote.new(self.name) remote.set_url(self.url) remote.set_gpg_verify(True) if self.title: remote.set_title(self.title) if self.default_branch: remote.set_default_branch(self.default_branch) if self.prio is not None: remote.set_prio(self.prio) # Import the GPG key if specified if self.gpg_key: # Strip any whitespace and decode from base64 gpg_key_decoded = base64.b64decode(self.gpg_key.strip(), validate=True) # Convert to GBytes gpg_key_bytes = GLib.Bytes.new(gpg_key_decoded) remote.set_gpg_key(gpg_key_bytes) # Recent flatpak began automatically adding collection IDs in # certain scenarios, but once they're set they can't change. # Clear any collection ID that might be present since it may not # match the configured URL. remote.set_collection_id(None) # Commit the changes self.installation.modify_remote(remote) # In case the remote metadata update applies a collection ID, # delete any current ostree-metadata ref to ensure flatpak pulls # it again. logger.info('Deleting %s ref for %s', OSTree.REPO_METADATA_REF, self.name) repo = self.manager.get_repo() repo.set_ref_immediate(self.name, OSTree.REPO_METADATA_REF, None) self.installation.drop_caches() # Fetch the deployed remote's metadata logger.info('Updating metadata for remote %s', self.name) eib.retry(self.installation.update_remote_sync, self.name) # Reset any configuration defined metadata self.reset_metadata() # If there's no default branch in the configuration, see if it # was set from the remote metadata if not self.default_branch: remote = self.installation.get_remote_by_name(self.name) self.default_branch = remote.get_default_branch() if self.default_branch: logger.info('Using %s as default branch for remote %s', self.default_branch, self.name)
def enumerate(self): """Populate refs from remote data Fetch the remote's data and create a FlatpakRef for each Flatpak app or runtime found. """ logger.info('Fetching refs for %s', self.name) all_remote_refs = eib.retry( self.installation.list_remote_refs_sync, self.name) for remote_ref in all_remote_refs: # Get the full ostree ref ref = remote_ref.format_ref() logger.debug('Found %s ref %s', self.name, ref) # Get the installed and download size _, download_size, installed_size = eib.retry( self.installation.fetch_remote_size_sync, self.name, remote_ref) # Try to get the runtime and sdk from the flatpak metadata. # We could use GKeyFile as the INI parser, but ConfigParser # is more pleasant from python. # # We disable strict parsing so that it doesn't error on # duplicate sections or options, which flatpak-builder # apparently generates sometimes # (https://phabricator.endlessm.com/T22435). metadata_bytes = eib.retry( self.installation.fetch_remote_metadata_sync, self.name, remote_ref) metadata_str = metadata_bytes.get_data().decode('utf-8') metadata = ConfigParser(strict=False) try: metadata.read_string(metadata_str) except: print('Could not read {} {} metadata:\n{}' .format(self.name, ref, metadata_str), file=sys.stderr) raise # Get all the related refs logger.debug('Getting related refs for %s ref %s', self.name, ref) related = eib.retry( self.installation.list_remote_related_refs_sync, self.name, ref) # Create FlatpakFullRef self.refs[ref] = FlatpakFullRef(remote=self, remote_ref=remote_ref, installed_size=installed_size, download_size=download_size, metadata=metadata, related=related)
def fetch_remote_collection_id(repo, remote): """Fetch the remote's collection ID from its summary file Fetch the remote's summary and look for the ostree.summary.collection-id value in the summary metadata. Return None if no value was found. Args: repo: An open OSTree.Repo remote: The OSTree remote name Returns: The collection ID string or None if one isn't set """ logger.info('Fetching OSTree summary for remote %s', remote) _, summary_bytes, _ = eib.retry(repo.remote_fetch_summary, remote) summary_variant_type = GLib.VariantType.new(OSTree.SUMMARY_GVARIANT_STRING) summary = GLib.Variant.new_from_bytes(summary_variant_type, summary_bytes, False) # Look for collection ID key in the metadata. This is # OSTREE_SUMMARY_COLLECTION_ID in ostree, but that's not exported. summary_metadata = summary[1] collection_id = summary_metadata.get('ostree.summary.collection-id') if collection_id is None: logger.info('No collection ID in %s summary', remote) else: logger.info('Found collection ID "%s" in %s summary', collection_id, remote) return collection_id
def install(self): """Install Flatpak refs Find and order all Flatpak refs needed and install them with the installation. """ if self.install_refs is None: raise FlatpakError('Must run resolve_refs before pull') # Try to order refs so dependencies are installed first. This # simply installs refs with no runtime dependencies first and # assumes flatpak won't error for any issues with extensions # being installed before the ref they extend. refs_with_runtime = [] refs_without_runtime = [] for _, install_ref in sorted(self.install_refs.items()): if install_ref.full_ref.runtime: refs_with_runtime.append(install_ref) else: refs_without_runtime.append(install_ref) refs_to_install = refs_without_runtime + refs_with_runtime for install_ref in refs_to_install: full_ref = install_ref.full_ref logger.info('Installing %s from %s', full_ref.ref, full_ref.remote.name) self._log_installation_free_space() eib.retry(self.installation.install_full, flags=Flatpak.InstallFlags.NO_STATIC_DELTAS | Flatpak.InstallFlags.NO_TRIGGERS, remote_name=full_ref.remote.name, kind=full_ref.kind, name=full_ref.name, arch=full_ref.arch, branch=full_ref.branch, subpaths=install_ref.subpaths) self.installation.run_triggers()