[Checkins] SVN: z3c.recipe.mkdir/trunk/ Support `user`, `group` and `mode` option. First draft.

Ulrich Fouquet cvs-admin at zope.org
Sat Jun 23 04:11:47 UTC 2012


Log message for revision 127052:
  Support `user`, `group` and `mode` option. First draft.

Changed:
  U   z3c.recipe.mkdir/trunk/CHANGES.txt
  U   z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/README.txt
  U   z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/__init__.py
  U   z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/tests.py

-=-
Modified: z3c.recipe.mkdir/trunk/CHANGES.txt
===================================================================
--- z3c.recipe.mkdir/trunk/CHANGES.txt	2012-06-23 01:03:50 UTC (rev 127051)
+++ z3c.recipe.mkdir/trunk/CHANGES.txt	2012-06-23 04:11:43 UTC (rev 127052)
@@ -4,6 +4,8 @@
 0.4 (unreleased)
 ================
 
+* Added support for ``mode``, ``user``, and ``group`` options.
+
 * Fixed (unnoticed?) bug when using the deprecated ``path`` option. In
   that case the default path (``parts/<sectionname>``) was created
   instead of the given one.

Modified: z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/README.txt
===================================================================
--- z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/README.txt	2012-06-23 01:03:50 UTC (rev 127051)
+++ z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/README.txt	2012-06-23 04:11:43 UTC (rev 127052)
@@ -163,7 +163,51 @@
 Note, that the created directory will be removed on next modification
 of `buildout.cfg`.
 
+Setting user, group, and permissions
+====================================
 
+You can optionally set ``user``, ``group``, or ``mode`` option for the
+dirs to be created.
+
+While ``user`` and ``group`` give the user/group that should own the
+created directory, ``mode`` is expected to be an octal number to
+represent the directory permissions in Unix style.
+
+Of course, setting all these permissions and ownerships only works if
+the system supports it and the running user has the permissions to do
+so.
+
+  >>> write('buildout.cfg',
+  ... '''
+  ... [buildout]
+  ... parts = mydir
+  ... offline = true
+  ...
+  ... [mydir]
+  ... recipe = z3c.recipe.mkdir
+  ... paths = my/newdir
+  ... remove-on-update = true
+  ... mode = 700
+  ... user = %s
+  ... group = %s
+  ... ''' % (user, group))
+
+  >>> print system(join('bin', 'buildout')),
+  Uninstalling mydir.
+  Installing mydir.
+  mydir: created path: /sample-buildout/my
+  mydir:   mode 0700, user 'USER', group 'GROUP'
+  mydir: created path: /sample-buildout/my/newdir
+  mydir:   mode 0700, user 'USER', group 'GROUP'
+
+  >>> lls('my')
+  drwx------ USER GROUP my/newdir
+
+
+These options are optional, so you can leave any of them out and the system
+defaults will be used instead.
+
+
 Creating relative paths
 =======================
 

Modified: z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/__init__.py
===================================================================
--- z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/__init__.py	2012-06-23 01:03:50 UTC (rev 127051)
+++ z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/__init__.py	2012-06-23 04:11:43 UTC (rev 127052)
@@ -21,15 +21,50 @@
         self.paths = [os.path.normpath(os.path.abspath(
             x.strip())) for x in paths.split('\n')]
 
+        self.mode = options.get('mode', None)
+        if self.mode is not None:
+            try:
+                self.mode = int(self.mode, 8)
+            except ValueError:
+                raise zc.buildout.UserError(
+                    "'mode' must be an octal number: " % self.mode)
+
+        # determine user id
+        self.user = options.get('user', None)
+        self.uid = -1
+        if self.user:
+            try:
+                import pwd
+                self.uid = pwd.getpwnam(options['user'])[2]
+            except ImportError:
+                self.logger.warn(
+                    "System does not support `pwd`. Using default user")
+
+        # determine group id
+        self.group = options.get('group', None)
+        self.gid = -1
+        if self.group:
+            try:
+                import grp
+                self.gid = grp.getgrnam(options['group'])[2]
+            except ImportError:
+                self.logger.warn(
+                    "System does not support `grp`. Using default group")
+
         # Update options to be referencable...
         options['path'] = options['paths'] = '\n'.join(self.paths)
+        if self.mode:
+            options['mode'] = oct(self.mode)
+        if self.user:
+            options['user'] = self.user
+        if self.group:
+            options['group'] = self.group
 
     def install(self):
         for path in self.paths:
             self.createIntermediatePaths(path)
         return self.options.created()
 
-
     def update(self):
         return self.install()
 
@@ -38,14 +73,30 @@
         if os.path.exists(path) and not os.path.isdir(path):
             raise zc.buildout.UserError(
                 "Cannot create directory: %s. It's a file." % path)
-        if os.path.exists(path) or parent == path:
+        if parent == path or os.path.exists(path):
             return
         self.createIntermediatePaths(parent)
         os.mkdir(path)
         self.logger.info('created path: %s' % path)
+        self.setPermissions(path)
         if self.remove_on_update:
             self.options.created(path)
 
+    def setPermissions(self, path):
+        additional_msgs = []
+        if self.mode is not None:
+            os.chmod(path, self.mode)
+            additional_msgs.append('mode 0%o' % self.mode)
+        if self.uid != -1 or self.gid != -1:
+            os.chown(path, self.uid, self.gid)
+            if self.uid != -1:
+                additional_msgs.append("user %r" % self.user)
+            if self.gid != -1:
+                additional_msgs.append("group %r" % self.group)
+        if additional_msgs:
+            self.logger.info('  ' + ', '.join(additional_msgs))
+
+
 def string_to_bool(value):
     if value is True or value is False:
         return value

Modified: z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/tests.py
===================================================================
--- z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/tests.py	2012-06-23 01:03:50 UTC (rev 127051)
+++ z3c.recipe.mkdir/trunk/z3c/recipe/mkdir/tests.py	2012-06-23 04:11:43 UTC (rev 127052)
@@ -11,18 +11,47 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-
+import grp
+import os
+import pwd
 import re
+import stat
 import unittest
 import doctest
 
 import zc.buildout.testing
 from zope.testing import renormalizing
 
+user = pwd.getpwuid(os.geteuid()).pw_name
+group = grp.getgrgid(os.getegid()).gr_name
 
+def dir_entry(path):
+    # create a dir entry for file/dir in path.
+    def perm(mode):
+        # turn file stat mode into rwx...-string
+        result = ''
+        for grp in oct(mode)[-3:]:
+            perms = int(grp)
+            for num, sign in ((04, 'r'), (02, 'w'), (01, 'x')):
+                result += perms & num and sign or '-'
+        return result
+    st = os.stat(path)
+    type_flag = stat.S_ISDIR(st.st_mode) and 'd' or '-'
+    permissions = type_flag + perm(st.st_mode)
+    return '%s %s %s %s' % (permissions, user, group, path)
+
+def lls(path):
+    # list files and directories in `path` with permissions and type.
+    for name in sorted(os.listdir(path)):
+        print dir_entry(os.path.join(path, name))
+
+
 def setUp(test):
     zc.buildout.testing.buildoutSetUp(test)
     zc.buildout.testing.install_develop('z3c.recipe.mkdir', test)
+    test.globs['lls'] = lls
+    test.globs['user'] = user
+    test.globs['group'] = group
 
 
 checker = renormalizing.RENormalizing([
@@ -38,6 +67,10 @@
     (re.compile('-\S+-py\d[.]\d(-\S+)?.egg'),
      '-pyN.N.egg',
     ),
+    (re.compile("user '%s'" % user), "user 'USER'"),
+    (re.compile("group '%s'" % group), "group 'GROUP'"),
+    (re.compile("%s %s" % (user, group)), "USER GROUP"),
+    (re.compile(user), "USER"),
     ])
 
 



More information about the checkins mailing list