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:
parent
391986b322
commit
146d15ee1c
248
comicarchive.py
248
comicarchive.py
@ -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():
|
||||
|
@ -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() )
|
||||
|
@ -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 ):
|
||||
|
Loading…
Reference in New Issue
Block a user