Start on refactoring file saving

This commit is contained in:
Phill Ridout 2017-12-27 16:06:36 +00:00
parent 6e2bc427a7
commit 4b1965520c

View File

@ -27,8 +27,9 @@ import json
import os import os
import shutil import shutil
import zipfile import zipfile
from contextlib import suppress
from datetime import datetime, timedelta from datetime import datetime, timedelta
from tempfile import mkstemp from tempfile import NamedTemporaryFile, mkstemp
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
@ -503,35 +504,9 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
service.append({'openlp_core': core}) service.append({'openlp_core': core})
return service return service
def save_file(self, field=None): def get_write_file_list(self):
"""
Save the current service file.
A temporary file is created so that we don't overwrite the existing one and leave a mangled service file should
there be an error when saving. Audio files are also copied into the service manager directory, and then packaged
into the zip file.
"""
if not self.file_name():
return self.save_file_as()
temp_file, temp_file_name = mkstemp('.osz', 'openlp_')
# We don't need the file handle.
os.close(temp_file)
self.log_debug(temp_file_name)
path_file_name = str(self.file_name())
path, file_name = os.path.split(path_file_name)
base_name = os.path.splitext(file_name)[0]
service_file_name = '{name}.osj'.format(name=base_name)
self.log_debug('ServiceManager.save_file - {name}'.format(name=path_file_name))
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', Path(path))
service = self.create_basic_service()
write_list = [] write_list = []
missing_list = [] missing_list = []
audio_files = []
total_size = 0
self.application.set_busy_cursor()
# Number of items + 1 to zip it
self.main_window.display_progress_bar(len(self.service_items) + 1)
# Get list of missing files, and list of files to write
for item in self.service_items: for item in self.service_items:
if not item['service_item'].uses_file(): if not item['service_item'].uses_file():
continue continue
@ -543,6 +518,32 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
missing_list.append(path_from) missing_list.append(path_from)
else: else:
write_list.append(path_from) write_list.append(path_from)
return write_list, missing_list
def save_file(self):
"""
Save the current service file.
A temporary file is created so that we don't overwrite the existing one and leave a mangled service file should
there be an error when saving. Audio files are also copied into the service manager directory, and then packaged
into the zip file.
"""
file_path = self.file_name()
service_file_name = '{name}.osj'.format(name=file_path.suffix)
self.log_debug('ServiceManager.save_file - {name}'.format(name=file_path))
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', file_path.parent)
service = self.create_basic_service()
self.application.set_busy_cursor()
# Number of items + 1 to zip it
self.main_window.display_progress_bar(len(self.service_items) + 1)
# Get list of missing files, and list of files to write
audio_files = []
write_list, missing_list = self.get_write_file_list()
if missing_list: if missing_list:
self.application.set_normal_cursor() self.application.set_normal_cursor()
title = translate('OpenLP.ServiceManager', 'Service File(s) Missing') title = translate('OpenLP.ServiceManager', 'Service File(s) Missing')
@ -572,19 +573,18 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
# Add the service item to the service. # Add the service item to the service.
service.append({'serviceitem': service_item}) service.append({'serviceitem': service_item})
self.repaint_service_list(-1, -1) self.repaint_service_list(-1, -1)
total_size = 0
for file_item in write_list: for file_item in write_list:
file_size = os.path.getsize(file_item) file_size = os.path.getsize(file_item)
total_size += file_size total_size += file_size
self.log_debug('ServiceManager.save_file - ZIP contents size is %i bytes' % total_size) self.log_debug('ServiceManager.save_file - ZIP contents size is %i bytes' % total_size)
service_content = json.dumps(service) service_content = json.dumps(service)
# Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be extracted using unzip in UNIX.
allow_zip_64 = (total_size > 2147483648 + len(service_content))
self.log_debug('ServiceManager.save_file - allowZip64 is {text}'.format(text=allow_zip_64))
zip_file = None
success = True
self.main_window.increment_progress_bar() self.main_window.increment_progress_bar()
try: try:
zip_file = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED, allow_zip_64) with NamedTemporaryFile() as temp_file, \
zipfile.ZipFile(temp_file, 'w') as zip_file:
# First we add service contents.. # First we add service contents..
zip_file.writestr(service_file_name, service_content) zip_file.writestr(service_file_name, service_content)
# Finally add all the listed media files. # Finally add all the listed media files.
@ -597,37 +597,23 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
# When items are saved, they get new unique_identifier. Let's copy the file to the new location. # When items are saved, they get new unique_identifier. Let's copy the file to the new location.
# Unused files can be ignored, OpenLP automatically cleans up the service manager dir on exit. # Unused files can be ignored, OpenLP automatically cleans up the service manager dir on exit.
audio_from = os.path.join(self.service_path, audio_from) audio_from = os.path.join(self.service_path, audio_from)
save_file = os.path.join(self.service_path, audio_to)
save_path = os.path.split(save_file)[0]
create_paths(Path(save_path))
if not os.path.exists(save_file):
shutil.copy(audio_from, save_file)
zip_file.write(audio_from, audio_to) zip_file.write(audio_from, audio_to)
except OSError: with suppress(FileNotFoundError):
self.log_exception('Failed to save service to disk: {name}'.format(name=temp_file_name)) file_path.unlink()
self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'), os.link(temp_file.name, file_path)
translate('OpenLP.ServiceManager', 'There was an error saving your file.')) except (PermissionError, OSError) as error:
success = False self.log_exception('Failed to save service to disk: {name}'.format(name=temp_file.name))
finally: self.main_window.error_message(
if zip_file: translate('OpenLP.ServiceManager', 'Error Saving File'),
zip_file.close() translate('OpenLP.ServiceManager', 'There was an error saving your file.\n\n{error}').format(error=error))
return self.save_file_as()
self.main_window.finished_progress_bar() self.main_window.finished_progress_bar()
self.application.set_normal_cursor() self.application.set_normal_cursor()
if success: self.main_window.add_recent_file(file_path)
try:
shutil.copy(temp_file_name, path_file_name)
except (shutil.Error, PermissionError):
return self.save_file_as()
except OSError as ose:
QtWidgets.QMessageBox.critical(self, translate('OpenLP.ServiceManager', 'Error Saving File'),
translate('OpenLP.ServiceManager', 'An error occurred while writing the '
'service file: {error}').format(error=ose.strerror),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
success = False
self.main_window.add_recent_file(path_file_name)
self.set_modified(False) self.set_modified(False)
delete_file(Path(temp_file_name)) return True
return success
def save_local_file(self): def save_local_file(self):
""" """