aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPapoteur <papoteur@mageia.org>2021-03-28 16:58:01 +0200
committerPapoteur <papoteur@mageia.org>2021-03-28 16:58:01 +0200
commit38a4a0a35c92c457e2c2a8cc7bf2ea4a6c09e3d1 (patch)
tree7a612ac188100b9a0437ed0dd97ab7cb2518dbd8
parent0ed27d2f918852df495b565bd9be7c442bb4d3fd (diff)
parent0d9522e267f8da916e57bcee51739e5573e209cb (diff)
downloadisodumper-38a4a0a35c92c457e2c2a8cc7bf2ea4a6c09e3d1.tar
isodumper-38a4a0a35c92c457e2c2a8cc7bf2ea4a6c09e3d1.tar.gz
isodumper-38a4a0a35c92c457e2c2a8cc7bf2ea4a6c09e3d1.tar.bz2
isodumper-38a4a0a35c92c457e2c2a8cc7bf2ea4a6c09e3d1.tar.xz
isodumper-38a4a0a35c92c457e2c2a8cc7bf2ea4a6c09e3d1.zip
Merge branch 'topic/newgui'
-rwxr-xr-xbackend/magiback7
-rwxr-xr-xbackend/raw_write.py90
-rwxr-xr-xlib/isodumper.py748
3 files changed, 503 insertions, 342 deletions
diff --git a/backend/magiback b/backend/magiback
index 49162b3..c65b3a3 100755
--- a/backend/magiback
+++ b/backend/magiback
@@ -38,9 +38,6 @@ class Isodumper(raw_write.Dumper):
<arg type='s' name='label' direction='in'/>
<arg type='s' name='key' direction='in'/>
</method>
- <method name='get_sum'>
- <arg type='s' name='source' direction='in'/>
- </method>
<method name='end'>
<arg type='b' name='success' direction='out'/>
<arg type='s' name='message' direction='out'/>
@@ -121,10 +118,6 @@ class Isodumper(raw_write.Dumper):
def progress(self):
return self._progress
- def get_sum(self, source):
- self.key_thread = threading.Thread(target=self._get_sum, args=(source,))
- self.key_thread.start()
-
def check_write(self, target, source):
if hasattr(self, 'key_thread'):
self.key_thread.join()
diff --git a/backend/raw_write.py b/backend/raw_write.py
index ac454f1..7891b43 100755
--- a/backend/raw_write.py
+++ b/backend/raw_write.py
@@ -27,7 +27,6 @@ import gettext
import hashlib
import io
import logging
-import datetime
###########
# imports #
###########
@@ -37,8 +36,6 @@ import sys
import time
from subprocess import Popen, PIPE
-import gnupg
-
class Dumper(object):
@@ -126,62 +123,6 @@ class Dumper(object):
self.finished.set()
return
- def _get_sum(self, source):
- self.return_state = False
- self.signature_checked = False
- mageia_keyid = "835E41F4EDCA7A90"
- logging.debug("Starting getting sum")
- # Check if the sum file has a valid signature
- gpg = gnupg.GPG()
- gpg.encoding = 'utf-8'
- # Use Mageia public key
- self.sum_type = 'sha3'
- sig_file = "{}.{}.gpg".format(source, self.sum_type)
- self.source_file = "{}.{}".format(source, self.sum_type)
- keys_list = gpg.list_keys()
- key_present = False
- for entry in keys_list:
- if (mageia_keyid == entry['keyid']):
- if entry['expires'] and (datetime.datetime.now().timestamp() > float(entry['expires'])):
- logging.info("Mageia key expired, reloading")
- else:
- logging.info("Mageia key already present")
- key_present = True
- break
- try:
- if not key_present:
- gpg.recv_keys('pool.sks-keyservers.net', mageia_keyid)
- self.sum_check_searched = True
- with open(sig_file, 'rb') as g:
- self.signature_found = True
- verified = gpg.verify_file(g, close_file=False)
- if verified:
- self.signature_checked = True
- logging.debug("signature checked")
- g.close()
- else:
- g.seek(0)
- verified = gpg.verify_file(g, self.source_file)
- if verified:
- self.signature_checked = True
- logging.debug("Detached signature is OK")
- else:
- self.signature_checked = False
- logging.warning("Signature is false")
- except Exception as e:
- self.signature_found = False
- logging.error(str(e))
- logging.info(_("Signature file {} not found\n" + _("or key expired")).format(sig_file))
- try:
- # Look for sum files in the same directory as source
- with open(self.source_file,'r') as fs:
- # Read the sum in the file
- self.sum_check=(fs.readline()).split()[0]
- self.sum_file = True
- except:
- logging.info(_("Sum file {} not found\n").format(self.source_file))
- self.sum_file = False
-
def _check_write(self, target, source):
logging.debug("Start checking")
self.return_message = ""
@@ -207,25 +148,30 @@ class Dumper(object):
sha512func.update(block)
sha512sumcalc=sha512func.hexdigest().upper()
#f.close()
+ self.sum_check = ""
+ sum_type = "sha3"
+ sum_file = f"{source}.{sum_type}"
+ try:
+ # Look for sum files in the same directory as source
+ with open(sum_file,'r') as fs:
+ # Read the sum in the file
+ self.sum_check=(fs.readline()).split()[0]
+ self.sum_file = True
+ except:
+ logging.info(_("Sum file {} not found\n").format(sum_file))
+ self.sum_file = False
self.return_state = True
- if self.signature_found and not self.signature_checked:
- #, keep the pourcent, this is the place for source file name
- self.return_message = _('Invalid signature for %s')%self.source_file
- self.return_state = False
+ #if self.signature_found and not self.signature_checked:
+ ##, keep the pourcent, this is the place for source file name
+ #self.return_message = _('Invalid signature for %s')%self.source_file
+ #self.return_state = False
if (self.sum_check == "") : # Can't get stored sum
self.return_message += _('SHA3 sum: {}').format(sha512sumcalc)
# compare the sums
elif (sha512sumcalc == self.sum_check) :
- if self.signature_checked and self.signature_found:
+ #if self.signature_checked and self.signature_found:
#, keep the bracket, this is the place for sum type
- self.return_message +="\n" + _("The {} sum check is OK and the sum is signed").format(self.sum_type)
- else :
- if self.signature_found:
- self.return_message +="\n" + _("The validation of the GPG signature failed !") + "\n" + _("The integrity of the ISO image could not be verified.")
- self.return_state = False
- else:
- #, keep the bracket, this is the place for sum type
- self.return_message +="\n" + _("The {} sum check is OK but the signature can't be found").format(self.sum_type)
+ self.return_message +="\n" + _("The {} sum check is OK").format(sum_type)
else:
self.return_message +="\n" + _("/!\\The computed and stored sums don't match")
self.return_state = False
diff --git a/lib/isodumper.py b/lib/isodumper.py
index 464943f..86433f6 100755
--- a/lib/isodumper.py
+++ b/lib/isodumper.py
@@ -45,6 +45,8 @@ import re
import gettext
from subprocess import Popen, PIPE
from pydbus import SystemBus
+import gnupg
+import datetime
import logging
import threading
@@ -52,6 +54,8 @@ from gi.repository import GLib
from queue import SimpleQueue
import psutil
import manatools.args as args
+import manatools.ui.common as common
+import manatools.ui.basedialog as basedialog
class NoUDisks2(Exception):
@@ -124,7 +128,13 @@ class UDisks2(object):
iface = self.bus.get(self.SERVICE, path_to_encrypted)
fs = iface[self.SERVICE + '.Filesystem']
if fs.MountPoints: # partition is mounted
- fs.Unmount({})
+ try:
+ fs.Unmount({})
+ except GLib.GError as e:
+ print(str(e))
+ return False, _("A partition is busy. Try to free it before starting again.")
+ except:
+ raise Exception(str(e))
iface = self.bus.get(self.SERVICE, block['path'])
fs = iface[self.SERVICE + '.Encrypted']
fs.Lock({})
@@ -135,11 +145,37 @@ class UDisks2(object):
fs = iface[self.SERVICE + '.Filesystem']
if fs.MountPoints: # partition is mounted
logging.debug(f"Unmounting {block['path']}")
- fs.Unmount({})
+ try:
+ fs.Unmount({})
+ except GLib.GError as e:
+ print(str(e))
+ return False, _("A partition is busy. Try to free it before starting again.")
+ except:
+ raise Exception(str(e))
else:
logging.debug(f"Not mounted {block['path']}")
return True, ""
+
+ def get_partitions(self, target):
+ # keep only the end, like sdb
+ target = os.path.basename(target)
+ partitions = []
+ objects = self._udisks2_obj_manager.GetManagedObjects()
+ re_block = re.compile('(?P<path>.*?/block_devices/(?P<id>.*))')
+ blocks = [m.groupdict() for m in
+ [re_block.match(path) for path in (objects.keys())]
+ if m]
+ for block in blocks:
+ if (self.SERVICE + '.Partition' in objects[block['path']]): # we skip non partition blocks
+ # Table should be something like '/org/freedesktop/UDisks2/block_devices/sdb'
+ if objects[block['path']][self.SERVICE + '.Partition']['Table'].split('/')[-1] == target:
+ partition = objects[block['path']][self.SERVICE + '.Block']
+ partitions.append( {'device': bytes(partition['Device']).decode("UTF-8", "replace").strip("\0"),
+ 'label': partition['IdLabel'],
+ 'type': partition['IdType']})
+ return partitions
+
def eject(self, device):
''' device is expected like /dev/sda'''
block = os.path.basename(device)
@@ -148,7 +184,6 @@ class UDisks2(object):
i_drive = self.bus.get(self.SERVICE, drive)
i_drive.Eject({})
-
class Info(object):
def __init__(self, title, richtext, text):
self.title = title
@@ -161,7 +196,7 @@ class ParseCLI(args.AppArgs):
super().__init__(command)
-class IsoDumper(object):
+class IsoDumper(basedialog.BaseDialog):
def get_devices(self, selected=None):
self.list = self.u.find_devices()
@@ -203,7 +238,7 @@ class IsoDumper(object):
self.ima.setLabel(self.ChooseImage)
self.backup_select.setLabel(self.ChooseImage)
self.dialog.recalcLayout()
- self.restore()
+ self.initial_state()
def update_list_on_event(self):
selitem = self.devicelist.selectedItem().label()
@@ -211,6 +246,10 @@ class IsoDumper(object):
self.get_devices(selected = selitem)
if self.devicelist.selectedItem().label() != selitem:
self.restore()
+
+ def refresh_signal(self, device, params):
+ self.devicelist.deleteAllItems()
+ self.get_devices()
self.dialog.recalcLayout()
def device_selected(self):
@@ -221,10 +260,23 @@ class IsoDumper(object):
if self.dev.startswith(name + ' (' + path.lstrip()):
self.deviceSize = size
self.device_name = name.rstrip().replace(' ', '')
- self.logger(_('Target Device: ') + self.dev)
- self.formatbt.setEnabled()
- self.ima.setEnabled()
- self.backup_select.setEnabled()
+ message = _('Target Device: {}').format(self.dev)
+ self.logger(message)
+ logging.info(message)
+ partitions = self.u.get_partitions(self.dev.split('(')[1].split(')')[0])
+ #, verb in singular 3rd person
+ self.logger(_("Contents partition(s)"))
+ for partition in partitions:
+ self.logger(_("{device}: Type {type} Label {label}").format(device=partition['device'],
+ type=partition['type'],
+ label=partition['label'],))
+ self.partition_cbox.setEnabled()
+ self.partition_cbox.setChecked(False)
+ self.backup_cbox.setEnabled()
+ self.backup_cbox.setChecked(False)
+ self.write_cbox.setEnabled()
+ self.write_cbox.setChecked(False)
+ self.cryptcb.setChecked(False)
break
@staticmethod
@@ -238,57 +290,123 @@ class IsoDumper(object):
def backup_choosed(self):
# Add .img if not specified
- if not self.backup_img_name.lower().endswith('.img'):
- self.backup_img_name = self.backup_img_name + ".img"
- head, tail = os.path.split(self.backup_img_name)
- self.backup_dest = self.backup_img_name
- self.backup_select.setLabel(tail)
- self.dialog.recalcLayout()
- self.backupbt.setEnabled()
-
- def do_format(self, format_type, name):
- target = self.dev.split('(')[1].split(')')[0]
- info = Info(_("Formatting confirmation"), True, self.warning)
- if self.ask_YesOrNo(info):
- rc = self.raw_format(target, format_type, name)
- self.operation = False
- if rc == 0:
- message = _('The device was formatted successfully.')
- self.logger(message)
- self.success()
- elif rc == 5:
- message = _("An error occurred while creating a partition.")
- self.logger(message)
- self.emergency(message)
- elif rc == 127:
- message = _('Authentication error.')
- self.logger(message)
- self.emergency(message)
- else:
- message = _('An error occurred.')
- self.emergency(message)
+ self.backup_img_name = yui.YUI.app().askForSaveFileName("", "*.img", _("Backup to:"))
+ if self.backup_img_name != '':
+ if not self.backup_img_name.lower().endswith('.img'):
+ self.backup_img_name = self.backup_img_name + ".img"
+ head, tail = os.path.split(self.backup_img_name)
+ self.backup_dest = self.backup_img_name
+ self.backup_select.setLabel(tail)
+ self.dialog.recalcLayout()
+ self.start_bt.setEnabled()
+ self.backup_is_selected = True
+ else:
+ self.backup_is_selected = False
+
+ def get_sum(self, source):
+ self.return_state = False
+ self.signature_checked = False
+ logging.debug("Starting getting sum")
+ # Check if the sum file has a valid signature
+ gpg = gnupg.GPG()
+ gpg.encoding = 'utf-8'
+ # Use Mageia public key
+ mageia_keyid = "835E41F4EDCA7A90"
+ self.sum_type = 'sha3'
+ sig_file = "{}.{}.gpg".format(source, self.sum_type)
+ self.source_file = "{}.{}".format(source, self.sum_type)
+ keys_list = gpg.list_keys()
+ key_present = False
+ for entry in keys_list:
+ if (mageia_keyid == entry['keyid']):
+ if entry['expires'] and (datetime.datetime.now().timestamp() > float(entry['expires'])):
+ logging.info("Mageia key expired, reloading")
+ else:
+ logging.info("Mageia key already present")
+ key_present = True
+ break
+ try:
+ if not key_present:
+ gpg.recv_keys('pool.sks-keyservers.net', mageia_keyid)
+ self.sum_check_searched = True
+ with open(sig_file, 'rb') as g:
+ self.signature_found = True
+ verified = gpg.verify_file(g, close_file=False)
+ if verified:
+ self.signature_checked = True
+ logging.debug("signature checked")
+ g.close()
+ else:
+ g.seek(0)
+ verified = gpg.verify_file(g, self.source_file)
+ if verified:
+ self.signature_checked = True
+ logging.debug("Detached signature is OK")
+ else:
+ self.signature_checked = False
+ logging.warning("Signature is false")
+ except Exception as e:
+ self.signature_found = False
+ logging.error(str(e))
+ logging.info(_("Signature file {} not found\n" + _("or key expired")).format(sig_file))
+
+ def do_format(self):
+ #code, format_type, name = self.ask_format()
+ if self.partition_cb.value() != "":
+ self.operation = True
+ format_type = list(self.format_type.keys())[list(self.format_type.values()).index(self.partition_cb.value())]
+ if format_type == 'persist':
+ self.emergency(_("Persistence partition is to use when writing a Live ISO image."))
+ return
+ target = self.dev.split('(')[1].split(')')[0]
+ info = Info(_("Formatting confirmation in {}".format(self.partition_cb.value())), True, self.warning)
+ if self.ask_YesOrNo(info):
+ name = self.partition_label.value()
+ if format_type == 'fat32':
+ name = name.upper()[:11]
+ elif format_type == 'exfat' or format_type == 'ntfs':
+ name = name[:32]
+ rc = self.raw_format(target, format_type, name)
+ self.operation = False
+ if rc == 0:
+ message = _('The device was formatted successfully.')
+ self.logger(message)
+ self.success()
+ elif rc == 5:
+ message = _("An error occurred while creating a partition.")
+ self.logger(message)
+ self.emergency(message)
+ elif rc == 127:
+ message = _('Authentication error.')
+ self.logger(message)
+ self.emergency(message)
+ else:
+ message = _('An error {} occurred.'.format(rc))
+ self.emergency(message)
+ self.initial_state()
- def restore(self):
+ def initial_state(self):
+ self.image_is_selected = False
+ self.backup_is_selected = False
self.backup_select.setDisabled()
- self.backupbt.setDisabled()
- self.formatbt.setDisabled()
+ self.backup_cbox.setDisabled()
+ self.partition_cbox.setDisabled()
self.ima.setDisabled()
- self.writebt.setDisabled()
+ self.img_name = ""
+ self.ima.setLabel(self.ChooseImage)
+ self.write_cbox.setDisabled()
self.devicelist.setEnabled()
self.progress.setLabel(_("Progress"))
self.progress.setValue(0)
self.progress.setDisabled()
self.refreshbt.setEnabled()
- self.persistencecb.setChecked(False)
- self.persistencecb.setDisabled()
- self.cryptcb.setChecked(False)
+ #self.persistencecb.setChecked(False)
+ #self.persistencecb.setDisabled()
+ self.partition_cb.setDisabled()
+ self.partition_label.setDisabled()
self.cryptcb.setDisabled()
self.cryptkey.setDisabled()
-
- def onProgress(self, frac):
- self.logger(_('Wrote: {}% '.format(frac)))
- self.progress.setValue(frac)
- self.dialog.pollEvent()
+ self.start_bt.setDisabled()
def raw_format(self, usb_path, fstype, label):
self.u.do_unmount(usb_path)
@@ -318,6 +436,11 @@ class IsoDumper(object):
return rc
def backup_go(self):
+ self.wip_unsensitive()
+ self.devicelist.setDisabled()
+ self.backup_select.setDisabled()
+ self.progress.setEnabled()
+ self.progress.setLabel("Backup")
dest = self.backup_img_name
if os.path.exists(dest):
info = Info(_("Backup confirmation"), True, _("Do you want to overwrite the file?"))
@@ -330,45 +453,53 @@ class IsoDumper(object):
sizeM = str(self.deviceSize / (1024 * 1024))
message = _("The destination directory is too small to receive the backup (%s Mb needed)") % (sizeM)
self.logger(message)
+ logging.warning(message)
self.emergency(message)
else:
+ self.operation = True
self.returncode = 0
source = self.dev.split('(')[1].split(')')[0]
- self.logger(_('Backup to:') + ' ' + dest)
- bus = SystemBus()
- iface = bus.get("org.mageia.Magiback", "Isodumper")
+ message = _('Backup to: {}').format(dest)
+ self.logger(message)
+ logging.info(message)
# Writing step
- iface.do_write(source, dest, self.deviceSize)
- while not iface.done:
- progress = iface.progress
+ self.iface.do_write(source, dest, self.deviceSize)
+ while not self.iface.done:
+ progress = self.iface.progress
self.progress.setValue(progress)
self.dialog.pollEvent()
time.sleep(.2)
- success, message = iface.end()
+ success, message = self.iface.end()
if success:
- self.logger(
- _('{source} successfully written to {target}').format(source=source.split('/')[-1], target=dest))
+ #: don't translate source or target
+ message = _('{source} successfully written to {target}').format(source=source.split('/')[-1], target=dest)
+ self.logger(message)
+ logging.info(message)
self.progress.setEnabled()
self.progress.setValue(100)
self.dialog.pollEvent()
self.logger(message)
+ logging.info(message)
self.success()
+ self.initial_state()
else:
self.emergency(message)
+ self.initial_state()
def do_write(self):
- self.writebt.setDisabled()
+ self.wip_unsensitive()
+ #self.writebt.setDisabled()
self.devicelist.setDisabled()
- self.formatbt.setDisabled()
- self.backupbt.setDisabled()
self.backup_select.setDisabled()
self.progress.setEnabled()
+ self.progress.setLabel("Writing")
source = self.img_name
target = self.dev.split('(')[1].split(')')[0]
b = os.path.getsize(source)
if b > (self.deviceSize):
message = _('The device is too small to contain the ISO file.')
self.logger(message)
+ logging.error(message)
self.emergency(message)
else:
info = Info(_("Writing confirmation"), True, self.warning)
@@ -381,79 +512,87 @@ class IsoDumper(object):
else:
return
self.ima.setDisabled()
- self.writebt.setDisabled()
+ #: don't translate source or target
self.progress.setLabel(_('Writing {source} to {target}').format(source=source.split('/')[-1],
target=target.split('/')[-1]))
- self.logger(_('Executing copy from ') + source + _(' to ') + target)
- bus = SystemBus()
- iface = bus.get("org.mageia.Magiback", "Isodumper")
+ message = _('Executing copy from {source} to {target}').format(source=source, target=target)
+ self.operation = True
+ self.logger(message)
+ logging.info(message)
success, message = self.u.do_unmount(target)
self.udev_wait(_("unmounting"))
if success:
# Writing step
- iface.do_write(source, target, b)
- iface.get_sum(source)
- progress = iface.progress
- while not iface.done:
- progress = iface.progress
+ self.iface.do_write(source, target, b)
+ progress = self.iface.progress
+ while not self.iface.done:
+ progress = self.iface.progress
self.progress.setValue(progress)
self.dialog.pollEvent()
time.sleep(.5)
- success, message = iface.end()
+ success, message = self.iface.end()
if success:
- self.logger(
- _('Image {source} successfully written to {target}').format(source=source.split('/')[-1],
- target=target))
- self.logger(_('Bytes written: ') + str(b))
+ #: don't translate source or target
+ message = _('Image {source} successfully written to {target}').format(source=source.split('/')[-1],
+ target=target)
+ message += "\n" + _('Bytes written: {}').format(str(b))
+ self.logger(message)
+ logging.info(message)
self.progress.setLabel(_('Checking ') + target.split('/')[-1])
self.progress.setValue(0)
self.dialog.pollEvent()
# Checking
- iface.check_write(target, source)
+ self.iface.check_write(target, source)
progress = 0
while progress < 100:
self.progress.setValue(progress)
self.dialog.pollEvent()
time.sleep(.5)
- progress = iface.progress
- nowarning, message = iface.end()
+ progress = self.iface.progress
+ nowarning, message = self.iface.end()
self.progress.setEnabled()
self.logger(message)
+ logging.info(message)
# Add persistent partition if asked
- if self.persistencecb.isChecked():
+ if self.partition_cbox.isChecked() and self.partition_cb.value() == _("Persistent partition"):
self.progress.setLabel(_("Adding persistent partition"))
self.progress.setValue(0)
if self.cryptcb.isChecked():
if self.cryptkey.value() == "":
- self.logger(
- _("No key for encrypted partition provided. Adding the partition aborted."))
+ message = _("No key for encrypted partition provided. Adding the partition aborted.")
+ self.logger(message)
+ logging.warning(message)
else:
- iface.do_persistence(target, "mgalive-persist", self.cryptkey.value())
- while not iface.done:
- progress = iface.progress
+ self.iface.do_persistence(target, self.partition_label.value(), self.cryptkey.value())
+ while not self.iface.done:
+ progress = self.iface.progress
self.progress.setValue(progress)
- self.progress.setLabel(iface.message)
+ self.progress.setLabel(self.iface.message)
self.dialog.pollEvent()
time.sleep(.5)
- if iface.state:
- self.logger(_("Added encrypted persistent partition"))
+ if self.iface.state:
+ message = _("Added encrypted persistent partition")
+ self.logger(message)
+ logging.warning(message)
else:
self.logger(_("Adding encrypted persistent partition failed"))
- self.logger(iface.message)
+ self.logger(self.iface.message)
nowarning = False
else:
- iface.do_persistence(target, "mgalive-persist", "")
- while not iface.done:
- progress = iface.progress
+ self.iface.do_persistence(target, self.partition_label.value(), "")
+ while not self.iface.done:
+ progress = self.iface.progress
self.progress.setValue(progress)
self.dialog.pollEvent()
time.sleep(.5)
- if iface.state:
- self.logger(_("Added persistent partition"))
+ if self.iface.state:
+ message = _("Added persistent partition")
else:
- self.logger(_("Adding persistent partition failed"))
- self.logger(iface.message)
+ message = _("Adding persistent partition failed")
+ self.logger(self.iface.message)
nowarning = False
+ self.logger(message)
+ logging.warning(message)
# Unmount if partitions are automatically mounted and then eject
self.progress.setValue(100)
self.dialog.pollEvent()
@@ -467,22 +606,23 @@ class IsoDumper(object):
self.warn()
else:
self.emergency(message)
- self.restore()
+ self.initial_state()
else:
self.emergency(message)
+ self.initial_state()
else:
self.emergency(message)
- self.restore()
+ self.initial_state()
else:
- self.restore()
+ self.initial_state()
+ self.operation = False
def success(self):
self.operation = False
self.final_unsensitive()
- info = Info(_("Success"), True, _("The operation completed successfully.\n\
- You are free to unplug it now, a logfile \n\
-(/home/-user- or /root)/.isodumper/isodumper.log will be saved when\n\
- you close the application."))
+ info = Info(_("Success"), True, _("The operation completed successfully.") + "\n"\
+ + _("You are free to unplug it now, a logfile \n\
+(/home/-user-/.isodumper/isodumper.log has been saved.") + _("You may also consult /var/log/magiback.log"))
if self.ask_OK(info):
return
@@ -490,12 +630,13 @@ class IsoDumper(object):
self.operation = False
self.final_unsensitive()
info = Info(_("Warning"), True, _("The operation completed, but with anomalies.\n\
- Check carefully the messages in log view.\n\
- You are free to unplug it now, a logfile \n\
-(/home/-user- or /root)/.isodumper/isodumper.log will be saved when\n\
- you close the application."))
+ Check carefully the messages in log view") + "\n"\
++ _("You are free to unplug it now, a logfile \n\
+(/home/-user-/.isodumper/isodumper.log has been saved.") + "\n"\
+ + _("You may also consult /var/log/magiback.log"))
if self.ask_OK(info):
return
+
def confirm_close(self, *args):
if not self.operation: # no writing , backup nor format running
self.close()
@@ -518,44 +659,38 @@ class IsoDumper(object):
def final_unsensitive(self):
self.ima.setDisabled()
self.devicelist.setDisabled()
- self.writebt.setDisabled()
+ self.write_cbox.setDisabled()
+ self.backup_cbox.setDisabled()
self.progress.setDisabled()
self.backup_select.setDisabled()
- self.persistencecb.setDisabled()
+ self.partition_cbox.setDisabled()
def wip_unsensitive(self):
self.ima.setDisabled()
self.devicelist.setDisabled()
- self.writebt.setDisabled()
+ self.backup_cbox.setDisabled()
self.backup_select.setDisabled()
- self.backupbt.setDisabled()
+ self.write_cbox.setDisabled()
self.refreshbt.setDisabled()
- self.persistencecb.setDisabled()
+ self.partition_cbox.setDisabled()
+ self.partition_cb.setDisabled()
+ self.partition_label.setDisabled()
+ self.cryptcb.setDisabled()
+ self.cryptkey.setDisabled()
+ self.start_bt.setDisabled()
def close(self):
- self.write_logfile()
- self.dialog.destroy()
- self.dialog = None
- if yui.YUI.app().isTextMode():
- self.glib_loop.quit()
- self.glib_thread.join()
-
- def write_logfile(self):
- logpath = os.path.join(os.path.expanduser('~'), '.isodumper')
- if not (os.path.isdir(logpath)):
- os.mkdir(logpath)
- logfile = open(logpath + '/isodumper.log', "w", encoding="utf-8")
- logfile.write(self.logview.logText())
- logfile.close()
-
- print((self.logview.logText()))
+ # to exit from _handleEvents loop
+ self._running = False
def logger(self, text):
self.logview.appendLines(text + "\n")
def activate_devicelist(self):
self.devicelist.setEnabled()
- self.logger(_('Image ') + ": " + self.img_name)
+ message = _('Image ') + ": " + self.img_name
+ self.logger(message)
+ logging.warning(message)
# self.chooser.set_tooltip_text(self.img_name)
@@ -594,6 +729,7 @@ exFAT, NTFS or ext. You can specify a volume name and the format in a new dialog
return
def __init__(self, debug=False):
+ #: placeholder for release number
APP = "isodumper"
DIR = "/usr/share/locale"
# Call translation catalog
@@ -614,7 +750,7 @@ exFAT, NTFS or ext. You can specify a volume name and the format in a new dialog
logpath = os.path.join(os.path.expanduser('~'), '.isodumper')
if not (os.path.isdir(logpath)):
os.mkdir(logpath)
- logging.basicConfig(filename=os.path.join(logpath,"isodumper2.log"),
+ logging.basicConfig(filename=os.path.join(logpath,"isodumper.log"),
format='%(asctime)s %(levelname)-8s %(message)s',
level=level)
@@ -623,6 +759,10 @@ exFAT, NTFS or ext. You can specify a volume name and the format in a new dialog
# Operation running
self.operation = False
+
+ # Prepare interface on DBus
+ self.bus = SystemBus()
+ self.iface = self.bus.get("org.mageia.Magiback", "Isodumper")
self.ChooseImage = _("Choose an image")
self.warning = _("Warning\nThis will destroy all data on the target device,\n\
@@ -632,15 +772,15 @@ exFAT, NTFS or ext. You can specify a volume name and the format in a new dialog
"""
Init/Constructor for the 'widgets'
"""
- yui.YUI.app().setApplicationTitle(_("IsoDumper") + " " + version.RELEASE)
+ self.dialog = basedialog.BaseDialog.__init__(self, _("Isodumper {}").format(version.RELEASE), "", basedialog.DialogType.POPUP, 100, 20)
yui.YUI.app().setApplicationIcon("/usr/share/icons/isodumper.png")
- self.atelier = yui.YUI.widgetFactory()
- self.dialog = self.atelier.createPopupDialog()
+
+ def UIlayout(self, layout):
# create the main gui
- # +---+-----------------+
+ # +---------------------+
# + banner +
- # +---+-----------------+
- # | devicelist |
+ # +---------------------+
+ # | devicebox |
# +---+-----+------+----+
# + L | ima | writebt |
# +---+-----+------+----+
@@ -654,72 +794,104 @@ exFAT, NTFS or ext. You can specify a volume name and the format in a new dialog
# +---------------------+
# | refreshbt | aboutbt | helpbt | quitbt |
# +---------------------+
- self.ancrage = self.atelier.createReplacePoint(self.dialog)
- self.box = self.atelier.createVBox(self.ancrage)
- self.bannerbox = self.atelier.createHBox(self.box)
- self.banner = self.atelier.createImage(self.bannerbox, "/usr/share/isodumper/header.svg")
- self.devicebox = self.atelier.createHBox(self.box)
- self.devicelist = self.atelier.createComboBox(self.devicebox, _("Device to work on:"), False)
+ #self.ancrage = self.factory.createReplacePoint(self.dialog)
+ self.box = self.factory.createVBox(layout)
+ self.bannerbox = self.factory.createHBox(self.box)
+ self.banner = self.factory.createImage(self.bannerbox, "/usr/share/isodumper/header.svg")
+ self.devicebox = self.factory.createHBox(self.box)
+ self.devicelist = self.factory.createComboBox(self.devicebox, _("Select the device to work on:"), False)
self.devicelist.setNotify()
self.devicelist.setStretchable(0, True)
- self.writebox = self.atelier.createHBox(self.box)
- self.atelier.createLabel(self.writebox, _("Write Image:"))
+ self.refreshbt = self.factory.createPushButton(self.devicebox, _("Update list"))
+ self.refreshbt.setStretchable(0, True)
+ self.operation_frame = self.factory.createFrame(self.box, _("Select operations"))
+ self.operationbox = self.factory.createVBox(self.operation_frame)
+ self.labelbox = self.factory.createHBox(self.operationbox)
+ self.labelbox.setStretchable(0, True)
+ self.factory.createLabel(self.labelbox, "The selected operations will be executed in order from top to bottom.\nIf both write image and create partition are selected, the partition\nwill be created in the free space after the image.").setStretchable(0, True)
+ self.backupbox = self.factory.createHBox(self.operationbox)
+ self.backup_cbox = self.factory.createCheckBox(self.backupbox, _("Backup the device to:"))
+ self.backup_cbox.setNotify()
+ # add file picker for backup file name
+ self.backup_select = self.factory.createPushButton(self.backupbox, self.ChooseImage)
+ self.backup_select.setStretchable(0, True)
+ self.factory.createHStretch(self.backupbox)
+ self.writebox = self.factory.createHBox(self.operationbox)
+ self.write_cbox = self.factory.createCheckBox(self.writebox, _("Write Image from:"))
+ self.write_cbox.setNotify()
# add file picker for image file
- self.ima = self.atelier.createPushButton(self.writebox, self.ChooseImage)
+ self.ima = self.factory.createPushButton(self.writebox, self.ChooseImage)
self.ima.setStretchable(0, True)
- self.ima.setDisabled()
- self.atelier.createHStretch(self.writebox)
- self.writebt = self.atelier.createPushButton(self.writebox, _("&Write to device"))
- self.writebt.setDisabled()
- self.persistencebox = self.atelier.createHBox(self.box)
- self.persistencecol1 = self.atelier.createVBox(self.persistencebox)
- self.persistencecol2 = self.atelier.createVBox(self.persistencebox)
- self.persistencecb = self.atelier.createCheckBox(self.persistencecol1,
- _("Add a persistent partition in the remaining space"))
- self.persistencebox2 = self.atelier.createHBox(self.box)
- self.cryptcb = self.atelier.createCheckBox(self.persistencecol1, _("Encrypt partition"))
- self.cryptkey = self.atelier.createInputField(self.persistencecol2, _("Key:"), passwordMode=True)
- self.persistencecb.setDisabled()
- self.persistencecb.setNotify()
- self.cryptcb.setDisabled()
+ self.factory.createHStretch(self.writebox)
+ #self.writebt = self.factory.createPushButton(self.writebox, _("&Write to device"))
+ self.partitionbox = self.factory.createHBox(self.operationbox)
+ self.partition_cbox = self.factory.createCheckBox(self.partitionbox, _("Create partition of type:"))
+ self.partition_cbox.setNotify()
+ self.partition_cb = self.factory.createComboBox(self.partitionbox, _("Type:"))
+ self.partition_cb.addItem("", True)
+ self.format_type = {'fat32': _("FAT 32"),
+ 'ext4': _("ext4"),
+ 'ntfs': _("NTFS"),
+ 'exfat': _("exfat"),
+ 'persist': _("Persistent partition"),
+ }
+ for key in self.format_type:
+ self.partition_cb.addItem(self.format_type[key], False)
+ self.partition_cb.setNotify()
+ self.partition_label = self.factory.createInputField(self.partitionbox, _("Label:"))
+ self.partition_label.setStretchable(0, True)
+ self.persistencebox = self.factory.createHBox(self.operationbox)
+ #self.persistencecb = self.factory.createCheckBox(self.persistencecol1,
+ # _("Add a persistent partition in the remaining space"))
+ self.cryptcb = self.factory.createCheckBox(self.persistencebox, _("Encrypt partition using LUKS, with key:"))
self.cryptcb.setNotify()
- self.cryptkey.setDisabled()
- self.backupbox = self.atelier.createHBox(self.box)
- self.atelier.createLabel(self.backupbox, _("Backup to:"))
- # add file picker for backup file name
- self.backup_select = self.atelier.createPushButton(self.backupbox, self.ChooseImage)
- self.backup_select.setStretchable(0, True)
- self.backup_select.setDisabled()
- self.atelier.createHStretch(self.backupbox)
- self.backupbt = self.atelier.createPushButton(self.backupbox, _("Backup the device"))
- self.backupbt.setDisabled()
- self.formatbox = self.atelier.createHBox(self.box)
- self.atelier.createLabel(self.formatbox, _("Format the device in FAT, exFAT, NTFS or ext:"))
- self.atelier.createHStretch(self.formatbox)
- self.formatbt = self.atelier.createPushButton(self.formatbox, _("Format the device"))
- self.formatbt.setDisabled()
- self.progressbox = self.atelier.createHBox(self.box)
- self.progress = self.atelier.createProgressBar(self.progressbox, _("Progress"), 100)
+ self.cryptkey = self.factory.createInputField(self.persistencebox, _("Key:"), passwordMode=True)
+ self.cryptkey.setStretchable(0, True)
+ #self.formatbt = self.factory.createPushButton(self.formatbox, _("Format the device"))
+ self.execute_frame = self.factory.createFrame(self.box, _("Execution"))
+ self.execute_framevb = self.factory.createVBox(self.execute_frame)
+ self.execute_label = self.factory.createLabel(self.execute_framevb, _("When you are sure all options are correct, start:"))
+ self.start_bt = self.factory.createPushButton(self.execute_framevb, _("Execute"))
+ self.start_bt.setNotify()
+ self.progressbox = self.factory.createHBox(self.execute_framevb)
+ self.progress = self.factory.createProgressBar(self.progressbox, _("Progress"), 100)
self.progress.setStretchable(0, True)
- self.reportbox = self.atelier.createHBox(self.box)
+ self.reportbox = self.factory.createHBox(self.box)
self.reportbox.setWeight(1, 30)
- self.logview = self.atelier.createLogView(self.reportbox, _("Report"), 10)
+ self.logview = self.factory.createLogView(self.reportbox, _("Report"), 10)
self.logview.setStretchable(0, True)
- self.buttonsbox = self.atelier.createHBox(self.box)
- self.refreshbt = self.atelier.createPushButton(self.devicebox, _("Refresh"))
- self.refreshbt.setStretchable(0, True)
- self.aboutbt = self.atelier.createPushButton(self.buttonsbox, _("About"))
+ self.buttonsbox = self.factory.createHBox(self.box)
+ self.aboutbt = self.factory.createPushButton(self.buttonsbox, _("About"))
self.aboutbt.setStretchable(0, True)
- self.helpbt = self.atelier.createPushButton(self.buttonsbox, _("Help"))
+ self.helpbt = self.factory.createPushButton(self.buttonsbox, _("Help"))
self.helpbt.setStretchable(0, True)
- self.quitbt = self.atelier.createPushButton(self.buttonsbox, _("Quit"))
+ self.quitbt = self.factory.createPushButton(self.buttonsbox, _("Quit"))
self.quitbt.setStretchable(0, True)
+ # Set the initial state, active, disabled
+ self.initial_state()
+ # Connect events
+ self.eventManager.addWidgetEvent(self.quitbt, self.confirm_close)
+ self.eventManager.addWidgetEvent(self.ima, self.ask_image)
+ #self.eventManager.addWidgetEvent(self.writebt, self.do_write)
+ self.eventManager.addWidgetEvent(self.cryptcb, self.check_encryt)
+ #self.eventManager.addWidgetEvent(self.backupbt, self.backup_go)
+ self.eventManager.addWidgetEvent(self.backup_select, self.backup_choosed)
+ #self.eventManager.addWidgetEvent(self.formatbt, self.do_format)
+ self.eventManager.addWidgetEvent(self.backup_cbox, self.select_backup)
+ self.eventManager.addWidgetEvent(self.write_cbox, self.select_write)
+ self.eventManager.addWidgetEvent(self.partition_cbox, self.select_partition)
+ self.eventManager.addWidgetEvent(self.partition_cb, self.select_partition_type)
+ self.eventManager.addWidgetEvent(self.devicelist, self.device_selected)
+ self.eventManager.addWidgetEvent(self.start_bt, self.start)
+ self.eventManager.addWidgetEvent(self.refreshbt, self.update_list)
+ self.eventManager.addWidgetEvent(self.helpbt, self.help_dialog)
+ self.eventManager.addWidgetEvent(self.aboutbt, self.aboutDialog)
self.u = None
try:
self.u = UDisks2()
except:
message = _('UDisks2 is not available on your system')
- self.logger(message)
+ logging.error(message)
self.emergency(message)
if not self.get_devices():
self.dialog.destroy()
@@ -727,7 +899,7 @@ exFAT, NTFS or ext. You can specify a volume name and the format in a new dialog
exit()
self.device_selected()
self.dialog.recalcLayout()
- self.ancrage.showChild()
+
self.uEventQueue = SimpleQueue()
if yui.YUI.app().isTextMode():
self.glib_loop = GLib.MainLoop()
@@ -745,8 +917,107 @@ exFAT, NTFS or ext. You can specify a volume name and the format in a new dialog
def device_changed(self, a, b):
- self.uEventQueue.put({'event': "device-changed", 'value': True})
+ logging.debug(f"Signal {a}")
+ if not self.operation:
+ if 'drives' in a.split('/'):
+ logging.debug('device-changed')
+ self.uEventQueue.put({'event': "device-changed", 'value': True})
+
+ def ask_image(self):
+ self.img_name = yui.YUI.app().askForExistingFile("", "*.iso *.img", self.ChooseImage)
+ if self.img_name != "":
+ # Check if the image has a signed checksum
+ self.get_sum(self.img_name)
+ if self.signature_found:
+ if not self.signature_checked:
+ info = Info(_("Warning"), True,
+ _("The validation of the GPG signature failed !") + "\n" + _("Do you want to continue?"))
+ if self.ask_YesOrNo(info):
+ pass
+ else:
+ self.img_name = ""
+ return
+ else:
+ info = Info(_("Warning"), True,
+ _('No GPG signature has been found or the key is expired. Are you sure you want to use this image?'))
+ if self.ask_YesOrNo(info):
+ pass
+ else:
+ self.img_name = ""
+ return
+ self.ima.setLabel(os.path.basename(self.img_name))
+ self.dialog.recalcLayout()
+ self.start_bt.setEnabled()
+ self.activate_devicelist()
+ self.image_is_selected = True
+ #self.persistencecb.setEnabled()
+ else:
+ self.image_is_selected = False
+
+ def select_backup(self):
+ if self.backup_cbox.isChecked():
+ self.backup_select.setEnabled()
+ else:
+ self.backup_select.setDisabled()
+
+ def select_write(self):
+ if self.write_cbox.isChecked():
+ self.ima.setEnabled()
+ else:
+ self.ima.setDisabled()
+
+ def select_partition(self):
+ if self.partition_cbox.isChecked():
+ self.partition_cb.setEnabled()
+ self.partition_label.setEnabled()
+ else:
+ self.partition_cb.setDisabled()
+ self.partition_label.setDisabled()
+ self.cryptcb.setDisabled()
+ self.cryptkey.setDisabled()
+
+ def select_partition_type(self):
+ if self.partition_cb.value() in ("ext4" ,"Persistent partition"):
+ self.cryptcb.setEnabled()
+ if self.partition_cb.value() == "Persistent partition":
+ self.partition_label.setValue("mgalive-persist")
+ else:
+ self.cryptcb.setDisabled()
+ self.cryptcb.setDisabled()
+ self.cryptkey.setDisabled()
+ if self.partition_cb.value() != "":
+ self.start_bt.setEnabled()
+ else:
+ self.start_bt.setDisabled()
+
+ def check_encryt(self):
+ if self.cryptcb.isChecked():
+ self.cryptkey.setEnabled()
+ else:
+ self.cryptkey.setDisabled()
+
+ def start(self):
+ if self.backup_cbox.isChecked():
+ # check that a name is set
+ if self.backup_is_selected:
+ self.backup_go()
+ self.backup_is_selected = False
+ else:
+ info = Info(_("Error"), True, _("No image for backup is selected."))
+ self.ask_OK(info)
+ if self.write_cbox.isChecked():
+ if self.image_is_selected:
+ self.do_write()
+ self.image_is_selected = False
+ else:
+ info = Info(_("Error"), True, _("No image to write is selected."))
+ self.ask_OK(info)
+ return
+ if self.partition_cbox.isChecked():
+ # Create a partition without writing image, will use all the device space.
+ self.do_format()
+
def ask_format(self):
atelier = yui.YUI.widgetFactory()
dialog = atelier.createPopupDialog()
@@ -839,87 +1110,38 @@ exFAT, NTFS or ext. You can specify a volume name and the format in a new dialog
dlg.setMinSize(60, 8)
return dlg.show() == yui.YMGAMessageBox.B_ONE
- def handleevent(self):
+ def doSomethingIntoLoop(self):
self.traitement = None
- while True:
- event = self.dialog.waitForEvent(100)
- if event.eventType() == yui.YEvent.CancelEvent:
- self.close()
- break
- if event.widget() == self.quitbt:
- self.close()
- break
- if event.widget() == self.ima:
- self.img_name = yui.YUI.app().askForExistingFile("", "*.iso *.img", self.ChooseImage)
- if self.img_name != "":
- self.ima.setLabel(os.path.basename(self.img_name))
- self.dialog.recalcLayout()
- self.writebt.setEnabled()
- self.activate_devicelist()
- self.persistencecb.setEnabled()
- if event.widget() == self.persistencecb:
- print(self.persistencecb.value)
- if self.persistencecb.isChecked():
- self.cryptcb.setEnabled()
- else:
- self.cryptcb.setDisabled()
- self.cryptkey.setDisabled()
- self.cryptcb.setChecked(False)
- if event.widget() == self.cryptcb:
- if self.cryptcb.isChecked():
- self.cryptkey.setEnabled()
- else:
- self.cryptkey.setDisabled()
- if event.widget() == self.writebt:
- self.wip_unsensitive()
- self.do_write()
- self.restore()
- if event.widget() == self.backupbt:
- self.wip_unsensitive()
- self.backup_go()
- self.restore()
- if event.widget() == self.backup_select:
- self.backup_img_name = yui.YUI.app().askForSaveFileName("", "*.img", _("Backup to:"))
- if self.backup_img_name != '':
- self.backup_choosed()
- if event.widget() == self.formatbt:
- code, format_type, name = self.ask_format()
- if code:
- self.do_format(format_type, name)
- self.restore()
- if event.widget() == self.devicelist:
- self.device_selected()
- try:
- if event.widget() == self.refreshbt:
- self.update_list()
- except:
- pass
- try:
- if event.widget() == self.helpbt:
- self.help_dialog()
- except:
- pass
- try:
- if event.widget() == self.quitbt:
- self.confirm_close()
- except:
- pass
- if event.widget() == self.aboutbt:
- self.aboutDialog()
- try:
- item = self.uEventQueue.get_nowait()
- if item['event'] == "device-changed":
- self.update_list_on_event()
- except Exception as e:
- pass
-
- def run(self):
+ #if event.eventType() == yui.YEvent.CancelEvent:
+ #self.confirm_close()
+ #break
try:
- self.handleevent()
+ item = self.uEventQueue.get_nowait()
+ logging.debug(f"Dealing with {item['event']}")
+ if item['event'] == "device-changed":
+ self.update_list_on_event()
+ except Exception as e:
+ pass
+
+ def run(self, debug=False):
+
+ self._setupUI()
+ # setting to False will break the event loop
+ self._running = True
+ self.timeout = 100
+
+ try:
+ self._handleEvents()
except Exception:
import traceback
traceback.print_exc()
yui.YDialog.deleteAllDialogs()
+ # Closing
+ self.dialog.destroy()
+ self.dialog = None
+ if yui.YUI.app().isTextMode():
+ self.glib_loop.quit()
+ self.glib_thread.join()
if __name__ == "__main__":