server/sources/storages.py
changeset 8180 1f6ba9afb925
parent 8148 b7a195d54fd4
child 8307 8be58694f416
equal deleted inserted replaced
8179:e52a084e955c 8180:1f6ba9afb925
    16 # You should have received a copy of the GNU Lesser General Public License along
    16 # You should have received a copy of the GNU Lesser General Public License along
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
    18 """custom storages for the system source"""
    18 """custom storages for the system source"""
    19 
    19 
    20 import os
    20 import os
       
    21 import sys
    21 from os import unlink, path as osp
    22 from os import unlink, path as osp
    22 from contextlib import contextmanager
    23 from contextlib import contextmanager
    23 
    24 
    24 from yams.schema import role_name
    25 from yams.schema import role_name
    25 
    26 
   110         del session.transaction_data['fs_importing']
   111         del session.transaction_data['fs_importing']
   111 
   112 
   112 
   113 
   113 class BytesFileSystemStorage(Storage):
   114 class BytesFileSystemStorage(Storage):
   114     """store Bytes attribute value on the file system"""
   115     """store Bytes attribute value on the file system"""
   115     def __init__(self, defaultdir, fsencoding='utf-8'):
   116     def __init__(self, defaultdir, fsencoding='utf-8', wmode=0444):
   116         if type(defaultdir) is unicode:
   117         if type(defaultdir) is unicode:
   117             defaultdir = defaultdir.encode(fsencoding)
   118             defaultdir = defaultdir.encode(fsencoding)
   118         self.default_directory = defaultdir
   119         self.default_directory = defaultdir
   119         self.fsencoding = fsencoding
   120         self.fsencoding = fsencoding
       
   121         # extra umask to use when creating file
       
   122         # 0444 as in "only allow read bit in permission"
       
   123         self._wmode = wmode
       
   124 
       
   125     def _writecontent(self, path, binary):
       
   126         """write the content of a binary in readonly file
       
   127 
       
   128         As the bfss never alter a create file it does not prevent it to work as
       
   129         intended. This is a beter safe than sorry approach.
       
   130         """
       
   131         write_flag = os.O_WRONLY | os.O_CREAT | os.O_EXCL
       
   132         if sys.platform == 'win32':
       
   133             write_flag |= os.O_BINARY
       
   134         fd = os.open(path, write_flag, self._wmode)
       
   135         fileobj = os.fdopen(fd, 'wb')
       
   136         binary.to_file(fileobj)
       
   137         fileobj.close()
       
   138 
   120 
   139 
   121     def callback(self, source, session, value):
   140     def callback(self, source, session, value):
   122         """sql generator callback when some attribute with a custom storage is
   141         """sql generator callback when some attribute with a custom storage is
   123         accessed
   142         accessed
   124         """
   143         """
   136         else:
   155         else:
   137             binary = entity.cw_edited.pop(attr)
   156             binary = entity.cw_edited.pop(attr)
   138             fpath = self.new_fs_path(entity, attr)
   157             fpath = self.new_fs_path(entity, attr)
   139             # bytes storage used to store file's path
   158             # bytes storage used to store file's path
   140             entity.cw_edited.edited_attribute(attr, Binary(fpath))
   159             entity.cw_edited.edited_attribute(attr, Binary(fpath))
   141             binary.to_file(fpath)
   160             self._writecontent(fpath, binary)
   142             AddFileOp.get_instance(entity._cw).add_data(fpath)
   161             AddFileOp.get_instance(entity._cw).add_data(fpath)
   143         return binary
   162         return binary
   144 
   163 
   145     def entity_updated(self, entity, attr):
   164     def entity_updated(self, entity, attr):
   146         """an entity using this storage for attr has been updated"""
   165         """an entity using this storage for attr has been updated"""
   169             else:
   188             else:
   170                 # Get filename for it
   189                 # Get filename for it
   171                 fpath = self.new_fs_path(entity, attr)
   190                 fpath = self.new_fs_path(entity, attr)
   172                 assert not osp.exists(fpath)
   191                 assert not osp.exists(fpath)
   173                 # write attribute value on disk
   192                 # write attribute value on disk
   174                 binary.to_file(fpath)
   193                 self._writecontent(fpath, binary)
   175                 # Mark the new file as added during the transaction.
   194                 # Mark the new file as added during the transaction.
   176                 # The file will be removed on rollback
   195                 # The file will be removed on rollback
   177                 AddFileOp.get_instance(entity._cw).add_data(fpath)
   196                 AddFileOp.get_instance(entity._cw).add_data(fpath)
   178         if oldpath != fpath:
   197         if oldpath != fpath:
   179             # register the new location for the file.
   198             # register the new location for the file.