Remove symlink if exists
[osm/common.git] / osm_common / fsmongo.py
index 6a96d44..740d540 100644 (file)
 # contact: eduardo.sousa@canonical.com
 ##
 
+import errno
+from http import HTTPStatus
 from io import BytesIO, StringIO
-from pymongo import MongoClient
-from gridfs import GridFSBucket, errors
 import logging
-from http import HTTPStatus
 import os
+
+from gridfs import GridFSBucket, errors
 from osm_common.fsbase import FsBase, FsException
+from pymongo import MongoClient
+
 
 __author__ = "Eduardo Sousa <eduardo.sousa@canonical.com>"
 
@@ -195,15 +198,19 @@ class FsMongo(FsBase):
         self.client = None
         self.fs = None
 
-    def __update_local_fs(self):
+    def __update_local_fs(self, from_path=None):
         dir_cursor = self.fs.find({"metadata.type": "dir"}, no_cursor_timeout=True)
 
         for directory in dir_cursor:
+            if from_path and not directory.filename.startswith(from_path):
+                continue
             os.makedirs(self.path + directory.filename, exist_ok=True)
 
         file_cursor = self.fs.find({"metadata.type": {"$in": ["file", "sym"]}}, no_cursor_timeout=True)
 
         for writing_file in file_cursor:
+            if from_path and not writing_file.filename.startswith(from_path):
+                continue
             file_path = self.path + writing_file.filename
 
             if writing_file.metadata["type"] == "sym":
@@ -211,6 +218,13 @@ class FsMongo(FsBase):
                     self.fs.download_to_stream(writing_file._id, b)
                     b.seek(0)
                     link = b.read().decode("utf-8")
+
+                try:
+                    os.remove(file_path)
+                except OSError as e:
+                    if e.errno != errno.ENOENT:
+                        # This is probably permission denied or worse
+                        raise
                 os.symlink(link, file_path)
             else:
                 with open(file_path, 'wb+') as file_stream:
@@ -313,7 +327,7 @@ class FsMongo(FsBase):
 
             if requested_file.metadata["type"] == mode:
                 return True
-            
+
             if requested_file.metadata["type"] == "sym" and mode == "file":
                 return True
 
@@ -448,12 +462,14 @@ class FsMongo(FsBase):
                 else:
                     self.fs.delete(requested_file._id)
             if not found and not ignore_non_exist:
-                raise FsException("File {} does not exist".format(storage), http_code=HTTPStatus.NOT_FOUND)    
+                raise FsException("File {} does not exist".format(storage), http_code=HTTPStatus.NOT_FOUND)
         except IOError as e:
             raise FsException("File {} cannot be deleted: {}".format(f, e), http_code=HTTPStatus.INTERNAL_SERVER_ERROR)
 
-    def sync(self):
+    def sync(self, from_path=None):
         """
         Sync from FSMongo to local storage
+        :param from_path: if supplied, only copy content from this path, not all
+        :return: None
         """
-        self.__update_local_fs()
+        self.__update_local_fs(from_path=from_path)