diff options
-rw-r--r-- | yui/isodumper.py | 1041 |
1 files changed, 1041 insertions, 0 deletions
diff --git a/yui/isodumper.py b/yui/isodumper.py new file mode 100644 index 0000000..2fc64a3 --- /dev/null +++ b/yui/isodumper.py @@ -0,0 +1,1041 @@ +#coding:utf-8 + +#!/usr/bin/python +# +# Copyright (c) 2007-2009 Canonical Ltd. +# +# Author: Oliver Grawert <ogra@ubuntu.com> +# +# Modifications 2013 from papoteur <papoteur@mageialinux-online.org> +# and Geiger David <david.david@mageialinux-online.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +# Requires python-parted + +# ensure we're using the latest build, if called from our build environment +import sys + +sys.path.insert(0,'../../../build/swig/python') +reload(sys) +sys.setdefaultencoding("utf-8") +########### +# imports # +########### +import yui +#import locale +import time + +#################################### +# LOCALE (important for TERMINAL!) # +#################################### +# set the locale to de/utf-8 +#locale.setlocale(locale.LC_ALL, "") +#log = yui.YUILog.instance() +#log.setLogFileName("debug.log") +#log.enableDebugLogging( True ) + +import os, re +import io +import gettext +from gettext import gettext as _ +from subprocess import call, Popen, PIPE +import dbus + + +class NoUDisks2(Exception): + pass + + +class UDisks2(object): + + BLOCK = 'org.freedesktop.UDisks2.Block' + FILESYSTEM = 'org.freedesktop.UDisks2.Filesystem' + DRIVE = 'org.freedesktop.UDisks2.Drive' + + def __init__(self): + self.bus = dbus.SystemBus() + try: + self.bus.get_object('org.freedesktop.UDisks2', + '/org/freedesktop/UDisks2') + except dbus.exceptions.DBusException as e: + if getattr(e, '_dbus_error_name', None) == 'org.freedesktop.DBus.Error.ServiceUnknown': + raise NoUDisks2() + raise + + def node_mountpoint(self,node): + + def de_mangle(raw): + return raw.replace('\\040', ' ').replace('\\011', '\t').replace('\\012', + '\n').replace('\\0134', '\\') + + for line in open('/proc/mounts').readlines(): + line = line.split() + if line[0] == node: + return de_mangle(line[1]) + return None + + def device(self, device_node_path): + device_node_path = os.path.realpath(device_node_path) + devname = device_node_path.split('/')[-1] + + # First we try a direct object path + bd = self.bus.get_object('org.freedesktop.UDisks2', + '/org/freedesktop/UDisks2/block_devices/%s'%devname) + try: + device = bd.Get(self.BLOCK, 'Device', + dbus_interface='org.freedesktop.DBus.Properties') + device = bytearray(device).replace(b'\x00', b'').decode('utf-8') + except: + device = None + + if device == device_node_path: + return bd + + # Enumerate all devices known to UDisks2 + devs = self.bus.get_object('org.freedesktop.UDisks2', + '/org/freedesktop/UDisks2/block_devices') + xml = devs.Introspect(dbus_interface='org.freedesktop.DBus.Introspectable') + for dev in re.finditer(r'name=[\'"](.+?)[\'"]', type(u'')(xml)): + bd = self.bus.get_object('org.freedesktop.UDisks2', + '/org/freedesktop/UDisks2/block_devices/%s2'%dev.group(1)) + try: + device = bd.Get(self.BLOCK, 'Device', + dbus_interface='org.freedesktop.DBus.Properties') + device = bytearray(device).replace(b'\x00', b'').decode('utf-8') + except: + device = None + if device == device_node_path: + return bd + + raise ValueError(_('%r not known to UDisks2')%device_node_path) + + def find_devices(self): + proxy = self.bus.get_object("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2") + iface = dbus.Interface(proxy, "org.freedesktop.UDisks2") + _udisks2_obj_manager = dbus.Interface(iface, "org.freedesktop.DBus.ObjectManager") + objects=_udisks2_obj_manager.GetManagedObjects() + re_drive = re.compile('(?P<path>.*?/drives/(?P<id>.*))') + re_block = re.compile('(?P<path>.*?/block_devices/(?P<id>.*))') + devs= [m.groupdict() for m in + [re_drive.match(path) for path in objects.keys()] + if m] + blocks = [m.groupdict() for m in + [re_block.match(path) for path in objects.keys()] + if m] + list=[] + + for dev in devs: + dev_obj =objects[dev['path']]['org.freedesktop.UDisks2.Drive'] + if (dev_obj['ConnectionBus'] == 'usb' or dev_obj['ConnectionBus'] == 'sdio') and \ + (dev_obj['Removable'] == 1 or dev_obj['MediaRemovable'] == 1 ): + item=[] + vend = dev_obj['Vendor'] + name = dev_obj['Model'] + for block in blocks: + if dev['path'] == objects[block['path']]['org.freedesktop.UDisks2.Block']['Drive']: + path = '/dev/'+block['path'].split('/')[-1] + size = dev_obj['Size'] + item.append(vend+" "+name) + item.append(path) + item.append(size) + list.append(item) + return list + + def mount(self, device_node_path): + try: + d = self.device(device_node_path) + mount_options = ['rw', 'noexec', 'nosuid', + 'nodev', 'uid=%d'%os.geteuid(), 'gid=%d'%os.getegid()] + r=d.Mount( + { + 'auth.no_user_interaction':True, + 'options':','.join(mount_options) + }, + dbus_interface=self.FILESYSTEM) + return unicode(r) + except: + # May be already mounted, check + mp = self.node_mountpoint(str(device_node_path)) + print mp, sys.exc_info()[0] + if mp is None: + raise ValueError(sys.exc_info()[0]) + return mp + + def unmount(self, device_node_path): + d = self.device(device_node_path) + d.Unmount({'force':True, 'auth.no_user_interaction':True}, + dbus_interface=self.FILESYSTEM) + + def drive_for_device(self, device): + drive = device.Get(self.BLOCK, 'Drive', + dbus_interface='org.freedesktop.DBus.Properties') + return self.bus.get_object('org.freedesktop.UDisks2', drive) + + def eject(self, device_node_path): + drive = self.drive_for_device(self.device(device_node_path)) + drive.Eject({'auth.no_user_interaction':True}, + dbus_interface=self.DRIVE) + +def countFiles(directory): + files = [] + if os.path.isdir(directory): + for path, dirs, filenames in os.walk(directory): + files.extend(filenames) + return len(files) + +def makedirs(dest): + if not os.path.exists(dest): + os.makedirs(dest) + +class Info(object): + def __init__(self,title,richtext,text): + self.title=title + self.richtext=richtext + self.text=text + + +class IsoDumper(object): + +# self.backup_select = self.wTree.get_widget("backup_select") +# self.backup_name = self.wTree.get_widget("backup_name") +# self.backup_button = self.wTree.get_widget("backup_button") +# self.choose = self.wTree.get_widget("choose") +# self.backup_bname = self.wTree.get_widget("bname") +# + + # set callbacks +# dict = { "on_main_dialog_destroy_event" : self.confirm_close, +# "on_main_dialog_delete_event" : self.confirm_close, +# "on_cancel_button_clicked" : self.confirm_close, +# "on_emergency_button_clicked" : self.restore, +# "on_confirm_cancel_button_clicked": self.restore, +# "on_filechooserbutton_file_set" : self.activate_devicelist, +# "on_device_combobox_changed" : self.device_selected, +# "on_nodev_close_clicked" : self.close, +# "on_backup_button_clicked" : self.backup_go, +# "on_backup_select_clicked" : self.backup_sel, +# "on_select_clicked" : self.backup_choosed, +# "on_choose_cancel_clicked" : self.backup_cancel, +# "on_format_button_clicked" : self.format_dialog, +# "on_format_cancel_clicked" : self.format_cancel, +# "on_format_go_clicked" : self.do_format, +# "on_write_button_clicked" : self.do_write, +# "on_help_close_clicked": self.help_close, +# "on_help_clicked": self.help_dialog, +# } +# self.wTree.signal_autoconnect(dict) +# +# self.window.show_all() + # make sure we have a target device + + def update_list(self ): + self.devicelist.deleteAllItems() + self.get_devices() + self.restore() + + def device_selected(self): + self.dev = self.devicelist.selectedItem().label() + if self.dev != None: + for name, path, size in self.list: + if self.dev.startswith(name): + self.deviceSize=size + self.device_name=name.rstrip().replace(' ', '') + break + self.backupbt.setEnabled() + self.formatbt.setEnabled() + self.ima.setEnabled() +# if self.chooser.get_current_folder_uri() == None : +# self.chooser.set_current_folder_uri('file:///home/'+self.user) + self.logger(_('Target Device: ')+ self.dev) + + def backup_sel(self,widget): + if self.backup_bname.get_current_folder_uri() == None : + self.backup_bname.set_current_folder_uri('file:///home/'+self.user) + self.backup_bname.set_current_name(self.device_name+".img") + self.choose.run() + + def backup_cancel(self,widget): + self.choose.hide() + # Unckeck the choice to backup + self.backupbt.setDisabled() + + def backup_choosed(self, widget): + exit_dialog=self.backup_bname.get_filename() + if exit_dialog != None: + # Add .img if not specified + if not exit_dialog.lower().endswith('.img'): + exit_dialog=exit_dialog+".img" + head, tail = os.path.split(exit_dialog) + self.backup_dest=exit_dialog + self.backup_select.set_label(tail) + self.backup_button.setEnabled() + self.backup_select.set_tooltip_text(exit_dialog) + self.logger(_('Backup in: ')+ exit_dialog) + expander = self.wTree.get_widget("detail_expander") + expander.setEnabled() + self.choose.hide() + + def format_dialog(self,widget): + self.backup_select.setDisabled() + format_button=self.wTree.get_widget("format_button") + format_button.setDisabled() + filechooserbutton=self.wTree.get_widget("filechooserbutton") + filechooserbutton.setDisabled() + write_button = self.wTree.get_widget("write_button") + write_button.setDisabled() + self.devicelist.setDisabled() + dialog=self.wTree.get_widget("format") + self.wTree.get_widget("format_device").set_text(self.dev) + self.wTree.get_widget("format_name").set_text(self.dev.split('(')[0]) + exit_dialog=dialog.run() + if exit_dialog==0: + dialog.hide() + + def do_format(self,format_type,name) : + target = self.dev.split('(')[1].split(')')[0] + info = Info(_("Formatting confirmation"),1,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) + + def restore(self): + print "restore" + self.backup_select.setEnabled() + self.backuptbt.setDisabled() + self.formatbt.setEnabled() + self.ima.setEnabled() + self.devicelist.setEnabled() + self.progress.setLabel("") + self.progress.setValue(0) + self.progress.setDisabled() + print "restored" + + def raw_format(self, usb_path, fstype, label): + self.operation=True + if os.geteuid() > 0: + launcher='pkexec' + self.process = Popen([launcher,'/usr/bin/python', '-u', '/usr/lib/isodumper/raw_format.py','-d',usb_path,'-f',fstype, '-l', label, '-u', str(os.geteuid()), '-g', str(os.getgid())], shell=False, stdout=PIPE, preexec_fn=os.setsid) + else: + self.process = Popen(['/usr/bin/python', '-u', '/usr/lib/isodumper/raw_format.py','-d',usb_path,'-f',fstype, '-l', label, '-u', str(os.geteuid()), '-g', str(os.getgid())], shell=False, stdout=PIPE, preexec_fn=os.setsid) + working=True + while working: + time.sleep(0.5) + self.process.poll() + rc=self.process.returncode + if rc is None: + working=True + else: + self.process = None + working= False + return rc + + def format_cancel(self, widget): + dialog=self.wTree.get_widget("format") + dialog.hide() + self.backup_select.setEnabled() + format_button=self.wTree.get_widget("format_button") + filechooserbutton=self.wTree.get_widget("filechooserbutton") + format_button.setEnabled() + filechooserbutton.setEnabled() + self.devicelist.setEnabled() + + def backup_go(self): + dest = self.backup_img_name + info = Info(_("Backup confirmation"),1,_("Do you want to overwrite the file?")) + if os.path.exists(dest): + if not(self.ask_YesOrNo(info)): + self.returncode = 1 + return True + st = os.statvfs(os.path.dirname(dest)) + free = st.f_bavail * st.f_frsize + if free<self.deviceSize : + sizeM=str(self.deviceSize/(1024*1024)) + message=_("The destination directory is too small to receive the backup (%s Mb needed)")%(sizeM) + self.logger(message) + self.emergency(message) + else: + self.returncode=0 + source = self.dev.split('(')[1].split(')')[0] + self.logger(_('Backup in:')+' '+dest) + self.raw_write(source, dest, self.deviceSize) + if self.returncode==0: + self.success() + + def do_write(self): +# write_button = self.wTree.get_widget("write_button") + self.writebt.setDisabled() + self.devicelist.setDisabled() + self.formatbt.setDisabled() + self.backupbt.setDisabled() + self.backup_select.setDisabled() + self.progress.setEnabled() + source = self.img_name + target = self.dev.split('(')[1].split(')')[0] + self.logger(_('Image: ')+source) + self.logger(_('Target Device: ')+self.dev) + b = os.path.getsize(source) + if b > (self.deviceSize): + message = _('The device is too small to contain the ISO file.') + self.logger(message) + self.emergency(message) + else: + info = Info(_("Writing confirmation"),1,self.warning) + if self.ask_YesOrNo(info): + if self.deviceSize> 1024*1024*1024*32 : + info = Info(_("Warning"),2,_('The device is bigger than 32 Gbytes.\ + Are you sure you want use it?')) + if self.ask_YesOrNo(info): + pass + else: + self.emergency(message) + return + self.ima.setDisabled() + self.writebt.setDisabled() + self.do_umount(target) + # Writing step + # Iso dump or Uefi preparation +# uefi_checkbox=self.wTree.get_widget("uefi_check") + if self.uefi_check.isChecked(): + #uefi mode : formats FAT32, names MGALIVE, copies the ISO + target = self.dev.split('(')[1].split(')')[0] + dev_name="MGALIVE" + rc=self.raw_format(target, 'fat32', dev_name) + if 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) + elif rc == 0: + message = _('The device was formatted successfully.') + self.logger(message) +# time.sleep(2) + seen=False + part=target+'1' + while(not seen): + try: + self.u.device(part) + seen=True + except: + seen=False + time.sleep(.5) + try: + dest=self.u.mount(part) + except: + self.logger(_("Error mounting the partition %s")%part) + self.emergency(message) + return + if dest!="": + self.logger(_("Mounted in: ")) + self.returncode=0 + self.files_write(source, dest) + self.u.unmount(part) + self.operation=False + if self.returncode==0: + self.success() + else: + self.logger(_("Error copying files")) + self.emergency(message) + else: + self.operation=False + self.logger(_("Error mounting the partition %s")%part) + self.emergency(message) + else: + message = _('An error occurred.') + self.emergency(message) + else: + #Dump mode + self.returncode=0 + b=os.path.getsize(source) + print "Launch write", source, target, b + self.raw_write(source, target, b) +# gobject.idle_add(task.next) +# while gtk.events_pending(): +# gtk.main_iteration(True) + self.check_write(target, b) +# gobject.idle_add(task.next) +# while gtk.events_pending(): +# gtk.main_iteration(True) + if self.returncode == 0: + self.success() + else: + self.devicelist.setEnabled() + self.writebt.setEnabled() + self.formatbt.setEnabled() + self.backup_select.setEnabled() + def do_umount(self, target): + mounts = self.get_mounted(target) + if mounts: + self.logger(_('Unmounting all partitions of ')+target+':') + for mount in mounts: + self.logger(_('Trying to unmount ')+mount[0]+'...') +# while gtk.events_pending(): +# gtk.main_iteration(True) + try: + retcode = call('umount '+mount[0], shell=True) + if retcode < 0: + message = _('Error, umount ')+mount[0]+_(' was terminated by signal ')+str(retcode) + self.logger(message) + self.emergency(message) + else: + if retcode == 0: + self.logger(mount[0]+_(' successfully unmounted')) + else: + message = _('Error, umount ')+mount[0]+_(' returned ')+str(retcode) + self.logger(message) + self.emergency(message) + except OSError, e: + message = _('Execution failed: ')+str(e) + self.logger(message) + self.emergency(message) + + def get_mounted(self, target): + try: + lines = [line.strip("\n").split(" ") for line in open ("/etc/mtab", "r").readlines()] + return [mount for mount in lines if mount[0].startswith(target)] + except: + message = _('Could not read mtab !') + self.logger(message) + self.emergency(message) + + def raw_write(self, source, target, b): + self.operation=True + bs=4096*128 + try: + ifc=io.open(source, "rb",1) + except: + message = _('Reading error.')+ source + self.logger(message) + self.emergency(message) + return + else: + try: + ofc= io.open(target, 'wb',0) + except: + message = _('You have not the rights for writing on the device') + self.logger(message) + self.emergency(message) + self.close('dummy') + else: + self.progress.setEnabled() + self.progress.setLabel(_('Writing ')+source.split('/')[-1]+_(' to ')+target.split('/')[-1]) + self.logger(_('Executing copy from ')+source+_(' to ')+target) + steps=range(0, b+1, b/100) + steps.append(b) + indice=1 + written=0 + ncuts=b/bs + while ncuts <= 100: + bs=bs/2 + ncuts=b/bs + for i in xrange(0,ncuts+1): + try: + buf=ifc.read(bs) + except: + message = _("Reading error.") + self.logger(message) + self.emergency(message) + return + try: + ofc.write(buf) + except: + message = _("Writing error.") + self.logger(message) + self.emergency(message) + return + written+=len(buf) + if written > steps[indice]: + if indice%1==0: + self.logger(_('Wrote: ')+str(indice)+'% '+str(written)+' bytes') + self.progress.setValue(indice) + indice +=1 + try: + os.fsync(ofc) + except: + message = _("Writing error.") + self.logger(message) + self.emergency(message) + return + self.progress.setValue(100) + self.logger(_('Image ')+source.split('/')[-1]+_(' successfully written to ')+target) + self.logger(_('Bytes written: ')+str(written)) + try: + ofc.close() + except: + message = _("Writing error.") + self.logger(message) + self.emergency(message) + ifc.close() + + def check_write(self, target, b): + import hashlib + self.progress.setEnabled() + self.progress.setLabel(_('Checking ')+target.split('/')[-1]) + self.progress.setValue(0) + steps=range(0, b+1, b/100) + steps.append(b) + indice=0 + checked=0 + sha1func=hashlib.sha1() + md5func=hashlib.md5() + ncuts=b/1024 + try: + with open(target, 'rb') as f: + for x in xrange(0,ncuts): + block = f.read(1024) + sha1func.update(block) + md5func.update(block) + if checked > steps[indice]: + self.progress.setValue(indice) + indice +=1 + checked+=1024 + block = f.read(b-ncuts*1024) + sha1func.update(block) + md5func.update(block) + sha1sumcalc=sha1func.hexdigest() + md5sumcalc=md5func.hexdigest() + self.logger(_('SHA1 sum: ')+sha1sumcalc) + self.logger(_('MD5 sum: ')+md5sumcalc) + f.close() + except: + pass + self.progress.setValue(100) + + def files_write(self, source, dest): + self.operation=True + temp_dir='/mnt/MGALIVE' + makedirs(temp_dir) + self.process=Popen(['mount', '-o', 'loop',source,temp_dir ], shell=False, stdout=PIPE) + working=True + while working: + time.sleep(0.5) + self.process.poll() + rc=self.process.returncode + if rc is None: + working=True + else: + self.process = None + working=False + self.logger(_('ISO image mounted in ')+temp_dir) + self.progress.setEnabled() + self.progress.setLabel(_('Writing ')+source.split('/')[-1]+_(' to ')+dest.encode()) + self.logger(_('Executing copy from ')+source+_(' to ')+dest.encode()) + total_files=countFiles(temp_dir) + self.logger(_("%s file(s) to copy."%total_files)) + cumuled_size=0 + if total_files > 0: + for path, dirs, filenames in os.walk(temp_dir): + for directory in dirs: + destDir = path.replace(temp_dir,dest) + makedirs(os.path.join(destDir, directory)) + for sfile in filenames: + srcFile = os.path.join(path, sfile) + destFile = os.path.join(path.replace(temp_dir, dest), sfile) + try: + with open(srcFile, 'rb') as fsrc: + with open(destFile, 'wb') as fdst: + while 1: + buf = fsrc.read(256*1024) + if not buf: + os.fsync(fdst) + break + fdst.write(buf) + cumuled_size += len(buf) + self.progress.setValue(int(cumuled_size*100/total_files)) + except: + self.returncode=1 + return + self.process = Popen(['umount', temp_dir ], shell=False, stdout=PIPE) + while True : + self.process.poll() + if self.process.returncode != None: + break + self.logger(_('Image ')+source.split('/')[-1]+_(' successfully written to ')+dest.encode()) + else: + self.returncode=1 + + def success(self): + self.operation=False + self.final_unsensitive() + info = Info(_("Success"),1,_("The operation was successfully performed.\n\ + You are free to unplug it now, a log isodumper.log\n\ + of the operation will be saved in your homedir/.isodumper/ when\n\ + you close the application.")) + if self.ask_OK(info) : + return + + + def confirm_close(self, *args): + if self.operation==False: # no writing , backup nor format running + self.close('dummy') + else: # writing , backup or format running + info = Info(_("Success"),1,_("Writing is in progress. Exiting during writing \n\ + will occur that the device or the backup will be unusable.\n\ + Are you sure you want to quit during writing?")) + if self.ask_YesOrNo(info) : + return True + else: + return False + + def emergency(self,message): + self.operation=False + self.returncode=1 + self.final_unsensitive() +# expander = self.wTree.get_widget("detail_expander") +# expander.set_expanded(True) +# mark = self.log.create_mark("end", self.log.get_end_iter(), False) +# self.logview.scroll_to_mark(mark, 0.05, True, 0.0, 1.0) + info = Info(_("Error"),1,message) + self.ask_OK(info) +# self.close() + + def final_unsensitive(self): + self.ima.setDisabled() + self.devicelist.setDisabled() + self.writebt.setDisabled() + self.progress.setDisabled() + self.backup_select.setDisabled() + + def close(self, widget): + self.write_logfile() +# gtk.main_quit() + exit(0) + + def write_logfile(self): + start = self.log.get_start_iter() + end = self.log.get_end_iter() + import pwd + pw = pwd.getpwnam(self.user) + uid = pw.pw_uid + gid=pw.pw_gid + if (self.user != 'root') and (self.user !=''): + logpath='/home/'+self.user+'/.isodumper' + os.setgid(gid) + os.setuid(uid) + if not(os.path.isdir(logpath)): + os.mkdir(logpath) + else: + logpath='/root' + logfile=open(logpath+'/isodumper.log',"w") + logfile.write(self.log.get_text(start, end, False)) + logfile.close() + + print self.log.get_text(start, end, False) + + def logger(self, text): + self.logview.appendLines(text+"\n") + + def activate_devicelist(self, widget): +# label = self.wTree.get_widget("to_label") + expander = self.wTree.get_widget("detail_expander") +# self.devicelist.setEnabled() + expander.setEnabled() +# label.setEnabled() +# self.img_name = self.chooser.get_filename() + write_button = self.wTree.get_widget("write_button") + write_button.setEnabled() + self.logger(_('Image ')+": "+ self.img_name) + self.chooser.set_tooltip_text(self.img_name) + + def activate_backup(self, widget): + self.backup_img_name = self.backup_dir.get_filename() + +# def expander_control(self, widget): +# # this is darn ugly but still better than the UI behavior of +# # the unexpanded expander which doesnt reset the window size +# if widget.get_expanded(): +# gobject.timeout_add(130, lambda: self.window.reshow_with_initial_size()) + + def help_dialog(self, widget): + dialog = self.wTree.get_widget("help_dialog") + dialog.run() + + def help_close(self, widget): + dialog = self.wTree.get_widget("help_dialog") + dialog.hide() + + def about(self, widget): + about_button = self.wTree.get_widget("about_button") + about_button.setEnabled() + dialog = self.wTree.get_widget("about_dialog") + resp = dialog.run() + if resp: + dialog.hide() + + def __init__(self,user): + APP="isodumper" + DIR="/usr/share/locale" + self.RELEASE="v0.40" + + gettext.bindtextdomain(APP, DIR) + gettext.textdomain(APP) + + # for the localisation of log file + self.user = user + + # define size of the selected device + self.deviceSize=0 + + # Operation running + self.operation=False + + self.warning = _("Warning\nThis will destroy all data on the target device,\n\ + are you sure you want to proceed?\n\ + If you say ok here, please <b>do not unplug</b>\ + the device during the following operation.") + """ + Init/Constructor for the 'widgets' + """ + self.atelier = yui.YUI.widgetFactory() + self.dialog = self.atelier.createMainDialog() + # create the main gui + # +---+-----------------+ + # + banner + + # +---+-----------------+ + # | L | device | + # +---+-----+------+----+ + # + W | ima | u | writebt | + # +---+-----+------+----+ + # + B | backup_select | backupbt | + # +---+-----+------+----+ + # + F | bf | + # +----------------+----+ + # | progress | + # +---------------------+ + # | report | + # +---------------------+ + # | ba | bp | bh | bq | + # +---------------------+ + self.ancrage = self.atelier.createReplacePoint(self.dialog) + self.box = self.atelier.createVBox(self.ancrage) + self.bannerbox = self.atelier.createHBox(self.box) +# self.bannerbox.setWeight(1,15) + self.banner=self.atelier.createImage(self.bannerbox,"/usr/share/isodumper/header.png") +# self.atelier.createLabel( self.hautbox, "ATELIER ANNUITÉS") + self.devicebox = self.atelier.createHBox(self.box) + self.devicebox.setWeight(1,10) + self.devicelist=self.atelier.createComboBox(self.devicebox,_("Device to use:"),False) + self.devicelist.setStretchable(0,True) + self.writebox = self.atelier.createHBox(self.box) + self.writebox.setWeight(1,10) + self.deviceLabel=self.atelier.createLabel(self.writebox,_("Write Image:")) + # add file picker + self.ima=self.atelier.createPushButton(self.writebox,"Choose an image") + self.ima.setStretchable(0,True) + self.uefi_check=self.atelier.createCheckBox(self.writebox,_("For UEFI")) + self.writebt = self.atelier.createPushButton(self.writebox, _("&Write" )) + self.writebt.setStretchable(0,True) + self.writebt.setDisabled() + self.backupbox = self.atelier.createHBox(self.box) + self.backupbox.setWeight(1,10) + self.atelier.createLabel(self.backupbox,_("Backup to:")) + self.backup_select=self.atelier.createPushButton(self.backupbox,"Choose an image") + self.backup_select.setStretchable(0,True) + # add file picker + # + self.backupbt = self.atelier.createPushButton(self.backupbox, _("&Backup" )) + self.backupbt.setStretchable(0,True) + self.backupbt.setDisabled() + self.formatbox = self.atelier.createHBox(self.box) + self.formatbox.setWeight(1,10) + self.atelier.createLabel(self.formatbox,_("Format the device in FAT, NTFS or ext:")) + self.formatbt = self.atelier.createPushButton(self.formatbox, _("&Format" )) + self.formatbt.setStretchable(0,True) + self.progressbox = self.atelier.createHBox(self.box) + self.progressbox.setWeight(1,10) + self.progress = self.atelier.createProgressBar(self.progressbox,"Progression",100) + self.reportbox = self.atelier.createHBox(self.box) + self.reportbox.setWeight(1,10) + self.logview = self.atelier.createLogView(self.reportbox,"Report", 10) + self.reportbox.setWeight(1,20) + self.buttonsbox = self.atelier.createHBox(self.box) + self.buttonsbox.setWeight(1,10) +# self.cadregauche= self.atelier.createFrame(self.mainhbox,"Traitements par lots") + self.refreshbt = self.atelier.createPushButton(self.buttonsbox, _("&Refresh" )) + self.refreshbt.setStretchable(0,True) + self.aboutbt = self.atelier.createPushButton(self.buttonsbox, _("&About" )) + self.aboutbt.setStretchable(0,True) + self.helpbt = self.atelier.createPushButton(self.buttonsbox, _("&Help" )) + self.helpbt.setStretchable(0,True) + self.quitbt = self.atelier.createPushButton(self.buttonsbox, _("&Quit" )) + self.quitbt.setStretchable(0,True) + #self.display = self.factory.createReplacePoint(self.framedisplayminsize) # here we change the widget + + self.u = None + try: + self.u = UDisks2() + except : + message = _('UDisks2 is not available on your system') + self.logger(message) + self.emergency(message) + self.get_devices() + self.device_selected() + self.dialog.recalcLayout() + self.ancrage.showChild() + + def ask_format(self): + atelier = yui.YUI.widgetFactory() + dialog = atelier.createPopupDialog() +# dialog.setTitle(_("Choose format")) + vb=atelier.createVBox(dialog) + label = atelier.createInputField(vb,_("Label for the device:")) + cr = atelier.createRadioButtonGroup(vb) + vb_cr = atelier.createVBox(cr) + format_fat = atelier.createRadioButton(vb_cr,_("FAT 32 (Windows)")) + format_ntfs = atelier.createRadioButton((vb_cr),_("NTFS (Windows)")) + format_ext = atelier.createRadioButton((vb_cr),_("ext4 (Linux)")) + bb = atelier.createHBox(vb) + executebt = atelier.createPushButton(bb,_("Execute")) + cancelbt = atelier.createPushButton(bb,_("Cancel")) + dialog.open() + while True: + event = dialog.waitForEvent() + if event.eventType() == yui.YEvent.CancelEvent: + dialog.destroy() + return "no", "no" + if event.widget() == executebt: + if format_fat.value(): + return 'fat32', label.value().upper()[:11] + if format_ntfs.value(): + #dialog.destroy() + return 'ntfs', label.value()[:32] + if format_ext.value(): + #dialog.destroy() + return 'ext4', label.value() + if event.widget() == cancelbt: + return "no","no" + + + def ask_OK(self, info): + yui.YUI.widgetFactory + mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga")) + dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_ONE) + dlg.setTitle(info.title) + dlg.setText(info.text, info.richtext) + dlg.setButtonLabel("OK", yui.YMGAMessageBox.B_ONE) + dlg.setMinSize(50, 5); + return dlg.show() == yui.YMGAMessageBox.B_ONE + + def ask_YesOrNo(self, info): + yui.YUI.widgetFactory + mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga")) + dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_TWO) + dlg.setTitle(info.title) + dlg.setText(info.text, info.richtext) + dlg.setButtonLabel("Yes", yui.YMGAMessageBox.B_ONE) + dlg.setButtonLabel("No", yui.YMGAMessageBox.B_TWO) + dlg.setMinSize(70, 8); + return dlg.show() == yui.YMGAMessageBox.B_ONE + + def aboutDialog(self): + yui.YUI.widgetFactory; + mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga")) + dlg = mgafactory.createAboutDialog("About Isodumper", self.RELEASE, "GPLv2", + "Oliver Grawert\nPapoteur", "A tool for writing ISO images to a device", "") + dlg.show(); + + def nodevDialog(self): + yui.YUI.widgetFactory + mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga")) + dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_TWO) + dlg.setTitle("IsoDumper") + dlg.setText("Warning\nNo target devices were found.\nYou need to plug in a USB Key to which the image can be written.","") + dlg.setButtonLabel("Refresh", yui.YMGAMessageBox.B_ONE) + dlg.setButtonLabel("Cancel", yui.YMGAMessageBox.B_TWO) + dlg.setMinSize(70, 8); + return dlg.show() == yui.YMGAMessageBox.B_ONE + + def handleevent(self): + self.traitement=None + while True: + event = self.dialog.waitForEvent() + if event.eventType() == yui.YEvent.CancelEvent: + self.dialog.destroy() + break + if event.widget() == self.quitbt: + self.dialog.destroy() + break + if event.widget() == self.ima: + self.img_name=yui.YUI.app().askForExistingFile('file:///home/'+self.user,"*.iso *.img","Choose an image") + self.ima.setLabel(self.img_name) + self.writebt.setEnabled() + if event.widget() == self.writebt: + self.do_write() + if event.widget() == self.backupbt: + self.backup_go() + if event.widget() == self.backup_select: + self.backup_img_name=yui.YUI.app().askForSaveFileName('file:///home/'+self.user,"*.img","Backup in") + self.backup_select.setLabel(self.backup_img_name) + self.backupbt.setEnabled() + if event.widget() == self.formatbt: + format_type,name = self.ask_format() + self.dialog.activate() + self.do_format(format_type,name) + 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() + def get_devices(self): +# dialog = self.wTree.get_widget("nodev_dialog") + self.list=self.u.find_devices() + while len(self.list)==0: + if self.nodevDialog(): + self.list = self.u.find_devices() + else: + self.dialog.destroy() + break + for name, path, size in self.list: + # convert in Mbytes + sizeM=str(int(size)/(1024*1024)) + self.devicelist.addItem(str(name+' ('+path.lstrip()+') '+sizeM+_('Mb'))) + +if __name__ == "__main__": + import sys + user=sys.argv[1] + app = IsoDumper(user) + app.handleevent() + + |