[arch] feature -> AUR: allowing to edit the PKGBUILD file of a package to be installed/upgraded/downgraded

This commit is contained in:
Vinicius Moreira
2020-08-16 12:39:20 -03:00
parent ef6909be38
commit 9c1ffbd356
41 changed files with 811 additions and 205 deletions

View File

@@ -53,14 +53,14 @@ class GenericSoftwareManager(SoftwareManager):
self.config = config
self.settings_manager = settings_manager
self.http_client = context.http_client
self.extra_actions = [CustomSoftwareAction(i18_label_key='action.reset',
self.extra_actions = [CustomSoftwareAction(i18n_label_key='action.reset',
i18n_status_key='action.reset.status',
manager_method='reset',
manager=self,
icon_path=resource.get_path('img/logo.svg'),
requires_root=False,
refresh=False)]
self.dynamic_extra_actions = {CustomSoftwareAction(i18_label_key='action.backups',
self.dynamic_extra_actions = {CustomSoftwareAction(i18n_label_key='action.backups',
i18n_status_key='action.backups.status',
manager_method='launch_timeshift',
manager=self,

View File

@@ -12,6 +12,7 @@ from bauh.api.abstract.download import FileDownloader
from bauh.api.abstract.view import ViewComponent, TabComponent, InputOption, TextComponent, MultipleSelectComponent, \
PanelComponent, FormComponent, TabGroupComponent, SingleSelectComponent, SelectViewType, TextInputComponent, \
FileChooserComponent, RangeInputComponent
from bauh.commons.view_utils import new_select
from bauh.view.core import config, timeshift
from bauh.view.core.config import read_config
from bauh.view.core.downloader import AdaptableFileDownloader
@@ -100,7 +101,7 @@ class GenericSettingsManager:
max_width=default_width,
id_="icon_exp")
select_trim_up = self._gen_select(label=self.i18n['core.config.trim.after_upgrade'],
select_trim_up = new_select(label=self.i18n['core.config.trim.after_upgrade'],
tip=self.i18n['core.config.trim.after_upgrade.tip'],
value=core_config['disk']['trim']['after_upgrade'],
max_width=default_width,
@@ -141,7 +142,7 @@ class GenericSettingsManager:
if current_mthread_client not in available_mthread_clients:
current_mthread_client = None
return self._gen_select(label=self.i18n['core.config.download.multithreaded_client'],
return new_select(label=self.i18n['core.config.download.multithreaded_client'],
tip=self.i18n['core.config.download.multithreaded_client.tip'],
id_="mthread_client",
max_width=default_width,
@@ -293,7 +294,7 @@ class GenericSettingsManager:
max_width=default_width,
id_="sugs_by_type")
inp_reboot = self._gen_select(label=self.i18n['core.config.updates.reboot'],
inp_reboot = new_select(label=self.i18n['core.config.updates.reboot'],
tip=self.i18n['core.config.updates.reboot.tip'],
id_='ask_for_reboot',
max_width=default_width,
@@ -479,64 +480,51 @@ class GenericSettingsManager:
(self.i18n['no'].capitalize(), False, None),
(self.i18n['ask'].capitalize(), None, None)]
install_mode = self._gen_select(label=self.i18n['core.config.backup.install'],
tip=None,
value=core_config['backup']['install'],
opts=ops_opts,
max_width=default_width,
id_='install')
install_mode = new_select(label=self.i18n['core.config.backup.install'],
tip=None,
value=core_config['backup']['install'],
opts=ops_opts,
max_width=default_width,
id_='install')
uninstall_mode = self._gen_select(label=self.i18n['core.config.backup.uninstall'],
tip=None,
value=core_config['backup']['uninstall'],
opts=ops_opts,
max_width=default_width,
id_='uninstall')
uninstall_mode = new_select(label=self.i18n['core.config.backup.uninstall'],
tip=None,
value=core_config['backup']['uninstall'],
opts=ops_opts,
max_width=default_width,
id_='uninstall')
upgrade_mode = self._gen_select(label=self.i18n['core.config.backup.upgrade'],
tip=None,
value=core_config['backup']['upgrade'],
opts=ops_opts,
max_width=default_width,
id_='upgrade')
upgrade_mode = new_select(label=self.i18n['core.config.backup.upgrade'],
tip=None,
value=core_config['backup']['upgrade'],
opts=ops_opts,
max_width=default_width,
id_='upgrade')
downgrade_mode = self._gen_select(label=self.i18n['core.config.backup.downgrade'],
tip=None,
value=core_config['backup']['downgrade'],
opts=ops_opts,
max_width=default_width,
id_='downgrade')
downgrade_mode = new_select(label=self.i18n['core.config.backup.downgrade'],
tip=None,
value=core_config['backup']['downgrade'],
opts=ops_opts,
max_width=default_width,
id_='downgrade')
mode = self._gen_select(label=self.i18n['core.config.backup.mode'],
tip=None,
value=core_config['backup']['mode'],
opts=[
(self.i18n['core.config.backup.mode.incremental'], 'incremental',
self.i18n['core.config.backup.mode.incremental.tip']),
(self.i18n['core.config.backup.mode.only_one'], 'only_one',
self.i18n['core.config.backup.mode.only_one.tip'])
],
max_width=default_width,
id_='mode')
type_ = self._gen_select(label=self.i18n['type'].capitalize(),
tip=None,
value=core_config['backup']['type'],
opts=[('rsync', 'rsync', None), ('btrfs', 'btrfs', None)],
max_width=default_width,
id_='type')
mode = new_select(label=self.i18n['core.config.backup.mode'],
tip=None,
value=core_config['backup']['mode'],
opts=[
(self.i18n['core.config.backup.mode.incremental'], 'incremental',
self.i18n['core.config.backup.mode.incremental.tip']),
(self.i18n['core.config.backup.mode.only_one'], 'only_one',
self.i18n['core.config.backup.mode.only_one.tip'])
],
max_width=default_width,
id_='mode')
type_ = new_select(label=self.i18n['type'].capitalize(),
tip=None,
value=core_config['backup']['type'],
opts=[('rsync', 'rsync', None), ('btrfs', 'btrfs', None)],
max_width=default_width,
id_='type')
sub_comps = [FormComponent([enabled_opt, mode, type_, install_mode, uninstall_mode, upgrade_mode, downgrade_mode], spaces=False)]
return TabComponent(self.i18n['core.config.tab.backup'].capitalize(), PanelComponent(sub_comps), None, 'core.bkp')
def _gen_select(self, label: str, tip: str, id_: str, opts: List[tuple], value: object, max_width: int, type_: SelectViewType = SelectViewType.RADIO):
inp_opts = [InputOption(label=o[0].capitalize(), value=o[1], tooltip=o[2]) for o in opts]
def_opt = [o for o in inp_opts if o.value == value]
return SingleSelectComponent(label=label,
tooltip=tip,
options=inp_opts,
default_option=def_opt[0] if def_opt else inp_opts[0],
max_per_line=len(inp_opts),
max_width=max_width,
type_=type_,
id_=id_)

View File

@@ -12,7 +12,7 @@ from PyQt5.QtWidgets import QTableWidget, QTableView, QMenu, QAction, QTableWidg
from bauh.api.abstract.cache import MemoryCache
from bauh.api.abstract.model import PackageStatus
from bauh.commons.html import strip_html
from bauh.commons.html import strip_html, bold
from bauh.view.qt import dialog
from bauh.view.qt.colors import GREEN, BROWN
from bauh.view.qt.components import IconButton
@@ -167,15 +167,20 @@ class AppsTable(QTableWidget):
if bool(pkg.model.get_custom_supported_actions()):
for action in pkg.model.get_custom_supported_actions():
item = QAction(self.i18n[action.i18_label_key])
item = QAction(self.i18n[action.i18n_label_key])
if action.icon_path:
item.setIcon(QIcon(action.icon_path))
def custom_action():
if action.i18n_confirm_key:
body = self.i18n[action.i18n_confirm_key].format(bold(pkg.model.name))
else:
body = '{} ?'.format(self.i18n[action.i18n_label_key])
if dialog.ask_confirmation(
title=self.i18n[action.i18_label_key],
body=self._parag('{} {} ?'.format(self.i18n[action.i18_label_key], self._bold(str(pkg)))),
title=self.i18n[action.i18n_label_key],
body=self._parag(body),
i18n=self.i18n):
self.window.begin_execute_custom_action(pkg, action)

View File

@@ -7,11 +7,11 @@ from PyQt5.QtCore import Qt, QSize, QTimer
from PyQt5.QtGui import QIcon, QPixmap, QIntValidator, QCursor
from PyQt5.QtWidgets import QRadioButton, QGroupBox, QCheckBox, QComboBox, QGridLayout, QWidget, \
QLabel, QSizePolicy, QLineEdit, QToolButton, QHBoxLayout, QFormLayout, QFileDialog, QTabWidget, QVBoxLayout, \
QSlider, QScrollArea, QFrame, QAction, QSpinBox
QSlider, QScrollArea, QFrame, QAction, QSpinBox, QPlainTextEdit
from bauh.api.abstract.view import SingleSelectComponent, InputOption, MultipleSelectComponent, SelectViewType, \
TextInputComponent, FormComponent, FileChooserComponent, ViewComponent, TabGroupComponent, PanelComponent, \
TwoStateButtonComponent, TextComponent, SpacerComponent, RangeInputComponent, ViewObserver
TwoStateButtonComponent, TextComponent, SpacerComponent, RangeInputComponent, ViewObserver, TextInputType
from bauh.view.qt import css
from bauh.view.qt.colors import RED
from bauh.view.util import resource
@@ -434,7 +434,24 @@ class QLineEditObserver(QLineEdit, ViewObserver):
super(QLineEditObserver, self).__init__(**kwargs)
def on_change(self, change: str):
self.setText(change if change is not None else '')
if self.text() != change:
self.setText(change if change is not None else '')
class QPlainTextEditObserver(QPlainTextEdit, ViewObserver):
def __init__(self, **kwargs):
super(QPlainTextEditObserver, self).__init__(**kwargs)
def on_change(self, change: str):
self.setText(change)
def setText(self, text: str):
if text != self.toPlainText():
self.setPlainText(text if text is not None else '')
def setCursorPosition(self, idx: int):
self.textCursor().setPosition(idx)
class TextInputQt(QGroupBox):
@@ -449,7 +466,7 @@ class TextInputQt(QGroupBox):
if self.model.max_width > 0:
self.setMaximumWidth(self.model.max_width)
self.text_input = QLineEditObserver()
self.text_input = QLineEditObserver() if model.type == TextInputType.SINGLE_LINE else QPlainTextEditObserver()
if model.only_int:
self.text_input.setValidator(QIntValidator())
@@ -469,8 +486,9 @@ class TextInputQt(QGroupBox):
self.model.observers.append(self.text_input)
self.layout().addWidget(self.text_input, 0, 1)
def _update_model(self, text: str):
self.model.set_value(val=text, caller=self)
def _update_model(self, *args):
change = args[0] if args else self.text_input.toPlainText()
self.model.set_value(val=change, caller=self)
class MultipleSelectQt(QGroupBox):
@@ -775,29 +793,29 @@ class FormQt(QGroupBox):
return tip_icon
def _new_text_input(self, c: TextInputComponent) -> Tuple[QLabel, QLineEdit]:
line_edit = QLineEditObserver()
view = QLineEditObserver() if c.type == TextInputType.SINGLE_LINE else QPlainTextEditObserver()
if c.only_int:
line_edit.setValidator(QIntValidator())
view.setValidator(QIntValidator())
if c.tooltip:
line_edit.setToolTip(c.tooltip)
view.setToolTip(c.tooltip)
if c.placeholder:
line_edit.setPlaceholderText(c.placeholder)
view.setPlaceholderText(c.placeholder)
if c.value:
line_edit.setText(str(c.value) if c.value else '')
line_edit.setCursorPosition(0)
view.setText(str(c.value) if c.value else '')
view.setCursorPosition(0)
if c.read_only:
line_edit.setEnabled(False)
view.setEnabled(False)
def update_model(text: str):
c.set_value(val=text, caller=line_edit)
c.set_value(val=text, caller=view)
line_edit.textChanged.connect(update_model)
c.observers.append(line_edit)
view.textChanged.connect(update_model)
c.observers.append(view)
label = QWidget()
label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
@@ -812,7 +830,7 @@ class FormQt(QGroupBox):
if c.tooltip:
label.layout().addWidget(self.gen_tip_icon(c.tooltip))
return label, self._wrap(line_edit, c)
return label, self._wrap(view, c)
def _new_range_input(self, model: RangeInputComponent) -> QSpinBox:
spinner = QSpinBox()

View File

@@ -1394,7 +1394,7 @@ class ManageWindow(QWidget):
def begin_execute_custom_action(self, pkg: PackageView, action: CustomSoftwareAction):
if pkg is None and not dialog.ask_confirmation(title=self.i18n['confirmation'].capitalize(),
body=self.i18n['custom_action.proceed_with'].capitalize().format('"{}"'.format(self.i18n[action.i18_label_key])),
body=self.i18n['custom_action.proceed_with'].capitalize().format('"{}"'.format(self.i18n[action.i18n_label_key])),
icon=QIcon(action.icon_path) if action.icon_path else QIcon(resource.get_path('img/logo.svg')),
i18n=self.i18n):
return False
@@ -1450,7 +1450,7 @@ class ManageWindow(QWidget):
self.settings_window.show()
def _map_custom_action(self, action: CustomSoftwareAction) -> QAction:
custom_action = QAction(self.i18n[action.i18_label_key])
custom_action = QAction(self.i18n[action.i18n_label_key])
if action.icon_path:
try:

View File

@@ -7,128 +7,128 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
height="24"
width="23.515306"
sodipodi:docname="ignore_update.svg"
xml:space="preserve"
viewBox="0 0 23.515307 24"
y="0px"
x="0px"
version="1.1"
id="Capa_1"
version="1.1"><metadata
x="0px"
y="0px"
viewBox="0 0 23.515307 24"
xml:space="preserve"
sodipodi:docname="ignore_update.svg"
width="23.515306"
height="24"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata
id="metadata977"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs975" /><sodipodi:namedview
inkscape:current-layer="Capa_1"
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:cy="15.198259"
inkscape:cx="25.836555"
inkscape:zoom="9.4874926"
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
showborder="true"
showgrid="false"
id="namedview973"
inkscape:window-height="703"
inkscape:window-width="1366"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
pagecolor="#ffffff" />
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="739"
id="namedview973"
showgrid="false"
showborder="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="9.4874926"
inkscape:cx="25.836555"
inkscape:cy="15.198259"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
transform="translate(-99.310818,-31.505501)"
id="g942">
id="g942"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g944">
id="g944"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g946">
id="g946"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g948">
id="g948"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g950">
id="g950"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g952">
id="g952"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g954">
id="g954"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g956">
id="g956"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g958">
id="g958"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g960">
id="g960"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g962">
id="g962"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g964">
id="g964"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g966">
id="g966"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g968">
id="g968"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="translate(-99.310818,-31.505501)"
id="g970">
id="g970"
transform="translate(-99.310818,-31.505501)">
</g>
<g
transform="scale(0.48990007)"
id="g3081"><g
style="fill:#91a069;fill-opacity:1;stroke:#91a069;stroke-width:0.0521502;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.8424663,0,0,1.9956679,0.04804185,-0.95415234)"
id="g6"><path
style="fill:#91a069;fill-opacity:1;stroke:#91a069;stroke-width:0.0521502;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0"
id="g982"><g
id="g6"
transform="matrix(0.90262437,0,0,0.97767784,0.02353571,-0.4674393)"
style="fill:#91a069;fill-opacity:1;stroke:#91a069;stroke-width:0.0521502;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"><path
d="m 25,17 h -2 c -0.6,0 -1,0.4 -1,1 v 2.5 C 22,20.8 21.8,21 21.5,21 H 4.5 C 4.2,21 4,20.8 4,20.5 V 18 C 4,17.4 3.6,17 3,17 H 1 c -0.6,0 -1,0.4 -1,1 v 6 c 0,0.6 0.4,1 1,1 h 24 c 0.6,0 1,-0.4 1,-1 v -6 c 0,-0.6 -0.4,-1 -1,-1 z"
id="path2"
d="m 25,17 h -2 c -0.6,0 -1,0.4 -1,1 v 2.5 C 22,20.8 21.8,21 21.5,21 H 4.5 C 4.2,21 4,20.8 4,20.5 V 18 C 4,17.4 3.6,17 3,17 H 1 c -0.6,0 -1,0.4 -1,1 v 6 c 0,0.6 0.4,1 1,1 h 24 c 0.6,0 1,-0.4 1,-1 v -6 c 0,-0.6 -0.4,-1 -1,-1 z" /><path
style="fill:#91a069;fill-opacity:1;stroke:#91a069;stroke-width:0.0521502;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0"
style="fill:#91a069;fill-opacity:1;stroke:#91a069;stroke-width:0.0521502;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><path
d="m 12.3,16.7 c 0.2,0.2 0.5,0.3 0.7,0.3 0.2,0 0.5,-0.1 0.7,-0.3 l 6,-6 C 19.9,10.5 20,10.3 20,10 20,9.7 19.9,9.5 19.7,9.3 L 18.3,7.9 C 18.1,7.7 17.9,7.6 17.6,7.6 c -0.3,0 -0.5,0.1 -0.7,0.3 l -1,1 C 15.6,9.2 15,9 15,8.5 V 2 C 15,1.4 14.6,1 14,1 H 12 C 11.4,1 11,1.4 11,2 V 8.6 C 11,9 10.5,9.3 10.1,9 L 9.1,8 C 8.9,7.8 8.7,7.7 8.4,7.7 8.1,7.7 7.9,7.8 7.7,8 L 6.3,9.4 C 6.1,9.6 6,9.8 6,10.1 c 0,0.3 0.1,0.5 0.3,0.7 z"
id="path4"
d="m 12.3,16.7 c 0.2,0.2 0.5,0.3 0.7,0.3 0.2,0 0.5,-0.1 0.7,-0.3 l 6,-6 C 19.9,10.5 20,10.3 20,10 20,9.7 19.9,9.5 19.7,9.3 L 18.3,7.9 C 18.1,7.7 17.9,7.6 17.6,7.6 c -0.3,0 -0.5,0.1 -0.7,0.3 l -1,1 C 15.6,9.2 15,9 15,8.5 V 2 C 15,1.4 14.6,1 14,1 H 12 C 11.4,1 11,1.4 11,2 V 8.6 C 11,9 10.5,9.3 10.1,9 L 9.1,8 C 8.9,7.8 8.7,7.7 8.4,7.7 8.1,7.7 7.9,7.8 7.7,8 L 6.3,9.4 C 6.1,9.6 6,9.8 6,10.1 c 0,0.3 0.1,0.5 0.3,0.7 z" /></g><g
id="g940"
inkscape:connector-curvature="0"
style="fill:#91a069;fill-opacity:1;stroke:#91a069;stroke-width:0.0521502;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></g><g
transform="matrix(-0.05511385,0,0,0.05511385,23.515284,-1.6640481e-7)"
style="fill:#ff0000"
transform="matrix(0.11250018,0,0,0.11250018,4.659997e-5,-3.3967093e-7)">
id="g940">
<g
id="g938"
style="fill:#ff0000">
style="fill:#ff0000"
id="g938">
<path
d="M 213.333,0 C 95.467,0 0,95.467 0,213.333 0,331.199 95.467,426.666 213.333,426.666 331.199,426.666 426.667,331.2 426.667,213.333 426.667,95.466 331.2,0 213.333,0 Z M 42.667,213.333 c 0,-94.293 76.373,-170.667 170.667,-170.667 39.467,0 75.627,13.547 104.533,35.947 L 78.613,317.867 C 56.213,288.96 42.667,252.8 42.667,213.333 Z M 213.333,384 C 173.866,384 137.706,370.453 108.8,348.053 L 348.053,108.8 C 370.453,137.707 384,173.867 384,213.333 384,307.627 307.627,384 213.333,384 Z"
style="fill:#ff0000"
id="path936"
style="fill:#ff0000" />
d="M 213.333,0 C 95.467,0 0,95.467 0,213.333 0,331.199 95.467,426.666 213.333,426.666 331.199,426.666 426.667,331.2 426.667,213.333 426.667,95.466 331.2,0 213.333,0 Z M 42.667,213.333 c 0,-94.293 76.373,-170.667 170.667,-170.667 39.467,0 75.627,13.547 104.533,35.947 L 78.613,317.867 C 56.213,288.96 42.667,252.8 42.667,213.333 Z M 213.333,384 C 173.866,384 137.706,370.453 108.8,348.053 L 348.053,108.8 C 370.453,137.707 384,173.867 384,213.333 384,307.627 307.627,384 213.333,384 Z" />
</g>
</g></g></svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB