Added some exception handling for file write operations

git-svn-id: http://comictagger.googlecode.com/svn/trunk@108 6c5673fe-1810-88d6-992b-cd32ca31540c
This commit is contained in:
beville@gmail.com 2012-11-28 00:33:51 +00:00
parent 391986b322
commit 146d15ee1c
3 changed files with 182 additions and 128 deletions

View File

@ -52,7 +52,7 @@ class ZipArchiver:
return comment
def setArchiveComment( self, comment ):
self.writeZipComment( self.path, comment )
return self.writeZipComment( self.path, comment )
def readArchiveFile( self, archive_file ):
zf = zipfile.ZipFile( self.path, 'r' )
@ -61,19 +61,28 @@ class ZipArchiver:
return data
def removeArchiveFile( self, archive_file ):
self.rebuildZipFile( [ archive_file ] )
try:
self.rebuildZipFile( [ archive_file ] )
except:
return False
else:
return True
def writeArchiveFile( self, archive_file, data ):
# At the moment, no other option but to rebuild the whole
# zip archive w/o the indicated file. Very sucky, but maybe
# another solution can be found
self.rebuildZipFile( [ archive_file ] )
#now just add the archive file as a new one
zf = zipfile.ZipFile(self.path, mode='a', compression=zipfile.ZIP_DEFLATED )
zf.writestr( archive_file, data )
zf.close()
try:
self.rebuildZipFile( [ archive_file ] )
#now just add the archive file as a new one
zf = zipfile.ZipFile(self.path, mode='a', compression=zipfile.ZIP_DEFLATED )
zf.writestr( archive_file, data )
zf.close()
return True
except:
return False
def getArchiveFilenameList( self ):
zf = zipfile.ZipFile( self.path, 'r' )
namelist = zf.namelist()
@ -85,7 +94,7 @@ class ZipArchiver:
# TODO: use tempfile.mkstemp
# this recompresses the zip archive, without the files in the exclude_list
print "Rebuilding zip {0} without {1}".format( self.path, exclude_list )
#print "Rebuilding zip {0} without {1}".format( self.path, exclude_list )
# generate temp file
tmp_fd, tmp_name = tempfile.mkstemp( dir=os.path.dirname(self.path) )
@ -123,50 +132,54 @@ class ZipArchiver:
statinfo = os.stat(filename)
file_length = statinfo.st_size
fo = open(filename, "r+b")
try:
fo = open(filename, "r+b")
#the starting position, relative to EOF
pos = -4
#the starting position, relative to EOF
pos = -4
found = False
value = bytearray()
# walk backwards to find the "End of Central Directory" record
while ( not found ) and ( -pos != file_length ):
# seek, relative to EOF
fo.seek( pos, 2)
value = fo.read( 4 )
#look for the end of central directory signature
if bytearray(value) == bytearray([ 0x50, 0x4b, 0x05, 0x06 ]):
found = True
else:
# not found, step back another byte
pos = pos - 1
#print pos,"{1} int: {0:x}".format(bytearray(value)[0], value)
found = False
value = bytearray()
if found:
# now skip forward 20 bytes to the comment length word
pos += 20
fo.seek( pos, 2)
# walk backwards to find the "End of Central Directory" record
while ( not found ) and ( -pos != file_length ):
# seek, relative to EOF
fo.seek( pos, 2)
# Pack the length of the comment string
format = "H" # one 2-byte integer
comment_length = struct.pack(format, len(comment)) # pack integer in a binary string
# write out the length
fo.write( comment_length )
fo.seek( pos+2, 2)
# write out the comment itself
fo.write( comment )
fo.truncate()
fo.close()
value = fo.read( 4 )
#look for the end of central directory signature
if bytearray(value) == bytearray([ 0x50, 0x4b, 0x05, 0x06 ]):
found = True
else:
# not found, step back another byte
pos = pos - 1
#print pos,"{1} int: {0:x}".format(bytearray(value)[0], value)
if found:
# now skip forward 20 bytes to the comment length word
pos += 20
fo.seek( pos, 2)
# Pack the length of the comment string
format = "H" # one 2-byte integer
comment_length = struct.pack(format, len(comment)) # pack integer in a binary string
# write out the length
fo.write( comment_length )
fo.seek( pos+2, 2)
# write out the comment itself
fo.write( comment )
fo.truncate()
fo.close()
else:
raise Exception('Failed to write comment to zip file!')
except:
return False
else:
raise Exception('Failed to write comment to zip file!')
return True
#------------------------------------------
# RAR implementation
@ -196,22 +209,29 @@ class RarArchiver:
def setArchiveComment( self, comment ):
if self.rar_exe_path is not None:
# write comment to temp file
tmp_fd, tmp_name = tempfile.mkstemp()
f = os.fdopen(tmp_fd, 'w+b')
f.write( comment )
f.close()
try:
# write comment to temp file
tmp_fd, tmp_name = tempfile.mkstemp()
f = os.fdopen(tmp_fd, 'w+b')
f.write( comment )
f.close()
# use external program to write comment to Rar archive
subprocess.call([self.rar_exe_path, 'c', '-c-', '-z' + tmp_name, self.path],
startupinfo=self.startupinfo,
stdout=self.devnull)
if platform.system() == "Darwin":
time.sleep(1)
# use external program to write comment to Rar archive
subprocess.call([self.rar_exe_path, 'c', '-c-', '-z' + tmp_name, self.path],
startupinfo=self.startupinfo,
stdout=self.devnull)
os.remove( tmp_name)
if platform.system() == "Darwin":
time.sleep(1)
os.remove( tmp_name)
except:
return False
else:
return True
else:
return False
def readArchiveFile( self, archive_file ):
entries = UnRAR2.RarFile( self.path ).read_files( archive_file )
@ -225,36 +245,48 @@ class RarArchiver:
def writeArchiveFile( self, archive_file, data ):
if self.rar_exe_path is not None:
try:
tmp_folder = tempfile.mkdtemp()
tmp_file = os.path.join( tmp_folder, archive_file )
f = open(tmp_file, 'w')
f.write( data )
f.close()
# use external program to write file to Rar archive
subprocess.call([self.rar_exe_path, 'a', '-c-', '-ep', self.path, tmp_file],
startupinfo=self.startupinfo,
stdout=self.devnull)
if platform.system() == "Darwin":
time.sleep(1)
os.remove( tmp_file)
os.rmdir( tmp_folder)
except:
return False
else:
return True
else:
return False
tmp_folder = tempfile.mkdtemp()
tmp_file = os.path.join( tmp_folder, archive_file )
f = open(tmp_file, 'w')
f.write( data )
f.close()
# use external program to write file to Rar archive
subprocess.call([self.rar_exe_path, 'a', '-c-', '-ep', self.path, tmp_file],
startupinfo=self.startupinfo,
stdout=self.devnull)
if platform.system() == "Darwin":
time.sleep(1)
os.remove( tmp_file)
os.rmdir( tmp_folder)
def removeArchiveFile( self, archive_file ):
if self.rar_exe_path is not None:
try:
# use external program to remove file from Rar archive
subprocess.call([self.rar_exe_path, 'd','-c-', self.path, archive_file],
startupinfo=self.startupinfo,
stdout=self.devnull)
# use external program to remove file from Rar archive
subprocess.call([self.rar_exe_path, 'd','-c-', self.path, archive_file],
startupinfo=self.startupinfo,
stdout=self.devnull)
if platform.system() == "Darwin":
time.sleep(1)
if platform.system() == "Darwin":
time.sleep(1)
except:
return False
else:
return True
else:
return False
def getArchiveFilenameList( self ):
rarc = UnRAR2.RarFile( self.path )
@ -273,7 +305,7 @@ class FolderArchiver:
return self.readArchiveFile( self.comment_file_name )
def setArchiveComment( self, comment ):
self.writeArchiveFile( self.comment_file_name, comment )
return self.writeArchiveFile( self.comment_file_name, comment )
def readArchiveFile( self, archive_file ):
@ -295,8 +327,10 @@ class FolderArchiver:
with open(fname, 'w+') as f:
f.write( data )
f.close()
except IOError as e:
pass
except:
return False
else:
return True
def removeArchiveFile( self, archive_file ):
@ -304,7 +338,9 @@ class FolderArchiver:
try:
os.remove( fname )
except:
pass
return False
else:
return True
def getArchiveFilenameList( self ):
return self.listFiles( self.path )
@ -330,13 +366,13 @@ class UnknownArchiver:
def getArchiveComment( self ):
return ""
def setArchiveComment( self, comment ):
return
return False
def readArchiveFilen( self ):
return ""
def writeArchiveFile( self, archive_file, data ):
return
return False
def removeArchiveFile( self, archive_file ):
return
return False
def getArchiveFilenameList( self ):
return []
@ -440,9 +476,9 @@ class ComicArchive:
def writeMetadata( self, metadata, style ):
if style == MetaDataStyle.CIX:
self.writeCIX( metadata )
return self.writeCIX( metadata )
elif style == MetaDataStyle.CBI:
self.writeCBI( metadata )
return self.writeCBI( metadata )
def hasMetadata( self, style ):
@ -455,9 +491,9 @@ class ComicArchive:
def removeMetadata( self, style ):
if style == MetaDataStyle.CIX:
self.removeCIX()
return self.removeCIX()
elif style == MetaDataStyle.CBI:
self.removeCBI()
return self.removeCBI()
def getCoverPage(self):
@ -522,10 +558,10 @@ class ComicArchive:
def writeCBI( self, metadata ):
cbi_string = ComicBookInfo().stringFromMetadata( metadata )
self.archiver.setArchiveComment( cbi_string )
return self.archiver.setArchiveComment( cbi_string )
def removeCBI( self ):
self.archiver.setArchiveComment( "" )
return self.archiver.setArchiveComment( "" )
def readCIX( self ):
raw_cix = self.readRawCIX()
@ -545,11 +581,13 @@ class ComicArchive:
if metadata is not None:
cix_string = ComicInfoXml().stringFromMetadata( metadata )
self.archiver.writeArchiveFile( self.ci_xml_filename, cix_string )
return self.archiver.writeArchiveFile( self.ci_xml_filename, cix_string )
else:
return False
def removeCIX( self ):
self.archiver.removeArchiveFile( self.ci_xml_filename )
return self.archiver.removeArchiveFile( self.ci_xml_filename )
def hasCIX(self):
if not self.seemsToBeAComicArchive():

View File

@ -27,6 +27,7 @@ import traceback
import time
from pprint import pprint
import json
import platform
try:
qt_available = True
@ -123,8 +124,10 @@ def process_file_cli( filename, opts, settings ):
if opts.data_style == MetaDataStyle.CIX:
if cix:
if not opts.dryrun:
ca.removeCIX()
print "Removed ComicRack tags."
if not ca.removeCIX():
print "Tag removal seemed to fail!"
else:
print "Removed ComicRack tags."
else:
print "dry-run. ComicRack tags not removed"
else:
@ -133,8 +136,10 @@ def process_file_cli( filename, opts, settings ):
if opts.data_style == MetaDataStyle.CBI:
if cbi:
if not opts.dryrun:
ca.removeCBI()
print "Removed ComicBookLover tags."
if not ca.removeCBI():
print "Tag removal seemed to fail!"
else:
print "Removed ComicBookLover tags."
else:
print "dry-run. ComicBookLover tags not removed"
else:
@ -224,7 +229,10 @@ def process_file_cli( filename, opts, settings ):
if not opts.dryrun:
# write out the new data
ca.writeMetadata( md, opts.data_style )
if not ca.writeMetadata( md, opts.data_style ):
print "The tag save seemed to fail!"
else:
print "Save complete."
else:
print "dry-run option was set, so nothing was written, but here is the final set of tags:"
print u"{0}".format(md)
@ -265,7 +273,7 @@ def process_file_cli( filename, opts, settings ):
new_name += " v{0}".format( md.volume )
if md.issue is not None:
new_name += " #{0}".format( md.issue )
new_name += " #{:03d}".format( int(md.issue) )
else:
print "Can't rename without issue number"
return
@ -276,7 +284,7 @@ def process_file_cli( filename, opts, settings ):
if md.year is not None:
new_name += " ({0})".format( md.year )
if ca.isZip:
if ca.isZip():
new_name += ".cbz"
elif ca.isRar():
new_name += ".cbr"
@ -323,16 +331,20 @@ def main():
app = QtGui.QApplication(sys.argv)
img = QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/tags.png' ))
splash = QtGui.QSplashScreen(img)
splash.show()
splash.raise_()
app.processEvents()
if platform.system() != "Linux":
img = QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/tags.png' ))
splash = QtGui.QSplashScreen(img)
splash.show()
splash.raise_()
app.processEvents()
try:
tagger_window = TaggerWindow( opts.filename, settings )
tagger_window.show()
splash.finish( tagger_window )
if platform.system() != "Linux":
splash.finish( tagger_window )
sys.exit(app.exec_())
except Exception, e:
QtGui.QMessageBox.critical(QtGui.QMainWindow(), "Error", "Unhandled exception in app:\n" + traceback.format_exc() )

View File

@ -693,7 +693,6 @@ class TaggerWindow( QtGui.QMainWindow):
dialog = QtGui.QFileDialog(self)
dialog.setFileMode(QtGui.QFileDialog.ExistingFile)
print "last opened folder=", self.settings.last_opened_folder
if self.settings.last_opened_folder is not None:
dialog.setDirectory( self.settings.last_opened_folder )
#dialog.setFileMode(QtGui.QFileDialog.Directory )
@ -803,13 +802,16 @@ class TaggerWindow( QtGui.QMainWindow):
if reply == QtGui.QMessageBox.Yes:
QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
self.formToMetadata()
self.comic_archive.writeMetadata( self.metadata, self.data_style )
self.clearDirtyFlag()
self.updateInfoBox()
QtGui.QApplication.restoreOverrideCursor()
QtGui.QMessageBox.information(self, self.tr("Yeah!"), self.tr("File written."))
success = self.comic_archive.writeMetadata( self.metadata, self.data_style )
QtGui.QApplication.restoreOverrideCursor()
if not success:
QtGui.QMessageBox.warning(self, self.tr("Save failed"), self.tr("The tag save operation seemed to fail!"))
else:
self.clearDirtyFlag()
self.updateInfoBox()
#QtGui.QMessageBox.information(self, self.tr("Yeah!"), self.tr("File written."))
else:
QtGui.QMessageBox.information(self, self.tr("Whoops!"), self.tr("No data to commit!"))
@ -1123,8 +1125,10 @@ class TaggerWindow( QtGui.QMainWindow):
if reply == QtGui.QMessageBox.Yes:
path = self.comic_archive.path
self.comic_archive.removeMetadata( style )
self.updateInfoBox()
if not self.comic_archive.removeMetadata( style ):
QtGui.QMessageBox.warning(self, self.tr("Remove failed"), self.tr("The tag removal operation seemed to fail!"))
else:
self.updateInfoBox()
def reloadAuto( self ):