(Finally reviewing code.)

There's a bit of a strategical flaw in this code - symbolic modes are usually incomplete specifications, like u+w,g-w, but this code makes them complete specs. E.g., if I say 'mode => 'u+w,o-w', this would translate that to '200', but really we'd just want to make sure the user had write access and other didn't.

So this is more about changing the 'insync?' and 'sync' methods than the munging. We need 'insync?' to be able to compare the specified bits, probably using something like a mask, and we need 'sync' to know how to change just the bits that need to be changed.

Also, a couple of comments below.

On Jan 4, 2010, at 6:42 PM, Trevor Vaughan - Onyx Point wrote:

From: Trevor Vaughan <[email protected]>


Signed-off-by: Trevor Vaughan - Onyx Point <[email protected]>
---
lib/puppet/type/file/mode.rb | 115 ++++++++++++++++++++++++++++++++ +--------
1 files changed, 92 insertions(+), 23 deletions(-)

diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/ mode.rb
index 83034cb..dd582cf 100755
--- a/lib/puppet/type/file/mode.rb
+++ b/lib/puppet/type/file/mode.rb
@@ -4,9 +4,8 @@
module Puppet
    Puppet::Type.type(:file).newproperty(:mode) do
        require 'etc'
-        desc "Mode the file should be.  Currently relatively limited:
-            you must specify the exact mode the file should be.
-
+ desc "Mode the file should be. You may specify either the precise octal mode or the POSIX symbolic mode per GNU coreutils chmod.
+
Note that when you set the mode of a directory, Puppet always sets the search/traverse (1) bit anywhere the read (4) bit is set. This is almost always what you want: read allows you to list the
@@ -22,9 +21,74 @@ module Puppet

In this case all of the files underneath ``/some/dir`` will have
            mode 644, and all of the directories will have mode 755."
-
        @event = :file_changed

+ # This is a helper that takes a symbolic string and a file path and + # returns the adjusted decimal representation octal file mode (0700,
+        # etc...)
+        def sym2oct(str,path)
+            if str.to_s =~ /^\d+$/
+                value = str
+            else
+                curmode = "00000"
+                if File.exists?(path) then
+                    curmode = "%o" % File.stat(path).mode
+                    curmode = curmode[-5 .. -1]
+                end
+                value = Integer(curmode)
+
+                base =  {
+                        "u" => 6,
+                        "g" => 3,
+                        "o" => 0
+                        }
+
+                left =  {
+                        "u" => 05700,
+                        "g" => 03070,
+                        "o" => 01007,
+                        "a" => 07777
+                        }
+
+                right = {
+                        "r" => 00444,
+                        "w" => 00222,
+                        "x" => 00111,
+                        "s" => 06000,
+                        "t" => 01000,
+                        "u" => 00700,
+                        "g" => 00070,
+                        "o" => 00007
+                        }
+
+                reg = /^(([ugoa]+)([+-=])([rwxst]+|[ugo]),?)+$/
+
+                str.split(",").each do |cmd|
+                    match = cmd.match(reg) or return curmode
+ # The following vars are directly dependent on the
+                    # structure of the regex (reg) above
+                    who = match[2]
+                    what = match[3]
+                    how = match[4].split(//).uniq.to_s
+                    if how =~ /^[ugo]$/ then
+                      who.split(//).uniq.each do |lhv|
+ right[how] = ( ((value << (base[lhv] - base[how])) & right[lhv]) | ( value & ~right[lhv] ) ) & 0777
+                      end
+                    end
+ who = who.split(//).inject(num=0) {|num,b| num | = left[b]; num } + how = how.split(//).inject(num=0) {|num,b| num | = right[b]; num }
+                    mask = who & how
+                    case what
+                        when "+": value = value | mask
+                        when "-": value = value & ~mask
+ when "=": value = ( mask & who ) | ( value & ~(who & 0777) )
+                    end
+                end
+            end
+            Integer("0%o" % value)
+        end
+
+

This whole patch is missing tests, but this method especially needs tests. It'd be good to have a bunch of example inputs and expected outputs, with verification that it does what we expect.

It'd also be good, stylistically, to see the method broken up a bit, with the static hashes turned into constants. It might even be worth moving the symbol munging into a module, but that might be overkill.

# Our modes are octal, so make sure they print correctly. Other
        # valid values are symbols, basically
        def is_to_s(currentvalue)
@@ -52,29 +116,35 @@ module Puppet
        end

        munge do |should|
- # this is pretty hackish, but i need to make sure the number is in - # octal, yet the number can only be specified as a string right now + # This handles both numbers and symbolic modes matching the regex
+            # /^(([ugoa]+)([+-=])([rwx]+),?)$/
+            #
+ # Note: This now returns a string and the accepting function must
+            # know how to handle it!
+            lregex = /^(([ugoa]+)([+-=])([rwxst]+|[ugo]),?)+$/
+
            value = should
+
            if value.is_a?(String)
-                unless value =~ /^\d+$/
- raise Puppet::Error, "File modes can only be numbers, not %s" %
+                if value =~ /^\d+$/ then
+                    unless value =~ /^0/
+                        value = "0#{value}"
+                    end
+
+                    old = value
+                    begin
+                        value = Integer(value)
+                    rescue ArgumentError => detail
+ raise Puppet::DevError, "Could not convert %s to integer" %
+                            old.inspect
+                    end
+                elsif value.match(lregex).nil? then
+ raise Puppet::DevError, "Symbolic mode %s does not match #{lregex}" %
                        value.inspect
                end
-                # Make sure our number looks like octal.
-                unless value =~ /^0/
-                    value = "0" + value
-                end
-                old = value
-                begin
-                    value = Integer(value)
-                rescue ArgumentError => detail
- raise Puppet::DevError, "Could not convert %s to integer" %
-                        old.inspect
-                end
            end
-
-            return value
-        end
+            return sym2oct(value,@resource[:path])
+       end

This call was already in need of a refactor, and this additional code makes it cry out for one. It'd be good to see this code broken up into multiple small methods, with this block just calling out to them as necessary, rather than having the whole block inline.

        # If we're a directory, we need to be executable for all cases
# that are readable. This should probably be selectable, but eh.
@@ -121,7 +191,6 @@ module Puppet

        def sync
            mode = self.should
-
            begin
                File.chmod(mode, @resource[:path])
            rescue => detail
--
1.6.2.5

--

You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to [email protected] . For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en .




--
Computers are not intelligent. They only think they are.
---------------------------------------------------------------------
Luke Kanies  -|-   http://reductivelabs.com   -|-   +1(615)594-8199

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.


Reply via email to