[snap] feature -> allowing to select an available channel during the installation process

This commit is contained in:
Vinicius Moreira
2020-09-06 01:10:13 -03:00
parent bf6361a6d1
commit 26fa25cebb
20 changed files with 135 additions and 14 deletions

View File

@@ -350,7 +350,7 @@ class SoftwareManager(ABC):
"""
pass
def save_settings(self, component: ViewComponent) -> Tuple[bool, List[str]]:
def save_settings(self, component: ViewComponent) -> Tuple[bool, Optional[List[str]]]:
"""
:return: a tuple with a bool informing if the settings were saved and a list of error messages
"""

View File

@@ -723,7 +723,7 @@ class AppImageManager(SoftwareManager):
return PanelComponent([FormComponent(updater_opts, self.i18n['appimage.config.db_updates'])])
def save_settings(self, component: PanelComponent) -> Tuple[bool, List[str]]:
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config()
panel = component.components[0]

View File

@@ -2682,7 +2682,7 @@ class ArchManager(SoftwareManager):
return PanelComponent([FormComponent(fields, spaces=False)])
def save_settings(self, component: PanelComponent) -> Tuple[bool, List[str]]:
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config()
form_install = component.components[0]

View File

@@ -5,7 +5,7 @@ from datetime import datetime
from math import floor
from pathlib import Path
from threading import Thread
from typing import List, Set, Type, Tuple
from typing import List, Set, Type, Tuple, Optional
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext, UpgradeRequirements, \
UpgradeRequirement, TransactionResult
@@ -570,7 +570,7 @@ class FlatpakManager(SoftwareManager):
return PanelComponent([FormComponent(fields, self.i18n['installation'].capitalize())])
def save_settings(self, component: PanelComponent) -> Tuple[bool, List[str]]:
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config()
config['installation_level'] = component.components[0].components[0].get_selected()

View File

@@ -1,10 +1,11 @@
import os
from bauh.api.constants import CACHE_PATH
from bauh.api.constants import CACHE_PATH, CONFIG_PATH
from bauh.commons import resource
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
SNAP_CACHE_PATH = CACHE_PATH + '/snap'
CONFIG_FILE = '{}/snap.yml'.format(CONFIG_PATH)
CATEGORIES_FILE_PATH = SNAP_CACHE_PATH + '/categories.txt'
URL_CATEGORIES_FILE = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master/snap/categories.txt'
SUGGESTIONS_FILE = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master/snap/suggestions.txt'

7
bauh/gems/snap/config.py Normal file
View File

@@ -0,0 +1,7 @@
from bauh.commons.config import read_config as read
from bauh.gems.snap import CONFIG_FILE
def read_config(update_file: bool = False) -> dict:
template = {'install_channel': False}
return read(CONFIG_FILE, template, update_file=update_file)

View File

@@ -2,7 +2,7 @@ import re
import time
import traceback
from threading import Thread
from typing import List, Set, Type, Optional
from typing import List, Set, Type, Optional, Tuple
from bauh.api.abstract.controller import SoftwareManager, SearchResult, ApplicationContext, UpgradeRequirements, \
TransactionResult
@@ -10,13 +10,17 @@ from bauh.api.abstract.disk import DiskCacheLoader
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
SuggestionPriority, CustomSoftwareAction, PackageStatus
from bauh.api.abstract.view import SingleSelectComponent, SelectViewType, InputOption
from bauh.api.abstract.view import SingleSelectComponent, SelectViewType, InputOption, ViewComponent, PanelComponent, \
FormComponent
from bauh.commons import resource, internet
from bauh.commons.category import CategoriesDownloader
from bauh.commons.config import save_config
from bauh.commons.html import bold
from bauh.commons.system import SystemProcess, ProcessHandler, new_root_subprocess, get_human_size_str
from bauh.commons.view_utils import new_select
from bauh.gems.snap import snap, URL_CATEGORIES_FILE, SNAP_CACHE_PATH, CATEGORIES_FILE_PATH, SUGGESTIONS_FILE, \
get_icon_path, snapd
get_icon_path, snapd, CONFIG_FILE
from bauh.gems.snap.config import read_config
from bauh.gems.snap.model import SnapApplication
from bauh.gems.snap.snapd import SnapdClient
@@ -175,7 +179,20 @@ class SnapManager(SoftwareManager):
installed_names = {s['name'] for s in SnapdClient(self.logger).list_all_snaps()}
res, output = ProcessHandler(watcher).handle_simple(snap.install_and_stream(pkg.name, pkg.confinement, root_password))
client = SnapdClient(self.logger)
snap_config = read_config()
try:
channel = self._request_channel_installation(pkg=pkg, snap_config=snap_config, snapd_client=client, watcher=watcher)
pkg.channel = channel
except:
watcher.print('Aborted by user')
return TransactionResult.fail()
res, output = ProcessHandler(watcher).handle_simple(snap.install_and_stream(app_name=pkg.name,
confinement=pkg.confinement,
root_password=root_password,
channel=channel))
if 'error:' in output:
res = False
@@ -247,6 +264,8 @@ class SnapManager(SoftwareManager):
task_man.finish_task('snap_cats')
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
Thread(target=read_config, args=(True,), daemon=True).start()
CategoriesDownloader(id_='snap', manager=self, http_client=self.http_client, logger=self.logger,
url_categories_file=URL_CATEGORIES_FILE, disk_cache_dir=SNAP_CACHE_PATH,
categories_path=CATEGORIES_FILE_PATH,
@@ -382,3 +401,56 @@ class SnapManager(SoftwareManager):
def get_screenshots(self, pkg: SnapApplication) -> List[str]:
return pkg.screenshots if pkg.has_screenshots() else []
def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent:
snap_config = read_config()
install_channel = new_select(label=self.i18n['snap.config.install_channel'],
opts=[(self.i18n['yes'].capitalize(), True, None),
(self.i18n['no'].capitalize(), False, None)],
value=bool(snap_config['install_channel']),
id_='install_channel',
max_width=200,
tip=self.i18n['snap.config.install_channel.tip'])
return PanelComponent([FormComponent([install_channel], self.i18n['installation'].capitalize())])
def save_settings(self, component: ViewComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config()
config['install_channel'] = component.components[0].components[0].get_selected()
try:
save_config(config, CONFIG_FILE)
return True, None
except:
return False, [traceback.format_exc()]
def _request_channel_installation(self, pkg: SnapApplication, snap_config: dict, snapd_client: SnapdClient, watcher: ProcessWatcher) -> Optional[str]:
if snap_config['install_channel']:
try:
data = [r for r in snapd_client.find_by_name(pkg.name) if r['name'] == pkg.name]
except:
self.logger.warning("snapd client could not retrieve channels for '{}'".format(pkg.name))
return
if not data:
self.logger.warning("snapd client could find a match for name '{}' when retrieving its channels".format(pkg.name))
else:
if not data[0].get('channels'):
self.logger.info("No channel available for '{}'. Skipping selection.".format(pkg.name))
else:
opts = [InputOption(label=c, value=c) for c in sorted(data[0]['channels'].keys())]
def_opt = [o for o in opts if o.value == 'latest/{}'.format(data[0].get('channel', 'stable'))]
select = SingleSelectComponent(label='',
options=opts,
default_option=def_opt[0] if def_opt else opts[0],
type_=SelectViewType.RADIO)
if not watcher.request_confirmation(title=self.i18n['snap.install.available_channels.title'],
body=self.i18n['snap.install.channel.body'] + ':',
components=[select],
confirmation_label=self.i18n['proceed'].capitalize(),
deny_label=self.i18n['cancel'].capitalize()):
raise Exception('aborted')
else:
return select.get_selected()

View File

@@ -2,6 +2,8 @@ gem.snap.info=Aplicacions publicades a https://snapcraft.io/store
snap.action.refresh.confirm=Actualitza {} ?
snap.action.refresh.label=Actualitza
snap.action.refresh.status=Sestà actualitzant
snap.config.install_channel=Display channels
snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed
snap.info.channel=channel
snap.info.commands=ordres
snap.info.contact=contacte
@@ -18,6 +20,7 @@ snap.info.version=versió
snap.install.available_channels.help=Seleccioneu-ne un si voleu continuar
snap.install.available_channels.message=No hi ha un canal {} (stable) disponible per a {}. Però més avall nhi ha els següents
snap.install.available_channels.title=Canals disponibles
snap.install.channel.body=Select a channel to proceed
snap.notification.snap.disable=Si no voleu utilitzar aplicacions snap, desmarqueu {} a {}
snap.notification.snapd_unavailable=Sembla que no sha iniciat o activat {}. Els paquets {} no estaran disponibles.
snap.notifications.api.unavailable=Sembla que lAPI de {} no està disponible en aquests moments. No podreu cercar aplicacions {} noves.

View File

@@ -2,6 +2,8 @@ gem.snap.info=Anwendungen von https://snapcraft.io/store
snap.action.refresh.confirm=Erneuern {} ?
snap.action.refresh.label=Erneuern
snap.action.refresh.status=Erneuern
snap.config.install_channel=Display channels
snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed
snap.info.channel=channel
snap.info.commands=Kommandos
snap.info.contact=Kontakt
@@ -18,6 +20,7 @@ snap.info.version=Version
snap.install.available_channels.help=Wähle einen aus um fortzufahren
snap.install.available_channels.message=Es ist kein {} Channel verfügbar für {}. Es gibt jedoch folgende
snap.install.available_channels.title=Verfügbare Channels
snap.install.channel.body=Select a channel to proceed
snap.notification.snap.disable=Um keine Snap Anwerndungen zu nutzen deaktivieren {} unter {}
snap.notification.snapd_unavailable={} wurde nicht gestartet oder ist deaktiviert. {} Pakete werden nicht verfügbar sein.
snap.notifications.api.unavailable=Es scheint als ob die {} API aktuell nicht verfügbar ist. Die Suche nach neuen {} Anwendungen ist nicht möglich.

View File

@@ -2,6 +2,8 @@ gem.snap.info=Applications published at https://snapcraft.io/store
snap.action.refresh.confirm=Refresh {} ?
snap.action.refresh.label=Refresh
snap.action.refresh.status=Refreshing
snap.config.install_channel=Display channels
snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed
snap.info.channel=channel
snap.info.commands=commands
snap.info.contact=contact
@@ -18,6 +20,7 @@ snap.info.version=version
snap.install.available_channels.help=Select one if you want to continue
snap.install.available_channels.message=There is no {} channel available for {}. But there are these below
snap.install.available_channels.title=Available channels
snap.install.channel.body=Select a channel to proceed
snap.notification.snap.disable=If you do not want to use Snap applications, uncheck {} in {}
snap.notification.snapd_unavailable={} seems not to be started or enabled. {} packages will not be available.
snap.notifications.api.unavailable=It seems the {} API is unavailable at the moment. It will not be possible to search for new {} applications.

View File

@@ -2,6 +2,8 @@ gem.snap.info=Aplicativos publicados en https://snapcraft.io/store
snap.action.refresh.confirm=Actualizar {} ?
snap.action.refresh.label=Actualizar
snap.action.refresh.status=Actualizando
snap.config.install_channel=Mostrar canales
snap.config.install_channel.tip=Permite seleccionar uno de los canales disponibles para la aplicación a instalar
snap.info.channel=canal
snap.info.commands=comandos
snap.info.contact=contacto
@@ -18,6 +20,7 @@ snap.info.version=versión
snap.install.available_channels.help=Seleccione uno si desea continuar
snap.install.available_channels.message=No hay un canal {} ( stable ) disponible para {}. Pero hay estos otros abajo
snap.install.available_channels.title=Canales disponibles
snap.install.channel.body=Seleccione un canal para continuar
snap.notification.snap.disable=Si no desea usar aplicativos Snap, desmarque {} en {}
snap.notification.snapd_unavailable={} parece no estar inicializado o habilitado. Los paquetes {} estarán indisponibles.
snap.notifications.api.unavailable=Parece que la API de {} no está disponible en este momento. No será posible buscar nuevos aplicativos {}.

View File

@@ -2,6 +2,8 @@ gem.snap.info=Applicazioni pubblicate su https://snapcraft.io/store
snap.action.refresh.confirm=Ripristina {} ?
snap.action.refresh.label=Ripristina
snap.action.refresh.status=Ripristinare
snap.config.install_channel=Display channels
snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed
snap.info.channel=channel
snap.info.commands=commands
snap.info.contact=contact
@@ -18,6 +20,7 @@ snap.info.version=version
snap.install.available_channels.help=Selezionane uno se vuoi continuare
snap.install.available_channels.message=Non esiste un {} canale disponibile per {}. Ma ci sono questi sotto
snap.install.available_channels.title=Canali disponibili
snap.install.channel.body=Select a channel to proceed
snap.notification.snap.disable=Se non si desidera utilizzare le applicazioni Snap, deselezionare {} in {}
snap.notification.snapd_unavailable={} sembra non essere avviato o abilitato. {} i pacchetti non saranno disponibili.
snap.notifications.api.unavailable=Sembra che l'API {} non sia al momento disponibile. Non sarà possibile cercare nuove {} applicazioni.

View File

@@ -2,6 +2,8 @@ gem.snap.info=Aplicativos publicados em https://snapcraft.io/store
snap.action.refresh.confirm=Atualizar {} ?
snap.action.refresh.label=Atualizar
snap.action.refresh.status=Atualizando
snap.config.install_channel=Exibir canais
snap.config.install_channel.tip=Permite-se selecionar um dos canais disponíveis para o aplicativo a ser instalado
snap.info.channel=canal
snap.info.commands=comandos
snap.info.contact=contato
@@ -18,6 +20,7 @@ snap.info.version=versão
snap.install.available_channels.help=Selecione algum se quiser continuar
snap.install.available_channels.message=Não há um canal {} ( stable ) disponível para {}. Porém existem estes outros abaixo
snap.install.available_channels.title=Canais disponíveis
snap.install.channel.body=Selecione um canal para continuar
snap.notification.snap.disable=Se não deseja usar aplicativos Snap, desmarque {} em {}
snap.notification.snapd_unavailable={} parece não estar inicializado ou habilitado. Os pacotes {} estarão indisponíveis.
snap.notifications.api.unavailable=Parece que a API de {} está indisponível no momento. Não será possível buscar novos aplicativos {}.

View File

@@ -2,6 +2,8 @@ gem.snap.info=Приложения, опубликованные на https://sn
snap.action.refresh.confirm=Обновить {} ?
snap.action.refresh.label=Обновить
snap.action.refresh.status=Обновляется
snap.config.install_channel=Display channels
snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed
snap.info.channel=channel
snap.info.commands=Команды
snap.info.contact=Контакт
@@ -18,6 +20,7 @@ snap.info.version=Версия
snap.install.available_channels.help=Выберите один, если вы хотите продолжить
snap.install.available_channels.message=Нет одного канала {}, доступного для {}. Но есть такие ниже
snap.install.available_channels.title=Доступные каналы
snap.install.channel.body=Select a channel to proceed
snap.notification.snap.disable=Если вы не хотите использовать приложения Snap, снимите флажок {} в {}
snap.notification.snapd_unavailable={} кажется, не запускается и не включается. {} пакеты будут недоступны.
snap.notifications.api.unavailable=Похоже, что API {} в данный момент недоступен. Невозможно будет искать новые приложения {}.

View File

@@ -2,6 +2,8 @@ gem.snap.info=https://snapcraft.io/store adresinde yayınlanan uygulamalar
snap.action.refresh.confirm=Yenile {} ?
snap.action.refresh.label=Yenile
snap.action.refresh.status=Yenileniyor
snap.config.install_channel=Display channels
snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed
snap.info.channel=channel
snap.info.commands=komutlar
snap.info.contact=iletişim
@@ -18,6 +20,7 @@ snap.info.version=sürüm
snap.install.available_channels.help=Devam etmek istiyorsanız birini seçin
snap.install.available_channels.message={} için hiçbir {} kanalı yok. Ama aşağıda bunlar var
snap.install.available_channels.title=Kullanılabilir kanallar
snap.install.channel.body=Select a channel to proceed
snap.notification.snap.disable=Snap uygulamalarını kullanmak istemiyorsanız, {} içindeki {} işaretini kaldırın
snap.notification.snapd_unavailable={} başlatılmamış veya etkinleştirilmemiş gibi görünüyor. {} paketler mevcut olmayacak.
snap.notifications.api.unavailable=Görünüşe göre {} API şu anda kullanılamıyor. Yeni {} uygulamaları aramak mümkün olmayacak.

View File

@@ -1,7 +1,7 @@
import os
import subprocess
from io import StringIO
from typing import Tuple
from typing import Tuple, Optional
from bauh.commons.system import run_cmd, SimpleProcess
@@ -18,13 +18,16 @@ def uninstall_and_stream(app_name: str, root_password: str) -> SimpleProcess:
shell=True)
def install_and_stream(app_name: str, confinement: str, root_password: str) -> SimpleProcess:
def install_and_stream(app_name: str, confinement: str, root_password: str, channel: Optional[str] = None) -> SimpleProcess:
install_cmd = [BASE_CMD, 'install', app_name] # default
if confinement == 'classic':
install_cmd.append('--classic')
if channel:
install_cmd.append('--channel={}'.format(channel))
return SimpleProcess(install_cmd, root_password=root_password, shell=True)

View File

@@ -9,7 +9,7 @@ import traceback
from math import floor
from pathlib import Path
from threading import Thread
from typing import List, Type, Set, Tuple
from typing import List, Type, Set, Tuple, Optional
import requests
import yaml
@@ -996,7 +996,7 @@ class WebApplicationManager(SoftwareManager):
return PanelComponent([form_env])
def save_settings(self, component: PanelComponent) -> Tuple[bool, List[str]]:
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config()
form_env = component.components[0]

View File

@@ -266,6 +266,7 @@ class RadioButtonQt(QRadioButton):
self.model = model
self.model_parent = model_parent
self.toggled.connect(self._set_checked)
self.setCursor(QCursor(Qt.PointingHandCursor))
if model.icon_path:
if model.icon_path.startswith('/'):