diff mercurial/util.py @ 4868:192cd95c2ba8

merge with crew-stable
author Alexis S. L. Carvalho <alexis@cecm.usp.br>
date Wed, 11 Jul 2007 20:15:03 -0300
parents 0875082d5471
children 001e8a745834 3d35c8cb5eb4
line wrap: on
line diff
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -540,7 +540,7 @@ def _matcher(canonroot, cwd, names, inc,
 
     return (roots, match, (inc or exc or anypats) and True)
 
-_hgexecutable = None
+_hgexecutable = 'hg'
 
 def set_hgexecutable(path):
     """remember location of the 'hg' executable if easily possible
@@ -549,7 +549,8 @@ def set_hgexecutable(path):
     fall back to 'hg' in this case.
     """
     global _hgexecutable
-    _hgexecutable = path and os.path.abspath(path) or 'hg'
+    if path:
+        _hgexecutable = os.path.abspath(path)
 
 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
     '''enhanced shell command execution.
@@ -1181,70 +1182,95 @@ def encodedopener(openerfn, fn):
         return openerfn(fn(path), *args, **kw)
     return o
 
-def opener(base, audit=True):
+def mktempcopy(name, emptyok=False):
+    """Create a temporary file with the same contents from name
+
+    The permission bits are copied from the original file.
+
+    If the temporary file is going to be truncated immediately, you
+    can use emptyok=True as an optimization.
+
+    Returns the name of the temporary file.
     """
-    return a function that opens files relative to base
+    d, fn = os.path.split(name)
+    fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
+    os.close(fd)
+    # Temporary files are created with mode 0600, which is usually not
+    # what we want.  If the original file already exists, just copy
+    # its mode.  Otherwise, manually obey umask.
+    try:
+        st_mode = os.lstat(name).st_mode
+    except OSError, inst:
+        if inst.errno != errno.ENOENT:
+            raise
+        st_mode = 0666 & ~_umask
+    os.chmod(temp, st_mode)
+    if emptyok:
+        return temp
+    try:
+        try:
+            ifp = posixfile(name, "rb")
+        except IOError, inst:
+            if inst.errno == errno.ENOENT:
+                return temp
+            if not getattr(inst, 'filename', None):
+                inst.filename = name
+            raise
+        ofp = posixfile(temp, "wb")
+        for chunk in filechunkiter(ifp):
+            ofp.write(chunk)
+        ifp.close()
+        ofp.close()
+    except:
+        try: os.unlink(temp)
+        except: pass
+        raise
+    return temp
 
-    this function is used to hide the details of COW semantics and
+class atomictempfile(posixfile):
+    """file-like object that atomically updates a file
+
+    All writes will be redirected to a temporary copy of the original
+    file.  When rename is called, the copy is renamed to the original
+    name, making the changes visible.
+    """
+    def __init__(self, name, mode):
+        self.__name = name
+        self.temp = mktempcopy(name, emptyok=('w' in mode))
+        posixfile.__init__(self, self.temp, mode)
+
+    def rename(self):
+        if not self.closed:
+            posixfile.close(self)
+            rename(self.temp, localpath(self.__name))
+
+    def __del__(self):
+        if not self.closed:
+            try:
+                os.unlink(self.temp)
+            except: pass
+            posixfile.close(self)
+
+class opener(object):
+    """Open files relative to a base directory
+
+    This class is used to hide the details of COW semantics and
     remote file access from higher level code.
     """
-    def mktempcopy(name, emptyok=False):
-        d, fn = os.path.split(name)
-        fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
-        os.close(fd)
-        # Temporary files are created with mode 0600, which is usually not
-        # what we want.  If the original file already exists, just copy
-        # its mode.  Otherwise, manually obey umask.
-        try:
-            st_mode = os.lstat(name).st_mode
-        except OSError, inst:
-            if inst.errno != errno.ENOENT:
-                raise
-            st_mode = 0666 & ~_umask
-        os.chmod(temp, st_mode)
-        if emptyok:
-            return temp
-        try:
-            try:
-                ifp = posixfile(name, "rb")
-            except IOError, inst:
-                if inst.errno == errno.ENOENT:
-                    return temp
-                if not getattr(inst, 'filename', None):
-                    inst.filename = name
-                raise
-            ofp = posixfile(temp, "wb")
-            for chunk in filechunkiter(ifp):
-                ofp.write(chunk)
-            ifp.close()
-            ofp.close()
-        except:
-            try: os.unlink(temp)
-            except: pass
-            raise
-        return temp
+    def __init__(self, base, audit=True):
+        self.base = base
+        self.audit = audit
 
-    class atomictempfile(posixfile):
-        """the file will only be copied when rename is called"""
-        def __init__(self, name, mode):
-            self.__name = name
-            self.temp = mktempcopy(name, emptyok=('w' in mode))
-            posixfile.__init__(self, self.temp, mode)
-        def rename(self):
-            if not self.closed:
-                posixfile.close(self)
-                rename(self.temp, localpath(self.__name))
-        def __del__(self):
-            if not self.closed:
-                try:
-                    os.unlink(self.temp)
-                except: pass
-                posixfile.close(self)
+    def __getattr__(self, name):
+        if name == '_can_symlink':
+            self._can_symlink = checklink(self.base)
+            return self._can_symlink
+        raise AttributeError(name)
 
-    def o(path, mode="r", text=False, atomictemp=False):
-        if audit:
+    def __call__(self, path, mode="r", text=False, atomictemp=False):
+        if self.audit:
             audit_path(path)
-        f = os.path.join(base, path)
+        f = os.path.join(self.base, path)
 
         if not text and "b" not in mode:
             mode += "b" # for that other OS
@@ -1263,7 +1289,25 @@ def opener(base, audit=True):
                 rename(mktempcopy(f), f)
         return posixfile(f, mode)
 
-    return o
+    def symlink(self, src, dst):
+        if self.audit:
+            audit_path(dst)
+        linkname = os.path.join(self.base, dst)
+        try:
+            os.unlink(linkname)
+        except OSError:
+            pass
+
+        dirname = os.path.dirname(linkname)
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+
+        if self._can_symlink:
+            os.symlink(src, linkname)
+        else:
+            f = self(self, dst, "w")
+            f.write(src)
+            f.close()
 
 class chunkbuffer(object):
     """Allow arbitrary sized chunks of data to be efficiently read from an