[snap] feature -> allowing the user to install an application when a stable channel is not available

This commit is contained in:
Vinicius Moreira
2019-10-22 11:53:56 -03:00
parent 696ce1c79e
commit 98367219dc
12 changed files with 62 additions and 17 deletions

View File

@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.7.1] 2019-
### Features
- Snap:
- if the **stable** channel is not available while an application is being installed, a popup is displayed allowing the user to choose a different one ( e.g: dbeaver-ce )
### Improvements
- 3 password attempts for root authentication
- AUR:

View File

@@ -59,9 +59,6 @@ class SingleSelectComponent(InputViewComponent):
def __init__(self, type_: SelectViewType, label: str, options: List[InputOption], default_option: InputOption = None, max_per_line: int = 1, id_: str = None):
super(SingleSelectComponent, self).__init__(id_=id_)
if options is None or len(options) < 2:
raise Exception("'options' must be a list with at least 2 elements")
self.type = type_
self.label = label
self.options = options

View File

@@ -100,7 +100,7 @@ class ProcessHandler:
if self.watcher:
self.watcher.print(msg)
def handle(self, process: SystemProcess) -> bool:
def handle(self, process: SystemProcess, error_output: StringIO = None) -> bool:
self._notify_watcher(' '.join(process.subproc.args) + '\n')
already_succeeded = False
@@ -126,6 +126,9 @@ class ProcessHandler:
if line:
self._notify_watcher(line)
if error_output is not None:
error_output.write(line)
if process.check_error_output:
if process.wrong_error_phrase and process.wrong_error_phrase in line:
continue

View File

@@ -1,3 +1,4 @@
import re
import time
from datetime import datetime
from threading import Thread
@@ -8,13 +9,15 @@ from bauh.api.abstract.disk import DiskCacheLoader
from bauh.api.abstract.handler import ProcessWatcher
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
SuggestionPriority
from bauh.api.abstract.view import SingleSelectComponent, SelectViewType, InputOption
from bauh.commons.html import bold
from bauh.commons.system import SystemProcess, ProcessHandler
from bauh.commons.system import SystemProcess, ProcessHandler, new_root_subprocess
from bauh.gems.snap import snap, suggestions
from bauh.gems.snap.constants import SNAP_API_URL
from bauh.gems.snap.model import SnapApplication
from bauh.gems.snap.worker import SnapAsyncDataLoader, CategoriesDownloader
RE_AVAILABLE_CHANNELS = re.compile(re.compile(r'(\w+)\s+(snap install.+)'))
class SnapManager(SoftwareManager):
@@ -125,9 +128,31 @@ class SnapManager(SoftwareManager):
raise Exception("'get_history' is not supported by {}".format(pkg.__class__.__name__))
def install(self, pkg: SnapApplication, root_password: str, watcher: ProcessWatcher) -> bool:
res = ProcessHandler(watcher).handle(SystemProcess(subproc=snap.install_and_stream(pkg.name, pkg.confinement, root_password)))
res, output = ProcessHandler(watcher).handle_simple(snap.install_and_stream(pkg.name, pkg.confinement, root_password))
if res:
if 'error:' in output:
res = False
if 'not available on stable' in output:
channels = RE_AVAILABLE_CHANNELS.findall(output)
if channels:
opts = [InputOption(label=c[0], value=c[1]) for c in channels]
channel_select = SingleSelectComponent(type_=SelectViewType.RADIO, label='', options=opts, default_option=opts[0])
if watcher.request_confirmation(title=self.i18n['snap.install.available_channels.title'],
body=self.i18n['snap.install.available_channels.body'].format(bold(self.i18n['stable']), bold(pkg.name)) + ':',
components=[channel_select],
confirmation_label=self.i18n['continue'],
deny_label=self.i18n['cancel']):
self.logger.info("Installing '{}' with the custom command '{}'".format(pkg.name, channel_select.value))
res = ProcessHandler(watcher).handle(SystemProcess(new_root_subprocess(channel_select.value.value.split(' '), root_password=root_password)))
if res:
pkg.has_apps_field = snap.has_apps_field(pkg.name, self.ubuntu_distro)
return res
else:
self.logger.error("Could not find available channels in the installation output: {}".format(output))
else:
pkg.has_apps_field = snap.has_apps_field(pkg.name, self.ubuntu_distro)
return res

View File

@@ -2,4 +2,6 @@ gem.snap.info=Applications published at https://snapcraft.io/store
snap.notification.snapd_unavailable={} seems not to be installed or enabled. {} packages will not be available.
snap.notification.snap.disable=If you do not want to use Snap applications, uncheck {} in {}
snap.action.refresh.status=Refreshing
snap.action.refresh.label=Refresh
snap.action.refresh.label=Refresh
snap.install.available_channels.title=Available channels
snap.install.available_channels.body=There is no {} channel available for {}. But there are these others available below ( select one if you want to continue )

View File

@@ -13,4 +13,6 @@ snap.info.size=tamaño
snap.notification.snapd_unavailable={} no parece estar instalado o habilitado. Los paquetes {} estarán indisponibles.
snap.notification.snap.disable=Si no desea usar aplicativos Snap, desmarque {} en {}
snap.action.refresh.status=Actualizando
snap.action.refresh.label=Actualizar
snap.action.refresh.label=Actualizar
snap.install.available_channels.title=Canales disponibles
snap.install.available_channels.body=No hay un canal {} ( stable ) disponible para {}. Pero hay estos otros disponibles abajo ( seleccione uno si desea continuar )

View File

@@ -13,4 +13,6 @@ snap.info.size=tamanho
snap.notification.snapd_unavailable={} não parece estar instalado ou habilitado. Os pacotes {} estarão indisponíveis.
snap.notification.snap.disable=Se não deseja usar aplicativos Snap, desmarque {} em {}
snap.action.refresh.status=Atualizando
snap.action.refresh.label=Atualizar
snap.action.refresh.label=Atualizar
snap.install.available_channels.title=Canais disponíveis
snap.install.available_channels.body=Não há um canal {} ( stable ) disponível para {}. Porém existem estes outros disponíveis abaixo ( selecione algum se quiser continuar )

View File

@@ -3,7 +3,7 @@ import re
import subprocess
from typing import List
from bauh.commons.system import new_root_subprocess, run_cmd, new_subprocess
from bauh.commons.system import new_root_subprocess, run_cmd, new_subprocess, SimpleProcess
from bauh.gems.snap.model import SnapApplication
BASE_CMD = 'snap'
@@ -176,14 +176,15 @@ def uninstall_and_stream(app_name: str, root_password: str):
return new_root_subprocess([BASE_CMD, 'remove', app_name], root_password)
def install_and_stream(app_name: str, confinement: str, root_password: str) -> subprocess.Popen:
def install_and_stream(app_name: str, confinement: str, root_password: str) -> SimpleProcess:
install_cmd = [BASE_CMD, 'install', app_name] # default
if confinement == 'classic':
install_cmd.append('--classic')
return new_root_subprocess(install_cmd, root_password)
# return new_root_subprocess(install_cmd, root_password)
return SimpleProcess(install_cmd, root_password=root_password)
def downgrade_and_stream(app_name: str, root_password: str) -> subprocess.Popen:

View File

@@ -67,7 +67,7 @@ class ComboBoxQt(QComboBox):
class RadioSelectQt(QGroupBox):
def __init__(self, model: SingleSelectComponent):
super(RadioSelectQt, self).__init__(model.label + ' :')
super(RadioSelectQt, self).__init__(model.label + ' :' if model.label else None)
self.model = model
self.setStyleSheet("QGroupBox { font-weight: bold }")

View File

@@ -141,6 +141,9 @@ filetransfer=file transfer
packagemanager=package manager
sportsgame=sports game
arcadegame=arcade game
player=player
screenshots,download.running=downloading image
screenshots.download.no_content=No content to display
screenshots.download.no_response=Image not found
screenshots.download.no_response=Image not found
continue=continue
stable=stable

View File

@@ -182,8 +182,11 @@ filetransfer=transferencia de archivos
packagemanager=administrador de paquetes
sportsgame=juego de deportes
arcadegame=juego arcade
player=jugador
screenshots.bt_next.label=próxima
screenshots.bt_back.label=anterior
screenshots,download.running=descargando imagen
screenshots.download.no_content=No hay contenido para mostrar
screenshots.download.no_response=Imagen no encontrada
screenshots.download.no_response=Imagen no encontrada
continue=continuar
stable=estable

View File

@@ -185,8 +185,11 @@ viewer=visualizador
packagemanager=gerenciador de pacotes
sportsgame=jogo de esportes
arcadegame=jogo arcade
player=jogador
screenshots.bt_next.label=próxima
screenshots.bt_back.label=anterior
screenshots,download.running=baixando imagem
screenshots.download.no_content=Sem conteúdo para exibir
screenshots.download.no_response=Imagem não encontrada
screenshots.download.no_response=Imagem não encontrada
continue=continuar
stable=estável