pamac-classic/pamac/transaction.py
2014-02-01 15:39:58 +01:00

862 lines
29 KiB
Python

#! /usr/bin/python3
# -*- coding:utf-8 -*-
# pamac - A Python implementation of alpm
# Copyright (C) 2013-2014 Guillaume Benoit <guillaume@manjaro.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import pyalpm
from gi.repository import Gtk, GObject
from time import sleep
import subprocess
import os
import fnmatch
#import requests
#from ftplib import FTP
#from urllib.parse import urlparse
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import signal
from pamac import config, common, aur
to_remove = set()
to_add = set()
to_mark_as_dep = set()
to_update = set()
to_load = set()
available_updates = (False, [])
to_build = []
cancel_download = False
build_proc = None
make_depends = set()
base_devel = ('autoconf', 'automake', 'binutils', 'bison', 'fakeroot',
'file', 'findutils', 'flex', 'gawk', 'gcc', 'gettext',
'grep', 'groff', 'gzip', 'libtool', 'm4', 'make', 'patch',
'pkg-config', 'sed', 'sudo', 'texinfo', 'util-linux', 'which')
build_depends = set()
handle = None
syncdbs = None
localdb = None
# i18n
import gettext
import locale
locale.bindtextdomain('pamac', '/usr/share/locale')
gettext.bindtextdomain('pamac', '/usr/share/locale')
gettext.textdomain('pamac')
_ = gettext.gettext
interface = Gtk.Builder()
interface.set_translation_domain('pamac')
interface.add_from_file('/usr/share/pamac/gui/dialogs.ui')
ErrorDialog = interface.get_object('ErrorDialog')
WarningDialog = interface.get_object('WarningDialog')
#InfoDialog = interface.get_object('InfoDialog')
QuestionDialog = interface.get_object('QuestionDialog')
ConfDialog = interface.get_object('ConfDialog')
transaction_sum = interface.get_object('transaction_sum')
sum_top_label = interface.get_object('sum_top_label')
sum_bottom_label = interface.get_object('sum_bottom_label')
ChooseDialog = interface.get_object('ChooseDialog')
choose_list = interface.get_object('choose_list')
choose_label = interface.get_object('choose_label')
choose_renderertoggle = interface.get_object('choose_renderertoggle')
ProgressWindow = interface.get_object('ProgressWindow')
progress_bar = interface.get_object('progressbar2')
progress_label = interface.get_object('progresslabel2')
action_icon = interface.get_object('action_icon')
ProgressCancelButton = interface.get_object('ProgressCancelButton')
ProgressCloseButton = interface.get_object('ProgressCloseButton')
progress_expander = interface.get_object('progress_expander')
progress_textview = interface.get_object('progress_textview')
PreferencesWindow = interface.get_object('PreferencesWindow')
EnableAURButton = interface.get_object('EnableAURButton')
RemoveUnrequiredDepsButton = interface.get_object('RemoveUnrequiredDepsButton')
RefreshPeriodSpinButton = interface.get_object('RefreshPeriodSpinButton')
RefreshPeriodLabel = interface.get_object('RefreshPeriodLabel')
# Do it for transalation ease
RefreshPeriodLabel.set_markup(_('How often to check for updates, value in hours')+':')
progress_buffer = progress_textview.get_buffer()
DBusGMainLoop(set_as_default = True)
bus = dbus.SystemBus()
def get_dbus_methods():
proxy = bus.get_object('org.manjaro.pamac','/org/manjaro/pamac', introspect = False)
global Refresh
global CheckUpdates
global Init
global Sysupgrade
global Remove
global Add
global Load
global Prepare
global To_Remove
global To_Add
global Commit
global Interrupt
global Release
global StopDaemon
global SetPkgReason
global WriteConfig
SetPkgReason = proxy.get_dbus_method('SetPkgReason','org.manjaro.pamac')
Refresh = proxy.get_dbus_method('Refresh','org.manjaro.pamac')
CheckUpdates = proxy.get_dbus_method('CheckUpdates','org.manjaro.pamac')
Init = proxy.get_dbus_method('Init','org.manjaro.pamac')
Sysupgrade = proxy.get_dbus_method('Sysupgrade','org.manjaro.pamac')
Remove = proxy.get_dbus_method('Remove','org.manjaro.pamac')
Add = proxy.get_dbus_method('Add','org.manjaro.pamac')
Load = proxy.get_dbus_method('Load','org.manjaro.pamac')
Prepare = proxy.get_dbus_method('Prepare','org.manjaro.pamac')
To_Remove = proxy.get_dbus_method('To_Remove','org.manjaro.pamac')
To_Add = proxy.get_dbus_method('To_Add','org.manjaro.pamac')
Commit = proxy.get_dbus_method('Commit','org.manjaro.pamac')
Interrupt = proxy.get_dbus_method('Interrupt','org.manjaro.pamac')
Release = proxy.get_dbus_method('Release','org.manjaro.pamac')
StopDaemon = proxy.get_dbus_method('StopDaemon','org.manjaro.pamac')
WriteConfig = proxy.get_dbus_method('WriteConfig','org.manjaro.pamac')
def config_dbus_signals():
bus.add_signal_receiver(action_handler, dbus_interface = "org.manjaro.pamac", signal_name = "EmitAction")
bus.add_signal_receiver(action_long_handler, dbus_interface = "org.manjaro.pamac", signal_name = "EmitActionLong")
bus.add_signal_receiver(icon_handler, dbus_interface = "org.manjaro.pamac", signal_name = "EmitIcon")
bus.add_signal_receiver(target_handler, dbus_interface = "org.manjaro.pamac", signal_name = "EmitTarget")
bus.add_signal_receiver(percent_handler, dbus_interface = "org.manjaro.pamac", signal_name = "EmitPercent")
bus.add_signal_receiver(need_details_handler, dbus_interface = "org.manjaro.pamac", signal_name = "EmitNeedDetails")
bus.add_signal_receiver(transaction_start_handler, dbus_interface = "org.manjaro.pamac", signal_name = "EmitTransactionStart")
bus.add_signal_receiver(log_error, dbus_interface = "org.manjaro.pamac", signal_name = "EmitLogError")
bus.add_signal_receiver(log_warning, dbus_interface = "org.manjaro.pamac", signal_name = "EmitLogWarning")
def action_handler(action):
progress_label.set_text(action)
def action_long_handler(action_long):
global progress_buffer
end_iter = progress_buffer.get_end_iter()
progress_buffer.insert(end_iter, action_long)
def need_details_handler(need):
progress_expander.set_expanded(need)
def icon_handler(icon):
action_icon.set_from_file(icon)
def target_handler(target):
progress_bar.set_text(target)
def percent_handler(percent):
if percent > 1:
progress_bar.pulse()
else:
progress_bar.set_fraction(percent)
def transaction_start_handler(msg):
ProgressCancelButton.set_visible(False)
def log_error(msg):
ErrorDialog.format_secondary_text(msg)
response = ErrorDialog.run()
while Gtk.events_pending():
Gtk.main_iteration()
if response:
ErrorDialog.hide()
def log_warning(msg):
WarningDialog.format_secondary_text(msg)
response = WarningDialog.run()
while Gtk.events_pending():
Gtk.main_iteration()
if response:
WarningDialog.hide()
def choose_provides(data):
virtual_dep = str(data[1])
providers = data[0]
choose_label.set_markup('<b>{}</b>'.format(_('{pkgname} is provided by {number} packages.\nPlease choose those you would like to install:').format(pkgname = virtual_dep, number = str(len(providers)))))
choose_list.clear()
for name in providers:
choose_list.append([False, str(name)])
lenght = len(to_add)
ChooseDialog.run()
if len(to_add) == lenght: # no choice was done by the user
to_add.add(choose_list.get(choose_list.get_iter_first(), 1)[0]) # add first provider
def on_choose_renderertoggle_toggled(widget, line):
choose_list[line][0] = not choose_list[line][0]
def on_ChooseButton_clicked(*args):
ChooseDialog.hide()
while Gtk.events_pending():
Gtk.main_iteration()
for row in choose_list:
if row[0] is True:
to_add.add(row[1].split(':')[0]) # split done in case of optdep choice
def on_progress_textview_size_allocate(*args):
#auto-scrolling method
adj = progress_textview.get_vadjustment()
adj.set_value(adj.get_upper() - adj.get_page_size())
def on_PreferencesValidButton_clicked(*args):
data = []
if EnableAURButton.get_active() != config.enable_aur:
data.append(('EnableAUR', str(EnableAURButton.get_active())))
if RemoveUnrequiredDepsButton.get_active() != config.recurse:
data.append(('RemoveUnrequiredDeps', str(RemoveUnrequiredDepsButton.get_active())))
if RefreshPeriodSpinButton.get_value() != config.refresh_period:
data.append(('RefreshPeriod', str(RefreshPeriodSpinButton.get_value_as_int())))
if data:
WriteConfig(data)
PreferencesWindow.hide()
def on_PreferencesCloseButton_clicked(*args):
PreferencesWindow.hide()
def on_PreferencesWindow_delete_event(*args):
PreferencesWindow.hide()
# return True is needed to not destroy the window
return True
def get_handle():
global handle
global syncdbs
global localdb
handle = config.handle()
syncdbs = handle.get_syncdbs()
localdb = handle.get_localdb()
def get_localpkg(name):
return localdb.get_pkg(name)
def get_syncpkg(name):
for repo in syncdbs:
pkg = repo.get_pkg(name)
if pkg:
return pkg
def refresh(force_update = False):
while Gtk.events_pending():
Gtk.main_iteration()
action_handler(_('Refreshing')+'...')
icon_handler('/usr/share/pamac/icons/24x24/status/refresh-cache.png')
target_handler('')
percent_handler(0)
ProgressCancelButton.set_visible(True)
ProgressCloseButton.set_visible(False)
progress_expander.set_visible(True)
ProgressWindow.show()
while Gtk.events_pending():
Gtk.main_iteration()
Refresh(force_update)
def init_transaction(**options):
return Init(dbus.Dictionary(options, signature='sb'))
def check_to_build():
global to_build
global to_add
global to_mark_as_dep
global make_depends
global build_depends
make_depends = set()
builds_depends = set()
# check if base_devel packages are installed
for name in base_devel:
if not pyalpm.find_satisfier(localdb.pkgcache, name):
make_depends.add(name)
already_checked = set()
build_order = []
i = 0
error = ''
while i < len(to_build):
while Gtk.events_pending():
Gtk.main_iteration()
pkg = to_build[i]
# if current pkg is not in build_order add it at the end of the list
if not pkg.name in build_order:
build_order.append(pkg.name)
# download end extract tarball from AUR
srcdir = aur.get_extract_tarball(pkg)
if srcdir:
# get PKGBUILD and parse it to create a new pkg object with makedeps and deps
new_pkgs = aur.get_pkgs(srcdir + '/PKGBUILD')
for new_pkg in new_pkgs:
while Gtk.events_pending():
Gtk.main_iteration()
print('checking', new_pkg.name)
# check if some makedeps must be installed
for makedepend in new_pkg.makedepends:
while Gtk.events_pending():
Gtk.main_iteration()
if not makedepend in already_checked:
if not pyalpm.find_satisfier(localdb.pkgcache, makedepend):
print('found make dep:',makedepend)
for db in syncdbs:
provider = pyalpm.find_satisfier(db.pkgcache, makedepend)
if provider:
break
if provider:
make_depends.add(provider.name)
already_checked.add(makedepend)
else:
# current makedep need to be built
raw_makedepend = common.format_pkg_name(makedepend)
if raw_makedepend in build_order:
# add it in build_order before pkg
build_order.remove(raw_makedepend)
index = build_order.index(pkg.name)
build_order.insert(index, raw_makedepend)
else:
# get infos about it
makedep_pkg = aur.info(raw_makedepend)
if makedep_pkg:
# add it in to_build so it will be checked
to_build.append(makedep_pkg)
# add it in build_order before pkg
index = build_order.index(pkg.name)
build_order.insert(index, raw_makedepend)
# add it in already_checked and to_add_as_as_dep
already_checked.add(raw_makedepend)
to_mark_as_dep.add(raw_makedepend)
else:
if error:
error += '\n'
error += _('{pkgname} depends on {dependname} but it is not installable').format(pkgname = pkg.name, dependname = makedepend)
# check if some deps must be installed or built
for depend in new_pkg.depends:
while Gtk.events_pending():
Gtk.main_iteration()
if not depend in already_checked:
if not pyalpm.find_satisfier(localdb.pkgcache, depend):
print('found dep:',depend)
for db in syncdbs:
provider = pyalpm.find_satisfier(db.pkgcache, depend)
if provider:
break
if provider:
# current dep need to be installed
build_depends.add(provider.name)
already_checked.add(depend)
else:
# current dep need to be built
raw_depend = common.format_pkg_name(depend)
if raw_depend in build_order:
# add it in build_order before pkg
build_order.remove(raw_depend)
index = build_order.index(pkg.name)
build_order.insert(index, raw_depend)
else:
# get infos about it
dep_pkg = aur.info(raw_depend)
if dep_pkg:
# add it in to_build so it will be checked
to_build.append(dep_pkg)
# add it in build_order before pkg
index = build_order.index(pkg.name)
build_order.insert(index, raw_depend)
# add it in already_checked and to_add_as_as_dep
already_checked.add(raw_depend)
to_mark_as_dep.add(raw_depend)
else:
if error:
error += '\n'
error += _('{pkgname} depends on {dependname} but it is not installable').format(pkgname = pkg.name, dependname = depend)
else:
if error:
error += '\n'
error += _('Failed to get {pkgname} archive from AUR').format(pkgname = pkg.name)
i += 1
if error:
return error
# add pkgname in make_depends and build_depends in to_add and to_mark_as_dep
for name in make_depends:
to_add.add(name)
to_mark_as_dep.add(name)
for name in build_depends:
to_add.add(name)
to_mark_as_dep.add(name)
# reorder to_build following build_order
to_build.sort(key = lambda pkg: build_order.index(pkg.name))
#print('order:', build_order)
print('to build:',to_build)
print('makedeps:',make_depends)
print('builddeps:',build_depends)
return error
def run(cascade = True, recurse = False):
if to_add or to_remove or to_load or to_build:
global progress_buffer
action_handler(_('Preparing')+'...')
icon_handler('/usr/share/pamac/icons/24x24/status/package-setup.png')
target_handler('')
percent_handler(0)
progress_buffer.delete(progress_buffer.get_start_iter(), progress_buffer.get_end_iter())
ProgressCancelButton.set_visible(False)
ProgressCloseButton.set_visible(False)
progress_expander.set_visible(True)
ProgressWindow.show()
while Gtk.events_pending():
Gtk.main_iteration()
# we need to give some time to the window to refresh
sleep(0.1)
error = ''
if to_build:
# check if packages in to_build have deps or makedeps which need to be install first
error += check_to_build()
if not error:
if to_add or to_remove or to_load:
ProgressCancelButton.set_visible(True)
while Gtk.events_pending():
Gtk.main_iteration()
trans_flags = {'cascade': cascade, 'recurse': recurse}
error += init_transaction(**trans_flags)
if not error:
for name in to_add:
error += Add(name)
for name in to_remove:
error += Remove(name)
for path in to_load:
error += Load(path)
if not error:
error += prepare(**trans_flags)
if not error:
set_transaction_sum()
ConfDialog.show_all()
while Gtk.events_pending():
Gtk.main_iteration()
if error:
ProgressWindow.hide()
Release()
return(error)
else:
return (_('Nothing to do'))
def prepare(**trans_flags):
error = ''
ret = Prepare()
# ret type is a(ass) so [([''], '')]
if ret[0][0]: # providers are emitted
Release()
for item in ret:
choose_provides(item)
error += init_transaction(**trans_flags)
if not error:
for name in to_add:
error += Add(name)
for name in to_remove:
error += Remove(name)
for path in to_load:
error += Load(path)
if not error:
ret = Prepare()
if ret[0][1]:
error = str(ret[0][1])
elif ret[0][1]: # an error is emitted
error = str(ret[0][1])
return(error)
def check_finished_build(data):
def handle_timeout(*args):
raise Exception('timeout')
def no_handle_timeout(*args):
try:
pass
except:
pass
global to_build
global build_proc
path = data[0]
pkg = data[1]
if build_proc.poll() is None:
# Build no finished : read stdout to push it to text_buffer
# add a timeout to stop reading stdout if too long
# so the gui won't freeze
signal.signal(signal.SIGALRM, handle_timeout)
signal.setitimer(signal.ITIMER_REAL, 0.05) # 50 ms timeout
try:
line = build_proc.stdout.readline().decode(encoding='UTF-8')
#print(line.rstrip('\n'))
progress_buffer.insert_at_cursor(line)
except Exception:
pass
else:
signal.signal(signal.SIGALRM, no_handle_timeout)
finally:
progress_bar.pulse()
while Gtk.events_pending():
Gtk.main_iteration()
return True
elif build_proc.poll() == 0:
# Build successfully finished
built = []
# parse again PKGBUILD to have new pkg objects in case of a pkgver() function
# was used so pkgver was changed during build process
new_pkgs = aur.get_pkgs(path + '/PKGBUILD')
# find built packages
for new_pkg in new_pkgs:
for item in os.listdir(path):
if os.path.isfile(os.path.join(path, item)):
# add a * before pkgver if there an epoch variable
if fnmatch.fnmatch(item, '{}-*{}-*.pkg.tar.?z'.format(new_pkg.name, new_pkg.version)):
built.append(os.path.join(path, item))
break
if built:
print('successfully built:', built)
build_proc = None
if pkg in to_build:
to_build.remove(pkg)
# install built packages
error = ''
error += init_transaction()
if not error:
for pkg_path in built:
error += Load(pkg_path)
if not error:
error += prepare()
if not error:
if To_Remove():
set_transaction_sum()
ConfDialog.show_all()
while Gtk.events_pending():
Gtk.main_iteration()
else:
finalize()
if error:
Release()
ProgressCancelButton.set_visible(False)
ProgressCloseButton.set_visible(True)
ErrorDialog.format_secondary_text(error)
response = ErrorDialog.run()
if response:
ErrorDialog.hide()
else:
ProgressCancelButton.set_visible(False)
ProgressCloseButton.set_visible(True)
action_long_handler(_('Build process failed.'))
return False
elif build_proc.poll() == 1:
# Build finish with an error
ProgressCancelButton.set_visible(False)
ProgressCloseButton.set_visible(True)
action_long_handler(_('Build process failed.'))
return False
def download(url_list, path):
def write_file(chunk):
nonlocal transferred
nonlocal f
if cancel_download:
if ftp:
ftp.quit()
raise Exception('Download cancelled')
return
f.write(chunk)
transferred += len(chunk)
if total_size > 0:
percent = round(transferred/total_size, 2)
percent_handler(percent)
if transferred <= total_size:
target = '{transferred}/{size}'.format(transferred = common.format_size(transferred), size = common.format_size(total_size))
else:
target = ''
target_handler(target)
while Gtk.events_pending():
Gtk.main_iteration()
global cancel_download
cancel_download = False
ftp = None
total_size = 0
transferred = 0
icon_handler('/usr/share/pamac/icons/24x24/status/package-download.png')
ProgressCancelButton.set_visible(True)
ProgressCloseButton.set_visible(False)
parsed_urls = []
for url in url_list:
url_components = urlparse(url)
if url_components.scheme:
parsed_urls.append(url_components)
print(parsed_urls)
for url_components in parsed_urls:
if url_components.scheme == 'http':
total_size += int(requests.get(url).headers['Content-Length'])
elif url_components.scheme == 'ftp':
ftp = FTP(url_components.netloc)
ftp.login('anonymous', '')
total_size += int(ftp.size(url_components.path))
print(total_size)
for url_components in parsed_urls:
filename = url_components.path.split('/')[-1]
print(filename)
action = _('Downloading {pkgname}').format(pkgname = filename)+'...'
action_long = action+'\n'
action_handler(action)
action_long_handler(action_long)
ProgressWindow.show()
while Gtk.events_pending():
Gtk.main_iteration()
with open(os.path.join(path, filename), 'wb') as f:
if url_components.scheme == 'http':
try:
r = requests.get(url, stream = True)
for chunk in r.iter_content(1024):
if cancel_download:
raise Exception('Download cancelled')
break
else:
write_file(chunk)
except Exception as e:
print(e)
cancel_download = False
elif url_components.scheme == 'ftp':
try:
ftp = FTP(url_components.netloc)
ftp.login('anonymous', '')
ftp.retrbinary('RETR '+url_components.path, write_file, blocksize=1024)
except Exception as e:
print(e)
cancel_download = False
def build_next():
global build_proc
pkg = to_build[0]
path = os.path.join(aur.srcpkgdir, pkg.name)
new_pkgs = aur.get_pkgs(path + '/PKGBUILD')
# sources are identicals for splitted packages
# (not complete) download(new_pkgs[0].source, path)
action = _('Building {pkgname}').format(pkgname = pkg.name)+'...'
action_handler(action)
action_long_handler(action+'\n')
icon_handler('/usr/share/pamac/icons/24x24/status/package-setup.png')
target_handler('')
percent_handler(0)
ProgressCancelButton.set_visible(True)
ProgressCloseButton.set_visible(False)
progress_expander.set_visible(True)
progress_expander.set_expanded(True)
ProgressWindow.show()
build_proc = subprocess.Popen(["makepkg", "-cf"], cwd = path, stdout = subprocess.PIPE, stderr=subprocess.STDOUT)
while Gtk.events_pending():
Gtk.main_iteration()
GObject.timeout_add(100, check_finished_build, (path, pkg))
def finalize():
if To_Add() or To_Remove():
try:
Commit()
except dbus.exceptions.DBusException as e:
Release()
elif to_build:
# packages in to_build have no deps or makedeps
# so we build and install the first one
# the next ones will be built by the caller
build_next()
def mark_needed_pkgs_as_dep():
global to_mark_as_dep
for name in to_mark_as_dep.copy():
if get_localpkg(name):
error = SetPkgReason(name, pyalpm.PKG_REASON_DEPEND)
if error:
print(error)
else:
to_mark_as_dep.discard(name)
def get_updates():
while Gtk.events_pending():
Gtk.main_iteration()
action_handler(_('Checking for updates')+'...')
icon_handler('/usr/share/pamac/icons/24x24/status/package-search.png')
target_handler('')
percent_handler(0)
ProgressCancelButton.set_visible(False)
ProgressCloseButton.set_visible(False)
progress_expander.set_visible(False)
ProgressWindow.show()
while Gtk.events_pending():
Gtk.main_iteration()
CheckUpdates()
def get_transaction_sum():
transaction_dict = {'to_remove': [], 'to_build': [], 'to_install': [], 'to_update': [], 'to_reinstall': [], 'to_downgrade': []}
for pkg in to_build:
transaction_dict['to_build'].append(pkg.name+' '+pkg.version)
_to_remove = sorted(To_Remove())
for name, version in _to_remove:
transaction_dict['to_remove'].append(name+' '+version)
others = sorted(To_Add())
for name, version, dsize in others:
pkg = get_localpkg(name)
if pkg:
comp = pyalpm.vercmp(version, pkg.version)
if comp == 1:
transaction_dict['to_update'].append((name+' '+version, dsize))
elif comp == 0:
transaction_dict['to_reinstall'].append((name+' '+version, dsize))
elif comp == -1:
transaction_dict['to_downgrade'].append((name+' '+version, dsize))
else:
transaction_dict['to_install'].append((name+' '+version, dsize))
#~ if transaction_dict['to_build']:
#~ print('To build:', [name for name in transaction_dict['to_build']])
#~ if transaction_dict['to_install']:
#~ print('To install:', [name for name, size in transaction_dict['to_install']])
#~ if transaction_dict['to_reinstall']:
#~ print('To reinstall:', [name for name, size in transaction_dict['to_reinstall']])
#~ if transaction_dict['to_downgrade']:
#~ print('To downgrade:', [name for name, size in transaction_dict['to_downgrade']])
#~ if transaction_dict['to_remove']:
#~ print('To remove:', [name for name in transaction_dict['to_remove']])
#~ if transaction_dict['to_update']:
#~ print('To update:', [name for name, size in transaction_dict['to_update']])
return transaction_dict
def set_transaction_sum(show_updates = True):
dsize = 0
transaction_sum.clear()
transaction_dict = get_transaction_sum()
sum_top_label.set_markup('<big><b>{}</b></big>'.format(_('Transaction Summary')))
if transaction_dict['to_remove']:
transaction_sum.append([_('To remove')+':', transaction_dict['to_remove'][0]])
i = 1
while i < len(transaction_dict['to_remove']):
transaction_sum.append(['', transaction_dict['to_remove'][i]])
i += 1
if transaction_dict['to_downgrade']:
transaction_sum.append([_('To downgrade')+':', transaction_dict['to_downgrade'][0][0]])
dsize += transaction_dict['to_downgrade'][0][1]
i = 1
while i < len(transaction_dict['to_downgrade']):
transaction_sum.append(['', transaction_dict['to_downgrade'][i][0]])
dsize += transaction_dict['to_downgrade'][i][1]
i += 1
if transaction_dict['to_build']:
transaction_sum.append([_('To build')+':', transaction_dict['to_build'][0]])
i = 1
while i < len(transaction_dict['to_build']):
transaction_sum.append(['', transaction_dict['to_build'][i]])
i += 1
if transaction_dict['to_install']:
transaction_sum.append([_('To install')+':', transaction_dict['to_install'][0][0]])
dsize += transaction_dict['to_install'][0][1]
i = 1
while i < len(transaction_dict['to_install']):
transaction_sum.append(['', transaction_dict['to_install'][i][0]])
dsize += transaction_dict['to_install'][i][1]
i += 1
if transaction_dict['to_reinstall']:
transaction_sum.append([_('To reinstall')+':', transaction_dict['to_reinstall'][0][0]])
dsize += transaction_dict['to_reinstall'][0][1]
i = 1
while i < len(transaction_dict['to_reinstall']):
transaction_sum.append(['', transaction_dict['to_reinstall'][i][0]])
dsize += transaction_dict['to_reinstall'][i][1]
i += 1
if show_updates:
if transaction_dict['to_update']:
transaction_sum.append([_('To update')+':', transaction_dict['to_update'][0][0]])
dsize += transaction_dict['to_update'][0][1]
i = 1
while i < len(transaction_dict['to_update']):
transaction_sum.append(['', transaction_dict['to_update'][i][0]])
dsize += transaction_dict['to_update'][i][1]
i += 1
else:
for name, size in transaction_dict['to_update']:
dsize += size
if dsize == 0:
sum_bottom_label.set_markup('')
else:
sum_bottom_label.set_markup('<b>{} {}</b>'.format(_('Total download size:'), common.format_size(dsize)))
def sysupgrade(show_updates = True):
syncfirst, updates = available_updates
if updates:
global to_update
global to_add
global to_remove
global progress_buffer
to_update.clear()
to_add.clear()
to_remove.clear()
action_handler(_('Preparing')+'...')
icon_handler('/usr/share/pamac/icons/24x24/status/package-setup.png')
target_handler('')
percent_handler(0)
progress_buffer.delete(progress_buffer.get_start_iter(), progress_buffer.get_end_iter())
ProgressCancelButton.set_visible(False)
ProgressCloseButton.set_visible(False)
progress_expander.set_visible(True)
ProgressWindow.show()
while Gtk.events_pending():
Gtk.main_iteration()
for name, version, db, tarpath, size in updates:
if db == 'AUR':
# call AURPkg constructor directly to avoid a request to AUR
infos = {'name': name, 'version': version, 'Description': '', 'URLPath': tarpath}
pkg = aur.AURPkg(infos)
to_build.append(pkg)
else:
to_update.add(name)
error = ''
if syncfirst:
ProgressCancelButton.set_visible(True)
error += init_transaction()
if not error:
for name in to_update:
error += Add(name)
if not error:
error += prepare()
else:
if to_build:
# check if packages in to_build have deps or makedeps which need to be install first
# grab errors differently here to not break regular updates
_error = check_to_build()
if to_update or to_add:
ProgressCancelButton.set_visible(True)
error += init_transaction()
if not error:
if to_update:
error += Sysupgrade()
_error = ''
for name in to_add:
_error += Add(name)
if _error:
print(_error)
if not error:
error += prepare()
if not error:
set_transaction_sum(show_updates = show_updates)
if show_updates:
ConfDialog.show_all()
while Gtk.events_pending():
Gtk.main_iteration()
else:
if len(transaction_sum) != 0:
ConfDialog.show_all()
while Gtk.events_pending():
Gtk.main_iteration()
else:
finalize()
if error:
ProgressWindow.hide()
Release()
return error