mercurial/util.py
changeset 4868 192cd95c2ba8
parent 4863 0875082d5471
child 4876 001e8a745834
child 5067 3d35c8cb5eb4
equal deleted inserted replaced
4857:8be7ba425621 4868:192cd95c2ba8
   538     else:
   538     else:
   539         match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn)
   539         match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn)
   540 
   540 
   541     return (roots, match, (inc or exc or anypats) and True)
   541     return (roots, match, (inc or exc or anypats) and True)
   542 
   542 
   543 _hgexecutable = None
   543 _hgexecutable = 'hg'
   544 
   544 
   545 def set_hgexecutable(path):
   545 def set_hgexecutable(path):
   546     """remember location of the 'hg' executable if easily possible
   546     """remember location of the 'hg' executable if easily possible
   547 
   547 
   548     path might be None or empty if hg was loaded as a module,
   548     path might be None or empty if hg was loaded as a module,
   549     fall back to 'hg' in this case.
   549     fall back to 'hg' in this case.
   550     """
   550     """
   551     global _hgexecutable
   551     global _hgexecutable
   552     _hgexecutable = path and os.path.abspath(path) or 'hg'
   552     if path:
       
   553         _hgexecutable = os.path.abspath(path)
   553 
   554 
   554 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
   555 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
   555     '''enhanced shell command execution.
   556     '''enhanced shell command execution.
   556     run with environment maybe modified, maybe in different dir.
   557     run with environment maybe modified, maybe in different dir.
   557 
   558 
  1179 def encodedopener(openerfn, fn):
  1180 def encodedopener(openerfn, fn):
  1180     def o(path, *args, **kw):
  1181     def o(path, *args, **kw):
  1181         return openerfn(fn(path), *args, **kw)
  1182         return openerfn(fn(path), *args, **kw)
  1182     return o
  1183     return o
  1183 
  1184 
  1184 def opener(base, audit=True):
  1185 def mktempcopy(name, emptyok=False):
       
  1186     """Create a temporary file with the same contents from name
       
  1187 
       
  1188     The permission bits are copied from the original file.
       
  1189 
       
  1190     If the temporary file is going to be truncated immediately, you
       
  1191     can use emptyok=True as an optimization.
       
  1192 
       
  1193     Returns the name of the temporary file.
  1185     """
  1194     """
  1186     return a function that opens files relative to base
  1195     d, fn = os.path.split(name)
  1187 
  1196     fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
  1188     this function is used to hide the details of COW semantics and
  1197     os.close(fd)
       
  1198     # Temporary files are created with mode 0600, which is usually not
       
  1199     # what we want.  If the original file already exists, just copy
       
  1200     # its mode.  Otherwise, manually obey umask.
       
  1201     try:
       
  1202         st_mode = os.lstat(name).st_mode
       
  1203     except OSError, inst:
       
  1204         if inst.errno != errno.ENOENT:
       
  1205             raise
       
  1206         st_mode = 0666 & ~_umask
       
  1207     os.chmod(temp, st_mode)
       
  1208     if emptyok:
       
  1209         return temp
       
  1210     try:
       
  1211         try:
       
  1212             ifp = posixfile(name, "rb")
       
  1213         except IOError, inst:
       
  1214             if inst.errno == errno.ENOENT:
       
  1215                 return temp
       
  1216             if not getattr(inst, 'filename', None):
       
  1217                 inst.filename = name
       
  1218             raise
       
  1219         ofp = posixfile(temp, "wb")
       
  1220         for chunk in filechunkiter(ifp):
       
  1221             ofp.write(chunk)
       
  1222         ifp.close()
       
  1223         ofp.close()
       
  1224     except:
       
  1225         try: os.unlink(temp)
       
  1226         except: pass
       
  1227         raise
       
  1228     return temp
       
  1229 
       
  1230 class atomictempfile(posixfile):
       
  1231     """file-like object that atomically updates a file
       
  1232 
       
  1233     All writes will be redirected to a temporary copy of the original
       
  1234     file.  When rename is called, the copy is renamed to the original
       
  1235     name, making the changes visible.
       
  1236     """
       
  1237     def __init__(self, name, mode):
       
  1238         self.__name = name
       
  1239         self.temp = mktempcopy(name, emptyok=('w' in mode))
       
  1240         posixfile.__init__(self, self.temp, mode)
       
  1241 
       
  1242     def rename(self):
       
  1243         if not self.closed:
       
  1244             posixfile.close(self)
       
  1245             rename(self.temp, localpath(self.__name))
       
  1246 
       
  1247     def __del__(self):
       
  1248         if not self.closed:
       
  1249             try:
       
  1250                 os.unlink(self.temp)
       
  1251             except: pass
       
  1252             posixfile.close(self)
       
  1253 
       
  1254 class opener(object):
       
  1255     """Open files relative to a base directory
       
  1256 
       
  1257     This class is used to hide the details of COW semantics and
  1189     remote file access from higher level code.
  1258     remote file access from higher level code.
  1190     """
  1259     """
  1191     def mktempcopy(name, emptyok=False):
  1260     def __init__(self, base, audit=True):
  1192         d, fn = os.path.split(name)
  1261         self.base = base
  1193         fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
  1262         self.audit = audit
  1194         os.close(fd)
  1263 
  1195         # Temporary files are created with mode 0600, which is usually not
  1264     def __getattr__(self, name):
  1196         # what we want.  If the original file already exists, just copy
  1265         if name == '_can_symlink':
  1197         # its mode.  Otherwise, manually obey umask.
  1266             self._can_symlink = checklink(self.base)
  1198         try:
  1267             return self._can_symlink
  1199             st_mode = os.lstat(name).st_mode
  1268         raise AttributeError(name)
  1200         except OSError, inst:
  1269 
  1201             if inst.errno != errno.ENOENT:
  1270     def __call__(self, path, mode="r", text=False, atomictemp=False):
  1202                 raise
  1271         if self.audit:
  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)
  1272             audit_path(path)
  1247         f = os.path.join(base, path)
  1273         f = os.path.join(self.base, path)
  1248 
  1274 
  1249         if not text and "b" not in mode:
  1275         if not text and "b" not in mode:
  1250             mode += "b" # for that other OS
  1276             mode += "b" # for that other OS
  1251 
  1277 
  1252         if mode[0] != "r":
  1278         if mode[0] != "r":
  1261                 return atomictempfile(f, mode)
  1287                 return atomictempfile(f, mode)
  1262             if nlink > 1:
  1288             if nlink > 1:
  1263                 rename(mktempcopy(f), f)
  1289                 rename(mktempcopy(f), f)
  1264         return posixfile(f, mode)
  1290         return posixfile(f, mode)
  1265 
  1291 
  1266     return o
  1292     def symlink(self, src, dst):
       
  1293         if self.audit:
       
  1294             audit_path(dst)
       
  1295         linkname = os.path.join(self.base, dst)
       
  1296         try:
       
  1297             os.unlink(linkname)
       
  1298         except OSError:
       
  1299             pass
       
  1300 
       
  1301         dirname = os.path.dirname(linkname)
       
  1302         if not os.path.exists(dirname):
       
  1303             os.makedirs(dirname)
       
  1304 
       
  1305         if self._can_symlink:
       
  1306             os.symlink(src, linkname)
       
  1307         else:
       
  1308             f = self(self, dst, "w")
       
  1309             f.write(src)
       
  1310             f.close()
  1267 
  1311 
  1268 class chunkbuffer(object):
  1312 class chunkbuffer(object):
  1269     """Allow arbitrary sized chunks of data to be efficiently read from an
  1313     """Allow arbitrary sized chunks of data to be efficiently read from an
  1270     iterator over chunks of arbitrary size."""
  1314     iterator over chunks of arbitrary size."""
  1271 
  1315