Suggested changes
included changes as suggested by @marmarek.
This commit is contained in:
parent
df31207028
commit
bb8abff988
@ -27,6 +27,7 @@ disable=
|
|||||||
duplicate-code,
|
duplicate-code,
|
||||||
file-ignored,
|
file-ignored,
|
||||||
fixme,
|
fixme,
|
||||||
|
inconsistent-return-statements,
|
||||||
locally-disabled,
|
locally-disabled,
|
||||||
locally-enabled,
|
locally-enabled,
|
||||||
logging-format-interpolation,
|
logging-format-interpolation,
|
||||||
|
@ -46,11 +46,11 @@ import time
|
|||||||
|
|
||||||
class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
||||||
|
|
||||||
def __init__(self, app, qvm_collection, parent=None):
|
def __init__(self, qt_app, qubes_app, parent=None):
|
||||||
super(BackupVMsWindow, self).__init__(parent)
|
super(BackupVMsWindow, self).__init__(parent)
|
||||||
|
|
||||||
self.app = app
|
self.qt_app = qt_app
|
||||||
self.qvm_collection = qvm_collection
|
self.qubes_app = qubes_app
|
||||||
self.backup_settings = QtCore.QSettings()
|
self.backup_settings = QtCore.QSettings()
|
||||||
|
|
||||||
self.selected_vms = []
|
self.selected_vms = []
|
||||||
@ -98,9 +98,9 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
|
|
||||||
self.target_vm_list, self.target_vm_idx = utils.prepare_vm_choice(
|
self.target_vm_list, self.target_vm_idx = utils.prepare_vm_choice(
|
||||||
self.appvm_combobox,
|
self.appvm_combobox,
|
||||||
self.qvm_collection,
|
self.qubes_app,
|
||||||
None,
|
None,
|
||||||
self.qvm_collection.domains['dom0'],
|
self.qubes_app.domains['dom0'],
|
||||||
(lambda vm: vm.klass != 'TemplateVM' and vm.is_running()),
|
(lambda vm: vm.klass != 'TemplateVM' and vm.is_running()),
|
||||||
allow_internal=False,
|
allow_internal=False,
|
||||||
allow_default=False,
|
allow_default=False,
|
||||||
@ -111,6 +111,13 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
self.__fill_vms_list__(selected)
|
self.__fill_vms_list__(selected)
|
||||||
|
|
||||||
def load_settings(self):
|
def load_settings(self):
|
||||||
|
"""
|
||||||
|
Helper function that tries to load existing backup profile
|
||||||
|
(default path: /etc/qubes/backup/qubes-manager-backup.conf )
|
||||||
|
and then apply its contents to the Backup window.
|
||||||
|
:return: list of vms to include in backup, if it exists in the profile,
|
||||||
|
or None if it does not
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
profile_data = backup_utils.load_backup_profile()
|
profile_data = backup_utils.load_backup_profile()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
@ -147,6 +154,13 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def save_settings(self, use_temp):
|
def save_settings(self, use_temp):
|
||||||
|
"""
|
||||||
|
Helper function that saves backup profile to either
|
||||||
|
/etc/qubes/backup/qubes-manager-backup.conf or
|
||||||
|
/etc/qubes/backup/qubes-manager-backup-tmp.conf
|
||||||
|
:param use_temp: whether to use temporary profile (True) or the default
|
||||||
|
backup profile (False)
|
||||||
|
"""
|
||||||
settings = {'destination_vm': self.appvm_combobox.currentText(),
|
settings = {'destination_vm': self.appvm_combobox.currentText(),
|
||||||
'destination_path': self.dir_line_edit.text(),
|
'destination_path': self.dir_line_edit.text(),
|
||||||
'include': [vm.name for vm in self.selected_vms],
|
'include': [vm.name for vm in self.selected_vms],
|
||||||
@ -169,7 +183,7 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
vm.name + " (" + admin_utils.size_to_human(self.size) + ")")
|
vm.name + " (" + admin_utils.size_to_human(self.size) + ")")
|
||||||
|
|
||||||
def __fill_vms_list__(self, selected=None):
|
def __fill_vms_list__(self, selected=None):
|
||||||
for vm in self.qvm_collection.domains:
|
for vm in self.qubes_app.domains:
|
||||||
if vm.features.get('internal', False):
|
if vm.features.get('internal', False):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -248,11 +262,11 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
msg = []
|
msg = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
vm = self.qvm_collection.domains[
|
vm = self.qubes_app.domains[
|
||||||
self.appvm_combobox.currentText()]
|
self.appvm_combobox.currentText()]
|
||||||
if not vm.is_running():
|
if not vm.is_running():
|
||||||
vm.start()
|
vm.start()
|
||||||
self.qvm_collection.qubesd_call(
|
self.qubes_app.qubesd_call(
|
||||||
'dom0', 'admin.backup.Execute',
|
'dom0', 'admin.backup.Execute',
|
||||||
backup_utils.get_profile_name(True))
|
backup_utils.get_profile_name(True))
|
||||||
except Exception as ex: # pylint: disable=broad-except
|
except Exception as ex: # pylint: disable=broad-except
|
||||||
@ -263,13 +277,19 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
|
|
||||||
t_monitor.set_finished()
|
t_monitor.set_finished()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cleanup_temporary_files():
|
||||||
|
try:
|
||||||
|
os.remove(backup_utils.get_profile_path(use_temp=True))
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
def current_page_changed(self, page_id): # pylint: disable=unused-argument
|
def current_page_changed(self, page_id): # pylint: disable=unused-argument
|
||||||
old_sigchld_handler = signal.signal(signal.SIGCHLD, signal.SIG_DFL)
|
old_sigchld_handler = signal.signal(signal.SIGCHLD, signal.SIG_DFL)
|
||||||
if self.currentPage() is self.confirm_page:
|
if self.currentPage() is self.confirm_page:
|
||||||
|
|
||||||
self.save_settings(True)
|
self.save_settings(use_temp=True)
|
||||||
backup_summary = self.qvm_collection.qubesd_call(
|
backup_summary = self.qubes_app.qubesd_call(
|
||||||
'dom0', 'admin.backup.Info',
|
'dom0', 'admin.backup.Info',
|
||||||
backup_utils.get_profile_name(True))
|
backup_utils.get_profile_name(True))
|
||||||
|
|
||||||
@ -280,7 +300,7 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
elif self.currentPage() is self.commit_page:
|
elif self.currentPage() is self.commit_page:
|
||||||
|
|
||||||
if self.save_profile_checkbox.isChecked():
|
if self.save_profile_checkbox.isChecked():
|
||||||
self.save_settings(False)
|
self.save_settings(use_temp=False)
|
||||||
|
|
||||||
self.button(self.FinishButton).setDisabled(True)
|
self.button(self.FinishButton).setDisabled(True)
|
||||||
self.showFileDialog.setEnabled(
|
self.showFileDialog.setEnabled(
|
||||||
@ -296,7 +316,7 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
while not self.thread_monitor.is_finished():
|
while not self.thread_monitor.is_finished():
|
||||||
self.app.processEvents()
|
self.qt_app.processEvents()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
if not self.thread_monitor.success:
|
if not self.thread_monitor.success:
|
||||||
@ -325,18 +345,21 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, multiselectwidget.QtGui.QWizard):
|
|||||||
self.button(self.CancelButton).setEnabled(False)
|
self.button(self.CancelButton).setEnabled(False)
|
||||||
self.button(self.FinishButton).setEnabled(True)
|
self.button(self.FinishButton).setEnabled(True)
|
||||||
self.showFileDialog.setEnabled(False)
|
self.showFileDialog.setEnabled(False)
|
||||||
|
self.cleanup_temporary_files()
|
||||||
signal.signal(signal.SIGCHLD, old_sigchld_handler)
|
signal.signal(signal.SIGCHLD, old_sigchld_handler)
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
if self.currentPage() is self.commit_page:
|
if self.currentPage() is self.commit_page:
|
||||||
self.canceled = True
|
self.canceled = True
|
||||||
self.qvm_collection.qubesd_call(
|
self.qubes_app.qubesd_call(
|
||||||
'dom0', 'admin.backup.Cancel',
|
'dom0', 'admin.backup.Cancel',
|
||||||
backup_utils.get_profile_name(True))
|
backup_utils.get_profile_name(True))
|
||||||
self.progress_bar.setMaximum(100)
|
self.progress_bar.setMaximum(100)
|
||||||
self.progress_bar.setValue(0)
|
self.progress_bar.setValue(0)
|
||||||
self.button(self.CancelButton).setDisabled(True)
|
self.button(self.CancelButton).setDisabled(True)
|
||||||
|
self.cleanup_temporary_files()
|
||||||
else:
|
else:
|
||||||
|
self.cleanup_temporary_files()
|
||||||
self.done(0)
|
self.done(0)
|
||||||
|
|
||||||
def has_selected_vms(self):
|
def has_selected_vms(self):
|
||||||
@ -374,21 +397,21 @@ def handle_exception(exc_type, exc_value, exc_traceback):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
qtapp = QtGui.QApplication(sys.argv)
|
qt_app = QtGui.QApplication(sys.argv)
|
||||||
qtapp.setOrganizationName("The Qubes Project")
|
qt_app.setOrganizationName("The Qubes Project")
|
||||||
qtapp.setOrganizationDomain("http://qubes-os.org")
|
qt_app.setOrganizationDomain("http://qubes-os.org")
|
||||||
qtapp.setApplicationName("Qubes Backup VMs")
|
qt_app.setApplicationName("Qubes Backup VMs")
|
||||||
|
|
||||||
sys.excepthook = handle_exception
|
sys.excepthook = handle_exception
|
||||||
|
|
||||||
app = Qubes()
|
app = Qubes()
|
||||||
|
|
||||||
backup_window = BackupVMsWindow(qtapp, app)
|
backup_window = BackupVMsWindow(qt_app, app)
|
||||||
|
|
||||||
backup_window.show()
|
backup_window.show()
|
||||||
|
|
||||||
qtapp.exec_()
|
qt_app.exec_()
|
||||||
qtapp.exit()
|
qt_app.exit()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -31,15 +31,18 @@ path_max_len = 512
|
|||||||
|
|
||||||
|
|
||||||
def fill_appvms_list(dialog):
|
def fill_appvms_list(dialog):
|
||||||
|
"""
|
||||||
|
Helper function, designed to fill the destination vm combobox in both backup
|
||||||
|
and restore GUI tools.
|
||||||
|
:param dialog: QtGui.QWizard with a combobox called appvm_combobox
|
||||||
|
"""
|
||||||
dialog.appvm_combobox.clear()
|
dialog.appvm_combobox.clear()
|
||||||
dialog.appvm_combobox.addItem("dom0")
|
dialog.appvm_combobox.addItem("dom0")
|
||||||
|
|
||||||
dialog.appvm_combobox.setCurrentIndex(0) # current selected is null ""
|
dialog.appvm_combobox.setCurrentIndex(0) # current selected is null ""
|
||||||
|
|
||||||
for vm in dialog.qvm_collection.domains:
|
for vm in dialog.qubes_app.domains:
|
||||||
if vm.klass == 'AppVM' and vm.features.get('internal', False):
|
if vm.features.get('internal', False) or vm.klass == 'TemplateVM':
|
||||||
continue
|
|
||||||
if vm.klass == 'TemplateVM' and vm.installed_by_rpm:
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if vm.is_running() and vm.qid != 0:
|
if vm.is_running() and vm.qid != 0:
|
||||||
@ -52,6 +55,17 @@ def enable_dir_line_edit(dialog, boolean):
|
|||||||
|
|
||||||
|
|
||||||
def select_path_button_clicked(dialog, select_file=False, read_only=False):
|
def select_path_button_clicked(dialog, select_file=False, read_only=False):
|
||||||
|
"""
|
||||||
|
Helper function that displays a file/directory selection wizard. Used by
|
||||||
|
backup and restore GUI tools.
|
||||||
|
:param dialog: QtGui.QWizard with a dir_line_edit text box that wants to
|
||||||
|
receive a file/directory path and appvm_combobox with VM to use
|
||||||
|
:param select_file: True: select file dialog; False: select directory
|
||||||
|
dialog
|
||||||
|
:param read_only: should the dir_line_edit be changed after selecting a file
|
||||||
|
or directory
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
backup_location = str(dialog.dir_line_edit.text())
|
backup_location = str(dialog.dir_line_edit.text())
|
||||||
file_dialog = QtGui.QFileDialog()
|
file_dialog = QtGui.QFileDialog()
|
||||||
file_dialog.setReadOnly(True)
|
file_dialog.setReadOnly(True)
|
||||||
@ -59,7 +73,7 @@ def select_path_button_clicked(dialog, select_file=False, read_only=False):
|
|||||||
new_path = None
|
new_path = None
|
||||||
|
|
||||||
new_appvm = str(dialog.appvm_combobox.currentText())
|
new_appvm = str(dialog.appvm_combobox.currentText())
|
||||||
vm = dialog.qvm_collection.domains[new_appvm]
|
vm = dialog.qubes_app.domains[new_appvm]
|
||||||
try:
|
try:
|
||||||
new_path = utils.get_path_from_vm(
|
new_path = utils.get_path_from_vm(
|
||||||
vm,
|
vm,
|
||||||
@ -81,6 +95,18 @@ def select_path_button_clicked(dialog, select_file=False, read_only=False):
|
|||||||
dialog.select_dir_page.emit(QtCore.SIGNAL("completeChanged()"))
|
dialog.select_dir_page.emit(QtCore.SIGNAL("completeChanged()"))
|
||||||
|
|
||||||
|
|
||||||
|
def get_profile_name(use_temp):
|
||||||
|
backup_profile_name = 'qubes-manager-backup'
|
||||||
|
temp_backup_profile_name = 'qubes-manager-backup-tmp'
|
||||||
|
|
||||||
|
return temp_backup_profile_name if use_temp else backup_profile_name
|
||||||
|
|
||||||
|
|
||||||
|
def get_profile_path(use_temp):
|
||||||
|
path = '/etc/qubes/backup/' + get_profile_name(use_temp) + '.conf'
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
def load_backup_profile(use_temp=False):
|
def load_backup_profile(use_temp=False):
|
||||||
|
|
||||||
path = get_profile_path(use_temp)
|
path = get_profile_path(use_temp)
|
||||||
@ -102,15 +128,3 @@ def write_backup_profile(args, use_temp=False):
|
|||||||
|
|
||||||
with open(path, 'w') as profile_file:
|
with open(path, 'w') as profile_file:
|
||||||
yaml.safe_dump(profile_data, profile_file)
|
yaml.safe_dump(profile_data, profile_file)
|
||||||
|
|
||||||
|
|
||||||
def get_profile_name(use_temp):
|
|
||||||
backup_profile_name = 'qubes-manager-backup'
|
|
||||||
temp_backup_profile_name = 'qubes-manager-backup-tmp'
|
|
||||||
|
|
||||||
return temp_backup_profile_name if use_temp else backup_profile_name
|
|
||||||
|
|
||||||
|
|
||||||
def get_profile_path(use_temp):
|
|
||||||
path = '/etc/qubes/backup/' + get_profile_name(use_temp) + '.conf'
|
|
||||||
return path
|
|
||||||
|
@ -28,6 +28,8 @@ import time
|
|||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import traceback
|
import traceback
|
||||||
|
import logging
|
||||||
|
import logging.handlers
|
||||||
|
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
@ -46,15 +48,22 @@ from qubesadmin.backup import restore
|
|||||||
|
|
||||||
class RestoreVMsWindow(ui_restoredlg.Ui_Restore, QtGui.QWizard):
|
class RestoreVMsWindow(ui_restoredlg.Ui_Restore, QtGui.QWizard):
|
||||||
|
|
||||||
def __init__(self, app, qvm_collection, parent=None):
|
def __init__(self, qt_app, qubes_app, parent=None):
|
||||||
super(RestoreVMsWindow, self).__init__(parent)
|
super(RestoreVMsWindow, self).__init__(parent)
|
||||||
|
|
||||||
self.app = app
|
self.qt_app = qt_app
|
||||||
self.qvm_collection = qvm_collection
|
self.qubes_app = qubes_app
|
||||||
|
|
||||||
self.vms_to_restore = None
|
self.vms_to_restore = None
|
||||||
self.func_output = []
|
self.func_output = []
|
||||||
|
|
||||||
|
# Set up logging
|
||||||
self.feedback_queue = Queue()
|
self.feedback_queue = Queue()
|
||||||
|
handler = logging.handlers.QueueHandler(self.feedback_queue)
|
||||||
|
logger = logging.getLogger('qubesadmin.backup')
|
||||||
|
logger.addHandler(handler)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
self.canceled = False
|
self.canceled = False
|
||||||
self.error_detected = Event()
|
self.error_detected = Event()
|
||||||
self.thread_monitor = None
|
self.thread_monitor = None
|
||||||
@ -104,12 +113,12 @@ class RestoreVMsWindow(ui_restoredlg.Ui_Restore, QtGui.QWizard):
|
|||||||
|
|
||||||
self.target_appvm = None
|
self.target_appvm = None
|
||||||
if self.appvm_combobox.currentIndex() != 0: # An existing appvm chosen
|
if self.appvm_combobox.currentIndex() != 0: # An existing appvm chosen
|
||||||
self.target_appvm = self.qvm_collection.domains[
|
self.target_appvm = self.qubes_app.domains[
|
||||||
str(self.appvm_combobox.currentText())]
|
str(self.appvm_combobox.currentText())]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.backup_restore = restore.BackupRestore(
|
self.backup_restore = restore.BackupRestore(
|
||||||
self.qvm_collection,
|
self.qubes_app,
|
||||||
self.dir_line_edit.text(),
|
self.dir_line_edit.text(),
|
||||||
self.target_appvm,
|
self.target_appvm,
|
||||||
self.passphrase_line_edit.text()
|
self.passphrase_line_edit.text()
|
||||||
@ -138,13 +147,6 @@ class RestoreVMsWindow(ui_restoredlg.Ui_Restore, QtGui.QWizard):
|
|||||||
def append_output(self, text):
|
def append_output(self, text):
|
||||||
self.commit_text_edit.append(text)
|
self.commit_text_edit.append(text)
|
||||||
|
|
||||||
def restore_error_output(self, text):
|
|
||||||
self.error_detected.set()
|
|
||||||
self.append_output(u'<font color="red">{0}</font>'.format(text))
|
|
||||||
|
|
||||||
def restore_output(self, text):
|
|
||||||
self.append_output(u'<font color="black">{0}</font>'.format(text))
|
|
||||||
|
|
||||||
def __do_restore__(self, t_monitor):
|
def __do_restore__(self, t_monitor):
|
||||||
err_msg = []
|
err_msg = []
|
||||||
try:
|
try:
|
||||||
@ -212,14 +214,20 @@ class RestoreVMsWindow(ui_restoredlg.Ui_Restore, QtGui.QWizard):
|
|||||||
args=(self.thread_monitor,))
|
args=(self.thread_monitor,))
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
while not self.thread_monitor.is_finished():
|
while not self.thread_monitor.is_finished():
|
||||||
self.app.processEvents()
|
self.qt_app.processEvents()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
try:
|
try:
|
||||||
for (signal_to_emit, data) in iter(
|
log_record = self.feedback_queue.get_nowait()
|
||||||
self.feedback_queue.get_nowait, None):
|
while log_record:
|
||||||
self.emit(signal_to_emit, data)
|
if log_record.levelno == logging.ERROR or\
|
||||||
|
log_record.levelno == logging.CRITICAL:
|
||||||
|
output = '<font color="red">{0}</font>'.format(
|
||||||
|
log_record.getMessage())
|
||||||
|
else:
|
||||||
|
output = log_record.getMessage()
|
||||||
|
self.append_output(output)
|
||||||
|
log_record = self.feedback_queue.get_nowait()
|
||||||
except Empty:
|
except Empty:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -238,7 +246,7 @@ class RestoreVMsWindow(ui_restoredlg.Ui_Restore, QtGui.QWizard):
|
|||||||
'<b><font color="black">{0}</font></b>'.format(
|
'<b><font color="black">{0}</font></b>'.format(
|
||||||
self.tr("Please unmount your backup volume and cancel "
|
self.tr("Please unmount your backup volume and cancel "
|
||||||
"the file selection dialog.")))
|
"the file selection dialog.")))
|
||||||
self.app.processEvents()
|
self.qt_app.processEvents()
|
||||||
backup_utils.select_path_button_clicked(self, False, True)
|
backup_utils.select_path_button_clicked(self, False, True)
|
||||||
|
|
||||||
self.button(self.FinishButton).setEnabled(True)
|
self.button(self.FinishButton).setEnabled(True)
|
||||||
@ -305,21 +313,21 @@ def handle_exception(exc_type, exc_value, exc_traceback):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
qtapp = QtGui.QApplication(sys.argv)
|
qt_app = QtGui.QApplication(sys.argv)
|
||||||
qtapp.setOrganizationName("The Qubes Project")
|
qt_app.setOrganizationName("The Qubes Project")
|
||||||
qtapp.setOrganizationDomain("http://qubes-os.org")
|
qt_app.setOrganizationDomain("http://qubes-os.org")
|
||||||
qtapp.setApplicationName("Qubes Restore VMs")
|
qt_app.setApplicationName("Qubes Restore VMs")
|
||||||
|
|
||||||
sys.excepthook = handle_exception
|
sys.excepthook = handle_exception
|
||||||
|
|
||||||
app = Qubes()
|
qubes_app = Qubes()
|
||||||
|
|
||||||
restore_window = RestoreVMsWindow(qtapp, app)
|
restore_window = RestoreVMsWindow(qt_app, qubes_app)
|
||||||
|
|
||||||
restore_window.show()
|
restore_window.show()
|
||||||
|
|
||||||
qtapp.exec_()
|
qt_app.exec_()
|
||||||
qtapp.exit()
|
qt_app.exit()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
# pylint: disable=unused-variable### mock qubesadmin.exc module
|
### mock qubesadmin.exc module
|
||||||
|
# pylint: disable=unused-variable
|
||||||
|
|
||||||
|
|
||||||
class QubesException(BaseException):
|
class QubesException(BaseException):
|
||||||
pass
|
pass
|
||||||
|
Loading…
Reference in New Issue
Block a user