From ac27fa37437422a35227b058f4045ebf82ee8b67 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 6 May 2013 15:45:04 +0300 Subject: [PATCH] TransRead: implement local caching Teach TransRead to cache remote and compressed files with local uncompressed files, which makes it possible to use operations like mmap and so on. This patch adds a 'local' parameter to the TransRead constructor which is 'False' by default, and when it is 'True', TransRead creates a local copy of the back-end file. Change-Id: I1bef11c132bb2750c8cb983ff7cdc5180a75bb66 Signed-off-by: Artem Bityutskiy --- bmaptool | 4 +++- bmaptools/TransRead.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/bmaptool b/bmaptool index 3b59073..f9c3318 100755 --- a/bmaptool +++ b/bmaptool @@ -139,7 +139,9 @@ def copy_command_open_all(args, log): bmap_obj = None if bmap_path: try: - bmap_obj = TransRead.TransRead(bmap_path) + # The current implementation of BmapCopy requires a local file for + # the bmap file. + bmap_obj = TransRead.TransRead(bmap_path, local = True) except TransRead.Error as err: log.error("cannot open bmap file '%s': %s" % (bmap_path, str(err))) raise SystemExit(1) diff --git a/bmaptools/TransRead.py b/bmaptools/TransRead.py index fd184da..c824adb 100644 --- a/bmaptools/TransRead.py +++ b/bmaptools/TransRead.py @@ -243,9 +243,42 @@ class TransRead: raise Error("cannot open URL '%s': server responds with an HTTP " \ "status code that we don't understand" % url) - def __init__(self, filepath): + def _create_local_copy(self): + """ Create a local copy of a remote or compressed file. """ + + import tempfile + + try: + tmp_file_obj = tempfile.NamedTemporaryFile("w+") + except IOError as err: + raise Error("cannot create a temporary file: %s" % err) + + while True: + chunk = self.read(1024 * 1024) + if not chunk: + break + + tmp_file_obj.write(chunk) + + tmp_file_obj.flush() + self.close() + self.is_compressed = False + self.is_url = False + self._file_obj = tmp_file_obj + + try: + self._transfile_obj = open(tmp_file_obj.name, "rb") + except IOError as err: + raise Error("cannot open own temporary file '%s': %s" \ + % (tmp_file_obj.name, err)) + + def __init__(self, filepath, local = False): """ Class constructor. The 'filepath' argument is the full path to the - file to read transparently. """ + file to read transparently. If 'local' is True, then the file-like + object is guaranteed to be backed by a local file. This means that if + the source file is compressed or an URL, then it will first be copied + to a temporary local file, and then all the subsequent operations will + be done with the local copy. """ self.name = filepath self.size = None @@ -266,6 +299,9 @@ class TransRead: self._open_compressed_file() + if local: + self._create_local_copy() + def read(self, size = -1): """ Read the data from the file or URL and and uncompress it on-the-fly if necessary. """ @@ -308,3 +344,11 @@ class TransRead: self.__del__() + def __getattr__(self, name): + """ If we are backed by a local uncompressed file, then fall-back to + using its operations. """ + + if not self.is_compressed and not self.is_url: + return getattr(self._transfile_obj, name) + else: + raise AttributeError -- 2.7.4