diff options
author | André Erdmann <dywi@mailerd.de> | 2013-09-05 11:07:19 +0200 |
---|---|---|
committer | André Erdmann <dywi@mailerd.de> | 2013-09-05 11:07:19 +0200 |
commit | bb0ea5c5eac6d13e68915d3bd445659fe026e982 (patch) | |
tree | 109c1fd9cd5942446f15d28cf5b5eb743ecd6fe5 /roverlay/util | |
parent | dbcollector: fix typo (diff) | |
download | R_overlay-bb0ea5c5eac6d13e68915d3bd445659fe026e982.tar.gz R_overlay-bb0ea5c5eac6d13e68915d3bd445659fe026e982.tar.bz2 R_overlay-bb0ea5c5eac6d13e68915d3bd445659fe026e982.zip |
roverlay/util/fileio: TextFile class
object representing a text file (with a 'dirty' flag)
Diffstat (limited to 'roverlay/util')
-rw-r--r-- | roverlay/util/fileio.py | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/roverlay/util/fileio.py b/roverlay/util/fileio.py index a8d2e01..151e7f1 100644 --- a/roverlay/util/fileio.py +++ b/roverlay/util/fileio.py @@ -8,8 +8,12 @@ import gzip import bz2 import mimetypes import sys +import os.path +import shutil +import errno import roverlay.util.common +import roverlay.util.objects import roverlay.strutil from roverlay.strutil import bytes_try_decode @@ -145,3 +149,183 @@ def write_text_file ( return True # --- end of write_text_file (...) --- + + +class TextFile ( roverlay.util.objects.PersistentContent ): + + READ_PREPARSE = True + READ_TRY_HARDER = True + + def __init__ ( self, filepath, compression=None ): + super ( TextFile, self ).__init__() + + self._filepath = None + self._compression = None + + self.first_line = None + self.lino = None + + self.set_filepath ( filepath ) + self.set_compression ( compression ) + # --- end of __init__ (...) --- + + @roverlay.util.objects.abstractmethod + def parse_line ( self, line ): + return True + # --- end of parse_line (...) --- + + def parse_header_line ( self, line ): + return self.parse_line ( line ) + # --- end of parse_header_line (...) --- + + @roverlay.util.objects.abstractmethod + def gen_lines ( self ): + #yield ... + return + # --- end of gen_lines (...) --- + + def start_reading ( self ): + pass + # --- end of start_reading (...) --- + + def done_reading ( self ): + pass + # --- end of done_reading (...) --- + + def set_filepath ( self, filepath ): + self._filepath = filepath + # --- end of set_filepath (...) --- + + def set_compression ( self, compression ): + if not compression or compression in { 'default', 'none' }: + self._compression = None + elif compression in SUPPORTED_COMPRESSION: + self._compression = compression + else: + raise ValueError ( + "unknown file compression {!r}".format ( compression ) + ) + # --- end of set_compression (...) --- + + def backup_file ( self, destfile=None, move=False, ignore_missing=False ): + """Creates a backup copy of the file. + + arguments: + * destfile -- backup file path + Defaults to <dfile> + '.bak'. + * move -- move dfile (instead of copying) + * ignore_missing -- return False if file does not exist instead of + raising an exception. Defaults to False. + """ + dest = destfile or ( self._filepath + '.bak' ) + try: + roverlay.util.dodir ( os.path.dirname ( dest ), mkdir_p=True ) + if move: + shutil.move ( self._filepath, dest ) + return True + else: + shutil.copyfile ( self._filepath, dest ) + return True + except IOError as ioerr: + if ignore_missing and ioerr.errno == errno.ENOENT: + return False + else: + raise + # --- end of backup_file (...) --- + + def backup_and_write ( self, + destfile=None, backup_file=None, + force=False, move=False, ignore_missing=True + ): + """Creates a backup copy of the distmap file and writes the modified + distmap afterwards. + + arguments: + * destfile -- file path to be written (defaults to self._filepath) + * backup_file -- backup file path (see backup_file()) + * force -- enforce writing even if file content not modified + * move -- move distmap (see backup_file()) + * ignore_missing -- do not fail if the file does not exist when + creating a backup copy. + Defaults to True. + """ + if force or self.dirty: + self.backup_file ( + destfile=backup_file, move=move, ignore_missing=ignore_missing + ) + return self.write ( filepath=destfile, force=True ) + else: + return True + # --- end of backup_and_write (...) --- + + def file_exists ( self ): + """Returns True if the file exists, else False.""" + return os.path.isfile ( self._filepath ) + # --- end of file_exists (...) --- + + def try_read ( self, *args, **kwargs ): + """Tries to read the file.""" + try: + self.read ( *args, **kwargs ) + except IOError as ioerr: + if ioerr.errno == errno.ENOENT: + pass + else: + raise + # --- end of try_read (...) --- + + def read ( self, filepath=None ): + """Reads the file. + + arguments: + * filepath -- path to the distmap file (defaults to self.dbfile) + """ + fpath = self._filepath if filepath is None else filepath + + self.start_reading() + + self.first_line = True + self.lino = 0 + for lino, line in enumerate ( + read_text_file ( fpath, + preparse=self.READ_PREPARSE, try_harder=self.READ_TRY_HARDER + ) + ): + self.lino = lino + if self.first_line: + self.first_line = False + # parse_header_line() can reset first_line to True + self.parse_header_line ( line ) + else: + self.parse_line ( line ) + + if filepath is not None: + self.set_dirty() + + self.done_reading() + # --- end of read (...) --- + + def write ( self, filepath=None, force=False ): + """Writes the file. + + arguments: + * filepath -- path to the file to be written (defaults to self._filepath) + * force -- enforce writing even if file content not modified + """ + if force or self.dirty or filepath is not None: + fpath = self._filepath if filepath is None else filepath + write_text_file ( + fpath, self.gen_lines(), + compression=self._compression, create_dir=True + ) + + if filepath is None: + self.reset_dirty() + # else keep + + return True + else: + return False + # --- end of write (...) --- + +# --- end of TextFile --- |