104 """sql generator callback when some attribute with a custom storage is |
104 """sql generator callback when some attribute with a custom storage is |
105 accessed |
105 accessed |
106 """ |
106 """ |
107 fpath = source.binary_to_str(value) |
107 fpath = source.binary_to_str(value) |
108 try: |
108 try: |
109 return Binary(file(fpath).read()) |
109 return Binary(file(fpath, 'rb').read()) |
110 except OSError, ex: |
110 except OSError, ex: |
111 source.critical("can't open %s: %s", value, ex) |
111 source.critical("can't open %s: %s", value, ex) |
112 return None |
112 return None |
113 |
113 |
114 def entity_added(self, entity, attr): |
114 def entity_added(self, entity, attr): |
115 """an entity using this storage for attr has been added""" |
115 """an entity using this storage for attr has been added""" |
116 if entity._cw.transaction_data.get('fs_importing'): |
116 if entity._cw.transaction_data.get('fs_importing'): |
117 binary = Binary(file(entity[attr].getvalue()).read()) |
117 binary = Binary(file(entity[attr].getvalue(), 'rb').read()) |
118 else: |
118 else: |
119 binary = entity.pop(attr) |
119 binary = entity.pop(attr) |
120 fpath = self.new_fs_path(entity, attr) |
120 fpath = self.new_fs_path(entity, attr) |
121 # bytes storage used to store file's path |
121 # bytes storage used to store file's path |
122 entity[attr] = Binary(fpath) |
122 entity[attr] = Binary(fpath) |
123 file(fpath, 'w').write(binary.getvalue()) |
123 file(fpath, 'wb').write(binary.getvalue()) |
124 hook.set_operation(entity._cw, 'bfss_added', fpath, AddFileOp) |
124 hook.set_operation(entity._cw, 'bfss_added', fpath, AddFileOp) |
125 return binary |
125 return binary |
126 |
126 |
127 def entity_updated(self, entity, attr): |
127 def entity_updated(self, entity, attr): |
128 """an entity using this storage for attr has been updatded""" |
128 """an entity using this storage for attr has been updatded""" |
|
129 # get the name of the previous file containing the value |
129 oldpath = self.current_fs_path(entity, attr) |
130 oldpath = self.current_fs_path(entity, attr) |
130 if entity._cw.transaction_data.get('fs_importing'): |
131 if entity._cw.transaction_data.get('fs_importing'): |
|
132 # If we are importing from the filesystem, the file already exists. |
|
133 # We do not need to create it but we need to fetch the content of |
|
134 # the file as the actual content of the attribute |
131 fpath = entity[attr].getvalue() |
135 fpath = entity[attr].getvalue() |
132 binary = Binary(file(fpath).read()) |
136 binary = Binary(file(fpath, 'rb').read()) |
133 else: |
137 else: |
|
138 # We must store the content of the attributes |
|
139 # into a file to stay consistent with the behaviour of entity_add. |
|
140 # Moreover, the BytesFileSystemStorage expects to be able to |
|
141 # retrieve the current value of the attribute at anytime by reading |
|
142 # the file on disk. To be able to rollback things, use a new file |
|
143 # and keep the old one that will be removed on commit if everything |
|
144 # went ok. |
|
145 # |
|
146 # fetch the current attribute value in memory |
134 binary = entity.pop(attr) |
147 binary = entity.pop(attr) |
|
148 # Get filename for it |
135 fpath = self.new_fs_path(entity, attr) |
149 fpath = self.new_fs_path(entity, attr) |
136 UpdateFileOp(entity._cw, filepath=fpath, filedata=binary.getvalue()) |
150 assert not osp.exists(fpath) |
|
151 # write attribute value on disk |
|
152 file(fpath, 'wb').write(binary.getvalue()) |
|
153 # Mark the new file as added during the transaction. |
|
154 # The file will be removed on rollback |
|
155 hook.set_operation(entity._cw, 'bfss_added', fpath, AddFileOp) |
137 if oldpath != fpath: |
156 if oldpath != fpath: |
|
157 # register the new location for the file. |
138 entity[attr] = Binary(fpath) |
158 entity[attr] = Binary(fpath) |
|
159 # Mark the old file as useless so the file will be removed at |
|
160 # commit. |
139 hook.set_operation(entity._cw, 'bfss_deleted', oldpath, |
161 hook.set_operation(entity._cw, 'bfss_deleted', oldpath, |
140 DeleteFileOp) |
162 DeleteFileOp) |
141 return binary |
163 return binary |
142 |
164 |
143 def entity_deleted(self, entity, attr): |
165 def entity_deleted(self, entity, attr): |