mercurial/util.py
changeset 4858 89defeae88f3
parent 4802 7549cd526b7f
child 4859 41ad4105dde9
equal deleted inserted replaced
4843:15efc1d06143 4858: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