server/sources/storages.py
branchstable
changeset 8131 a6654712ad50
parent 7695 2f6e37661cf6
child 8148 b7a195d54fd4
equal deleted inserted replaced
8127:96d343a5e01b 8131:a6654712ad50
    15 #
    15 #
    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 from os import unlink, path as osp
    21 from os import unlink, path as osp
    21 from contextlib import contextmanager
    22 from contextlib import contextmanager
    22 
    23 
    23 from yams.schema import role_name
    24 from yams.schema import role_name
    24 
    25 
   119         """sql generator callback when some attribute with a custom storage is
   120         """sql generator callback when some attribute with a custom storage is
   120         accessed
   121         accessed
   121         """
   122         """
   122         fpath = source.binary_to_str(value)
   123         fpath = source.binary_to_str(value)
   123         try:
   124         try:
   124             return Binary(file(fpath, 'rb').read())
   125             return Binary.from_file(fpath)
   125         except EnvironmentError, ex:
   126         except EnvironmentError, ex:
   126             source.critical("can't open %s: %s", value, ex)
   127             source.critical("can't open %s: %s", value, ex)
   127             return None
   128             return None
   128 
   129 
   129     def entity_added(self, entity, attr):
   130     def entity_added(self, entity, attr):
   130         """an entity using this storage for attr has been added"""
   131         """an entity using this storage for attr has been added"""
   131         if entity._cw.transaction_data.get('fs_importing'):
   132         if entity._cw.transaction_data.get('fs_importing'):
   132             binary = Binary(file(entity.cw_edited[attr].getvalue(), 'rb').read())
   133             binary = Binary.from_file(entity.cw_edited[attr].getvalue())
   133         else:
   134         else:
   134             binary = entity.cw_edited.pop(attr)
   135             binary = entity.cw_edited.pop(attr)
   135             fpath = self.new_fs_path(entity, attr)
   136             fpath = self.new_fs_path(entity, attr)
   136             # bytes storage used to store file's path
   137             # bytes storage used to store file's path
   137             entity.cw_edited.edited_attribute(attr, Binary(fpath))
   138             entity.cw_edited.edited_attribute(attr, Binary(fpath))
   138             file(fpath, 'wb').write(binary.getvalue())
   139             binary.to_file(fpath)
   139             AddFileOp.get_instance(entity._cw).add_data(fpath)
   140             AddFileOp.get_instance(entity._cw).add_data(fpath)
   140         return binary
   141         return binary
   141 
   142 
   142     def entity_updated(self, entity, attr):
   143     def entity_updated(self, entity, attr):
   143         """an entity using this storage for attr has been updatded"""
   144         """an entity using this storage for attr has been updated"""
   144         # get the name of the previous file containing the value
   145         # get the name of the previous file containing the value
   145         oldpath = self.current_fs_path(entity, attr)
   146         oldpath = self.current_fs_path(entity, attr)
   146         if entity._cw.transaction_data.get('fs_importing'):
   147         if entity._cw.transaction_data.get('fs_importing'):
   147             # If we are importing from the filesystem, the file already exists.
   148             # If we are importing from the filesystem, the file already exists.
   148             # We do not need to create it but we need to fetch the content of
   149             # We do not need to create it but we need to fetch the content of
   149             # the file as the actual content of the attribute
   150             # the file as the actual content of the attribute
   150             fpath = entity.cw_edited[attr].getvalue()
   151             fpath = entity.cw_edited[attr].getvalue()
   151             assert fpath is not None
   152             assert fpath is not None
   152             binary = Binary(file(fpath, 'rb').read())
   153             binary = Binary.from_file(fpath)
   153         else:
   154         else:
   154             # We must store the content of the attributes
   155             # We must store the content of the attributes
   155             # into a file to stay consistent with the behaviour of entity_add.
   156             # into a file to stay consistent with the behaviour of entity_add.
   156             # Moreover, the BytesFileSystemStorage expects to be able to
   157             # Moreover, the BytesFileSystemStorage expects to be able to
   157             # retrieve the current value of the attribute at anytime by reading
   158             # retrieve the current value of the attribute at anytime by reading
   166             else:
   167             else:
   167                 # Get filename for it
   168                 # Get filename for it
   168                 fpath = self.new_fs_path(entity, attr)
   169                 fpath = self.new_fs_path(entity, attr)
   169                 assert not osp.exists(fpath)
   170                 assert not osp.exists(fpath)
   170                 # write attribute value on disk
   171                 # write attribute value on disk
   171                 file(fpath, 'wb').write(binary.getvalue())
   172                 binary.to_file(fpath)
   172                 # Mark the new file as added during the transaction.
   173                 # Mark the new file as added during the transaction.
   173                 # The file will be removed on rollback
   174                 # The file will be removed on rollback
   174                 AddFileOp.get_instance(entity._cw).add_data(fpath)
   175                 AddFileOp.get_instance(entity._cw).add_data(fpath)
   175         if oldpath != fpath:
   176         if oldpath != fpath:
   176             # register the new location for the file.
   177             # register the new location for the file.
   206                 self.default_directory, '_'.join(basename))
   207                 self.default_directory, '_'.join(basename))
   207             raise ValidationError(entity.eid, {role_name(attr, 'subject'): msg})
   208             raise ValidationError(entity.eid, {role_name(attr, 'subject'): msg})
   208         return fspath
   209         return fspath
   209 
   210 
   210     def current_fs_path(self, entity, attr):
   211     def current_fs_path(self, entity, attr):
   211         """return the current fs_path of the tribute.
   212         """return the current fs_path of the attribute, or None is the attr is
   212 
   213         not stored yet.
   213         Return None is the attr is not stored yet."""
   214         """
   214         sysource = entity._cw.cnxset.source('system')
   215         sysource = entity._cw.cnxset.source('system')
   215         cu = sysource.doexec(entity._cw,
   216         cu = sysource.doexec(entity._cw,
   216                              'SELECT cw_%s FROM cw_%s WHERE cw_eid=%s' % (
   217                              'SELECT cw_%s FROM cw_%s WHERE cw_eid=%s' % (
   217                              attr, entity.__regid__, entity.eid))
   218                              attr, entity.__regid__, entity.eid))
   218         rawvalue = cu.fetchone()[0]
   219         rawvalue = cu.fetchone()[0]