[Pkg-puppet-devel] [SCM] Packaging of Facter for debian branch, upstream, updated. 51bcebe38cab6088c901f1006339bbe40a36d161

James Turnbull james at lovedthanlost.net
Wed Aug 18 05:55:51 UTC 2010


The following commit has been merged in the upstream branch:
commit 83b3ea6abbd1d382a6738fa731f9f7409867e135
Author: David Schmitt <david at dasz.at>
Date:   Mon Jun 14 17:05:20 2010 +0200

    Fixed #3393 - Updates to Facter for MS Windows
    
    This patch is originally by Daniel Berger <djberg96 at gmail.com>, I
    changed using Facter.value instead of repeatedly testing
    Config['host_os'], removed Resolution::which, and fixed the specs.
    
    Thanks to Paul Nasrat for helping with cross-platform debugging.
    
    Signed-off-by: David Schmitt <david at dasz.at>

diff --git a/lib/facter/ipaddress.rb b/lib/facter/ipaddress.rb
index dd0d418..7c62aa1 100644
--- a/lib/facter/ipaddress.rb
+++ b/lib/facter/ipaddress.rb
@@ -111,30 +111,25 @@ end
 
 Facter.add(:ipaddress) do
     confine :kernel => %w{windows}
-    setcode do
-        ip = nil
-        output = %x{ipconfig}
-
-        output.split(/^\S/).each { |str|
-            if str =~ /IP Address.*: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
-                tmp = $1
-                unless tmp =~ /^127\./
-                    ip = tmp
-                    break
-                end
-            end
-        }
-        ip
-    end
+    require 'socket'
+    IPSocket.getaddress(Socket.gethostname)
 end
 
 Facter.add(:ipaddress, :ldapname => "iphostnumber", :timeout => 2) do
     setcode do
-        require 'resolv'
-
+        if Facter.value(:kernel) == 'windows'
+            require 'win32/resolv'
+        else
+            require 'resolv'
+        end
+        
         begin
             if hostname = Facter.value(:hostname)
-                ip = Resolv.getaddress(hostname)
+                if Facter.value(:kernel) == 'windows'
+                    ip = Win32::Resolv.get_resolv_info.last[0]
+                else
+                    ip = Resolv.getaddress(hostname)                
+                end
                 unless ip == "127.0.0.1"
                     ip
                 end
diff --git a/lib/facter/kernel.rb b/lib/facter/kernel.rb
index d68aa3f..66f21ce 100644
--- a/lib/facter/kernel.rb
+++ b/lib/facter/kernel.rb
@@ -2,8 +2,10 @@ Facter.add(:kernel) do
     setcode do
         require 'rbconfig'
         case Config::CONFIG['host_os']
-        when /mswin/i; 'windows'
-        else Facter::Util::Resolution.exec("uname -s")
+        when /mswin|win32|dos|cygwin|mingw/i
+            'windows'
+        else
+            Facter::Util::Resolution.exec("uname -s")
         end
     end
 end
diff --git a/lib/facter/macaddress.rb b/lib/facter/macaddress.rb
index e8f40dc..889feea 100644
--- a/lib/facter/macaddress.rb
+++ b/lib/facter/macaddress.rb
@@ -67,13 +67,26 @@ end
 Facter.add(:macaddress) do
     confine :kernel => %w(windows)
     setcode do
-        ether = []
-        output = %x{ipconfig /all}
-        output.split(/\r\n/).each do |str|
-            if str =~  /.*Physical Address.*: (\w{1,2}-\w{1,2}-\w{1,2}-\w{1,2}-\w{1,2}-\w{1,2})/
-                ether.push($1.gsub(/-/, ":"))
-            end
-        end
-        ether[0]
+        require 'win32ole'
+        require 'socket'
+
+        ether = nil
+        host = Socket.gethostname
+        connect_string = "winmgmts://#{host}/root/cimv2"
+
+        wmi = WIN32OLE.connect(connect_string)
+
+        query = %Q{
+          select *
+          from Win32_NetworkAdapterConfiguration
+          where IPEnabled = True
+        }
+
+        wmi.ExecQuery(query).each{ |nic|
+          ether = nic.MacAddress
+          break
+        }
+        
+        ether
     end
 end
diff --git a/lib/facter/util/resolution.rb b/lib/facter/util/resolution.rb
index b9e28e8..f837f64 100644
--- a/lib/facter/util/resolution.rb
+++ b/lib/facter/util/resolution.rb
@@ -11,9 +11,13 @@ require 'rbconfig'
 class Facter::Util::Resolution
     attr_accessor :interpreter, :code, :name, :timeout
 
+    WINDOWS = Config::CONFIG['host_os'] =~ /mswin|win32|dos|mingw|cygwin/i
+
+    INTERPRETER = WINDOWS ? 'cmd.exe' : '/bin/sh'
+
     def self.have_which
         if ! defined?(@have_which) or @have_which.nil?
-            if Config::CONFIG['host_os'] =~ /mswin/
+            if Facter.value(:kernel) == 'windows'
                 @have_which = false
             else
                 %x{which which >/dev/null 2>&1}
@@ -23,31 +27,50 @@ class Facter::Util::Resolution
         @have_which
     end
 
-    # Execute a chunk of code.
-    def self.exec(code, interpreter = "/bin/sh")
-        raise ArgumentError, "non-sh interpreters are not currently supported" unless interpreter == "/bin/sh"
-        binary = code.split(/\s+/).shift
-
-        if have_which
+    # Execute a program and return the output of that program.
+    #
+    # Returns nil if the program can't be found, or if there is a problem
+    # executing the code.
+    #
+    def self.exec(code, interpreter = INTERPRETER)
+        raise ArgumentError, "invalid interpreter" unless interpreter == INTERPRETER
+
+        # Try to guess whether the specified code can be executed by looking at the
+        # first word. If it cannot be found on the PATH defer on resolving the fact
+        # by returning nil.
+        # This only fails on shell built-ins, most of which are masked by stuff in 
+        # /bin or of dubious value anyways. In the worst case, "sh -c 'builtin'" can
+        # be used to work around this limitation
+        #
+        # Windows' %x{} throws Errno::ENOENT when the command is not found, so we 
+        # can skip the check there. This is good, since builtins cannot be found 
+        # elsewhere.
+        if have_which and !WINDOWS
             path = nil
-            if binary !~ /^\//
+            binary = code.split.first
+            if code =~ /^\//
+                path = binary
+            else
                 path = %x{which #{binary} 2>/dev/null}.chomp
                 # we don't have the binary necessary
                 return nil if path == "" or path.match(/Command not found\./)
-            else
-                path = binary
             end
 
             return nil unless FileTest.exists?(path)
         end
 
         out = nil
+
         begin
             out = %x{#{code}}.chomp
+        rescue Errno::ENOENT => detail
+            # command not found on Windows
+            return nil
         rescue => detail
             $stderr.puts detail
             return nil
         end
+
         if out == ""
             return nil
         else
@@ -86,7 +109,7 @@ class Facter::Util::Resolution
     def setcode(string = nil, interp = nil, &block)
         if string
             @code = string
-            @interpreter = interp || "/bin/sh"
+            @interpreter = interp || INTERPRETER
         else
             unless block_given?
                 raise ArgumentError, "You must pass either code or a block"
diff --git a/spec/unit/util/resolution.rb b/spec/unit/util/resolution.rb
index 7cbfb31..396f800 100755
--- a/spec/unit/util/resolution.rb
+++ b/spec/unit/util/resolution.rb
@@ -44,9 +44,10 @@ describe Facter::Util::Resolution do
             @resolve = Facter::Util::Resolution.new("yay")
         end
 
-        it "should default to /bin/sh as the interpreter if a string is provided" do
+        it "should default to the detected interpreter if a string is provided" do
+            Facter::Util::Resolution::INTERPRETER = "/bin/bar"
             @resolve.setcode "foo"
-            @resolve.interpreter.should == "/bin/sh"
+            @resolve.interpreter.should == "/bin/bar"
         end
 
         it "should set the code to any provided string" do
@@ -87,17 +88,44 @@ describe Facter::Util::Resolution do
         end
 
         describe "and the code is a string" do
-            it "should return the result of executing the code with the interpreter" do
-                @resolve.setcode "/bin/foo"
-                Facter::Util::Resolution.expects(:exec).with("/bin/foo", "/bin/sh").returns "yup"
-
-                @resolve.value.should == "yup"
+            describe "on windows" do
+                before do
+                    Facter::Util::Resolution::WINDOWS = true
+                    Facter::Util::Resolution::INTERPRETER = "cmd.exe"
+                end
+                
+                it "should return the result of executing the code with the interpreter" do
+                    @resolve.setcode "/bin/foo"
+                    Facter::Util::Resolution.expects(:exec).once.with("/bin/foo", "cmd.exe").returns "yup"
+
+                    @resolve.value.should == "yup"
+                end
+
+                it "should return nil if the value is an empty string" do
+                    @resolve.setcode "/bin/foo"
+                    Facter::Util::Resolution.expects(:exec).once.returns ""
+                    @resolve.value.should be_nil
+                end
             end
 
-            it "should return nil if the value is an empty string" do
-                @resolve.setcode "/bin/foo"
-                Facter::Util::Resolution.stubs(:exec).returns ""
-                @resolve.value.should be_nil
+            describe "on non-windows systems" do
+                before do
+                    Facter::Util::Resolution::WINDOWS = false
+                    Facter::Util::Resolution::INTERPRETER = "/bin/sh"
+                end
+                
+                it "should return the result of executing the code with the interpreter" do
+                    @resolve.setcode "/bin/foo"
+                    Facter::Util::Resolution.expects(:exec).once.with("/bin/foo", "/bin/sh").returns "yup"
+
+                    @resolve.value.should == "yup"
+                end
+
+                it "should return nil if the value is an empty string" do
+                    @resolve.setcode "/bin/foo"
+                    Facter::Util::Resolution.expects(:exec).once.returns ""
+                    @resolve.value.should be_nil
+                end
             end
         end
 
@@ -233,5 +261,9 @@ describe Facter::Util::Resolution do
         it "should fail if any interpreter other than /bin/sh is requested" do
             lambda { Facter::Util::Resolution.exec("/something", "/bin/perl") }.should raise_error(ArgumentError)
         end
+
+        it "should execute the binary" do
+            Facter::Util::Resolution.exec("echo foo").should == "foo"
+        end
     end
 end

-- 
Packaging of Facter for debian



More information about the Pkg-puppet-devel mailing list