Show More
@@ -1181,70 +1181,89 b' def encodedopener(openerfn, fn):' | |||||
1181 | return openerfn(fn(path), *args, **kw) |
|
1181 | return openerfn(fn(path), *args, **kw) | |
1182 | return o |
|
1182 | return o | |
1183 |
|
1183 | |||
1184 | def opener(base, audit=True): |
|
1184 | def mktempcopy(name, emptyok=False): | |
|
1185 | """Create a temporary file with the same contents from name | |||
|
1186 | ||||
|
1187 | The permission bits are copied from the original file. | |||
|
1188 | ||||
|
1189 | If the temporary file is going to be truncated immediately, you | |||
|
1190 | can use emptyok=True as an optimization. | |||
|
1191 | ||||
|
1192 | Returns the name of the temporary file. | |||
1185 |
|
|
1193 | """ | |
1186 | return a function that opens files relative to base |
|
1194 | d, fn = os.path.split(name) | |
|
1195 | fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) | |||
|
1196 | os.close(fd) | |||
|
1197 | # Temporary files are created with mode 0600, which is usually not | |||
|
1198 | # what we want. If the original file already exists, just copy | |||
|
1199 | # its mode. Otherwise, manually obey umask. | |||
|
1200 | try: | |||
|
1201 | st_mode = os.lstat(name).st_mode | |||
|
1202 | except OSError, inst: | |||
|
1203 | if inst.errno != errno.ENOENT: | |||
|
1204 | raise | |||
|
1205 | st_mode = 0666 & ~_umask | |||
|
1206 | os.chmod(temp, st_mode) | |||
|
1207 | if emptyok: | |||
|
1208 | return temp | |||
|
1209 | try: | |||
|
1210 | try: | |||
|
1211 | ifp = posixfile(name, "rb") | |||
|
1212 | except IOError, inst: | |||
|
1213 | if inst.errno == errno.ENOENT: | |||
|
1214 | return temp | |||
|
1215 | if not getattr(inst, 'filename', None): | |||
|
1216 | inst.filename = name | |||
|
1217 | raise | |||
|
1218 | ofp = posixfile(temp, "wb") | |||
|
1219 | for chunk in filechunkiter(ifp): | |||
|
1220 | ofp.write(chunk) | |||
|
1221 | ifp.close() | |||
|
1222 | ofp.close() | |||
|
1223 | except: | |||
|
1224 | try: os.unlink(temp) | |||
|
1225 | except: pass | |||
|
1226 | raise | |||
|
1227 | return temp | |||
1187 |
|
1228 | |||
1188 | this function is used to hide the details of COW semantics and |
|
1229 | class atomictempfile(posixfile): | |
|
1230 | """file-like object that atomically updates a file | |||
|
1231 | ||||
|
1232 | All writes will be redirected to a temporary copy of the original | |||
|
1233 | file. When rename is called, the copy is renamed to the original | |||
|
1234 | name, making the changes visible. | |||
|
1235 | """ | |||
|
1236 | def __init__(self, name, mode): | |||
|
1237 | self.__name = name | |||
|
1238 | self.temp = mktempcopy(name, emptyok=('w' in mode)) | |||
|
1239 | posixfile.__init__(self, self.temp, mode) | |||
|
1240 | ||||
|
1241 | def rename(self): | |||
|
1242 | if not self.closed: | |||
|
1243 | posixfile.close(self) | |||
|
1244 | rename(self.temp, localpath(self.__name)) | |||
|
1245 | ||||
|
1246 | def __del__(self): | |||
|
1247 | if not self.closed: | |||
|
1248 | try: | |||
|
1249 | os.unlink(self.temp) | |||
|
1250 | except: pass | |||
|
1251 | posixfile.close(self) | |||
|
1252 | ||||
|
1253 | class opener(object): | |||
|
1254 | """Open files relative to a base directory | |||
|
1255 | ||||
|
1256 | This class is used to hide the details of COW semantics and | |||
1189 | remote file access from higher level code. |
|
1257 | remote file access from higher level code. | |
1190 | """ |
|
1258 | """ | |
1191 | def mktempcopy(name, emptyok=False): |
|
1259 | def __init__(self, base, audit=True): | |
1192 | d, fn = os.path.split(name) |
|
1260 | self.base = base | |
1193 | fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) |
|
1261 | self.audit = audit | |
1194 | os.close(fd) |
|
|||
1195 | # Temporary files are created with mode 0600, which is usually not |
|
|||
1196 | # what we want. If the original file already exists, just copy |
|
|||
1197 | # its mode. Otherwise, manually obey umask. |
|
|||
1198 | try: |
|
|||
1199 | st_mode = os.lstat(name).st_mode |
|
|||
1200 | except OSError, inst: |
|
|||
1201 | if inst.errno != errno.ENOENT: |
|
|||
1202 | raise |
|
|||
1203 | st_mode = 0666 & ~_umask |
|
|||
1204 | os.chmod(temp, st_mode) |
|
|||
1205 | if emptyok: |
|
|||
1206 | return temp |
|
|||
1207 | try: |
|
|||
1208 | try: |
|
|||
1209 | ifp = posixfile(name, "rb") |
|
|||
1210 | except IOError, inst: |
|
|||
1211 | if inst.errno == errno.ENOENT: |
|
|||
1212 | return temp |
|
|||
1213 | if not getattr(inst, 'filename', None): |
|
|||
1214 | inst.filename = name |
|
|||
1215 | raise |
|
|||
1216 | ofp = posixfile(temp, "wb") |
|
|||
1217 | for chunk in filechunkiter(ifp): |
|
|||
1218 | ofp.write(chunk) |
|
|||
1219 | ifp.close() |
|
|||
1220 | ofp.close() |
|
|||
1221 | except: |
|
|||
1222 | try: os.unlink(temp) |
|
|||
1223 | except: pass |
|
|||
1224 | raise |
|
|||
1225 | return temp |
|
|||
1226 |
|
1262 | |||
1227 | class atomictempfile(posixfile): |
|
1263 | def __call__(self, path, mode="r", text=False, atomictemp=False): | |
1228 | """the file will only be copied when rename is called""" |
|
1264 | if self.audit: | |
1229 | def __init__(self, name, mode): |
|
|||
1230 | self.__name = name |
|
|||
1231 | self.temp = mktempcopy(name, emptyok=('w' in mode)) |
|
|||
1232 | posixfile.__init__(self, self.temp, mode) |
|
|||
1233 | def rename(self): |
|
|||
1234 | if not self.closed: |
|
|||
1235 | posixfile.close(self) |
|
|||
1236 | rename(self.temp, localpath(self.__name)) |
|
|||
1237 | def __del__(self): |
|
|||
1238 | if not self.closed: |
|
|||
1239 | try: |
|
|||
1240 | os.unlink(self.temp) |
|
|||
1241 | except: pass |
|
|||
1242 | posixfile.close(self) |
|
|||
1243 |
|
||||
1244 | def o(path, mode="r", text=False, atomictemp=False): |
|
|||
1245 | if audit: |
|
|||
1246 | audit_path(path) |
|
1265 | audit_path(path) | |
1247 | f = os.path.join(base, path) |
|
1266 | f = os.path.join(self.base, path) | |
1248 |
|
1267 | |||
1249 | if not text and "b" not in mode: |
|
1268 | if not text and "b" not in mode: | |
1250 | mode += "b" # for that other OS |
|
1269 | mode += "b" # for that other OS | |
@@ -1263,8 +1282,6 b' def opener(base, audit=True):' | |||||
1263 | rename(mktempcopy(f), f) |
|
1282 | rename(mktempcopy(f), f) | |
1264 | return posixfile(f, mode) |
|
1283 | return posixfile(f, mode) | |
1265 |
|
1284 | |||
1266 | return o |
|
|||
1267 |
|
||||
1268 | class chunkbuffer(object): |
|
1285 | class chunkbuffer(object): | |
1269 | """Allow arbitrary sized chunks of data to be efficiently read from an |
|
1286 | """Allow arbitrary sized chunks of data to be efficiently read from an | |
1270 | iterator over chunks of arbitrary size.""" |
|
1287 | iterator over chunks of arbitrary size.""" |
General Comments 0
You need to be logged in to leave comments.
Login now