Make files in .hg inherit the permissions from .hg/store
authorAlexis S. L. Carvalho <alexis@cecm.usp.br>
Sat, 09 Feb 2008 18:38:54 -0200
changeset 6062 3c3b126e5619
parent 6061 de08788511d7
child 6063 b74a0c4bfb30
Make files in .hg inherit the permissions from .hg/store
mercurial/localrepo.py
mercurial/util.py
--- a/mercurial/localrepo.py	Sat Feb 09 20:17:09 2008 +0100
+++ b/mercurial/localrepo.py	Sat Feb 09 18:38:54 2008 -0200
@@ -68,8 +68,20 @@
             self.encodefn = lambda x: x
             self.decodefn = lambda x: x
             self.spath = self.path
-        self.sopener = util.encodedopener(util.opener(self.spath),
-                                          self.encodefn)
+
+        try:
+            # files in .hg/ will be created using this mode
+            mode = os.stat(self.spath).st_mode
+            # avoid some useless chmods
+            if (0777 & ~util._umask) == (0777 & mode):
+                mode = None
+        except OSError:
+            mode = None
+
+        self.opener.createmode = mode
+        sopener = util.opener(self.spath)
+        sopener.createmode = mode
+        self.sopener = util.encodedopener(sopener, self.encodefn)
 
         self.ui = ui.ui(parentui=parentui)
         try:
--- a/mercurial/util.py	Sat Feb 09 20:17:09 2008 +0100
+++ b/mercurial/util.py	Sat Feb 09 18:38:54 2008 -0200
@@ -1298,7 +1298,7 @@
         return openerfn(fn(path), *args, **kw)
     return o
 
-def mktempcopy(name, emptyok=False):
+def mktempcopy(name, emptyok=False, createmode=None):
     """Create a temporary file with the same contents from name
 
     The permission bits are copied from the original file.
@@ -1319,7 +1319,10 @@
     except OSError, inst:
         if inst.errno != errno.ENOENT:
             raise
-        st_mode = 0666 & ~_umask
+        st_mode = createmode
+        if st_mode is None:
+            st_mode = ~_umask
+        st_mode &= 0666
     os.chmod(temp, st_mode)
     if emptyok:
         return temp
@@ -1350,9 +1353,10 @@
     file.  When rename is called, the copy is renamed to the original
     name, making the changes visible.
     """
-    def __init__(self, name, mode):
+    def __init__(self, name, mode, createmode):
         self.__name = name
-        self.temp = mktempcopy(name, emptyok=('w' in mode))
+        self.temp = mktempcopy(name, emptyok=('w' in mode),
+                               createmode=createmode)
         posixfile.__init__(self, self.temp, mode)
 
     def rename(self):
@@ -1367,6 +1371,22 @@
             except: pass
             posixfile.close(self)
 
+def makedirs(name, mode=None):
+    """recursive directory creation with parent mode inheritance"""
+    try:
+        os.mkdir(name)
+        if mode is not None:
+            os.chmod(name, mode)
+        return
+    except OSError, err:
+        if err.errno == errno.EEXIST:
+            return
+        if err.errno != errno.ENOENT:
+            raise
+    parent = os.path.abspath(os.path.dirname(name))
+    makedirs(parent, mode)
+    makedirs(name, mode)
+
 class opener(object):
     """Open files relative to a base directory
 
@@ -1379,6 +1399,7 @@
             self.audit_path = path_auditor(base)
         else:
             self.audit_path = always
+        self.createmode = None
 
     def __getattr__(self, name):
         if name == '_can_symlink':
@@ -1386,6 +1407,11 @@
             return self._can_symlink
         raise AttributeError(name)
 
+    def _fixfilemode(self, name):
+        if self.createmode is None:
+            return
+        os.chmod(name, self.createmode & 0666)
+
     def __call__(self, path, mode="r", text=False, atomictemp=False):
         self.audit_path(path)
         f = os.path.join(self.base, path)
@@ -1393,6 +1419,7 @@
         if not text and "b" not in mode:
             mode += "b" # for that other OS
 
+        nlink = -1
         if mode[0] != "r":
             try:
                 nlink = nlinks(f)
@@ -1400,12 +1427,15 @@
                 nlink = 0
                 d = os.path.dirname(f)
                 if not os.path.isdir(d):
-                    os.makedirs(d)
+                    makedirs(d, self.createmode)
             if atomictemp:
-                return atomictempfile(f, mode)
+                return atomictempfile(f, mode, self.createmode)
             if nlink > 1:
                 rename(mktempcopy(f), f)
-        return posixfile(f, mode)
+        fp = posixfile(f, mode)
+        if nlink == 0:
+            self._fixfilemode(f)
+        return fp
 
     def symlink(self, src, dst):
         self.audit_path(dst)
@@ -1417,7 +1447,7 @@
 
         dirname = os.path.dirname(linkname)
         if not os.path.exists(dirname):
-            os.makedirs(dirname)
+            makedirs(dirname, self.createmode)
 
         if self._can_symlink:
             try:
@@ -1429,6 +1459,7 @@
             f = self(dst, "w")
             f.write(src)
             f.close()
+            self._fixfilemode(dst)
 
 class chunkbuffer(object):
     """Allow arbitrary sized chunks of data to be efficiently read from an