aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Erdmann <dywi@mailerd.de>2013-09-05 11:07:19 +0200
committerAndré Erdmann <dywi@mailerd.de>2013-09-05 11:07:19 +0200
commitbb0ea5c5eac6d13e68915d3bd445659fe026e982 (patch)
tree109c1fd9cd5942446f15d28cf5b5eb743ecd6fe5 /roverlay/util
parentdbcollector: fix typo (diff)
downloadR_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.py184
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 ---