Mercurial > hg
comparison mercurial/util.py @ 4827:89defeae88f3
turn util.opener into a class
author | Alexis S. L. Carvalho <alexis@cecm.usp.br> |
---|---|
date | Wed, 11 Jul 2007 17:40:41 -0300 |
parents | 7549cd526b7f |
children | 41ad4105dde9 |
comparison
equal
deleted
inserted
replaced
4826:15efc1d06143 | 4827:89defeae88f3 |
---|---|
1179 def encodedopener(openerfn, fn): | 1179 def encodedopener(openerfn, fn): |
1180 def o(path, *args, **kw): | 1180 def o(path, *args, **kw): |
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) |
1187 | 1195 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) |
1188 this function is used to hide the details of COW semantics and | 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 | |
1228 | |
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) | 1262 |
1195 # Temporary files are created with mode 0600, which is usually not | 1263 def __call__(self, path, mode="r", text=False, atomictemp=False): |
1196 # what we want. If the original file already exists, just copy | 1264 if self.audit: |
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 | |
1227 class atomictempfile(posixfile): | |
1228 """the file will only be copied when rename is called""" | |
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 |
1251 | 1270 |
1252 if mode[0] != "r": | 1271 if mode[0] != "r": |
1260 if atomictemp: | 1279 if atomictemp: |
1261 return atomictempfile(f, mode) | 1280 return atomictempfile(f, mode) |
1262 if nlink > 1: | 1281 if nlink > 1: |
1263 rename(mktempcopy(f), f) | 1282 rename(mktempcopy(f), f) |
1264 return posixfile(f, mode) | 1283 return posixfile(f, mode) |
1265 | |
1266 return o | |
1267 | 1284 |
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.""" |
1271 | 1288 |