Codebase list facter / a40be6d
Merge tag 'upstream/1.6.10' Upstream version 1.6.10 Stig Sandbeck Mathisen 11 years ago
49 changed file(s) with 1313 addition(s) and 128 deletion(s). Raw diff Collapse all Expand all
0 Autotest.add_discovery { "rspec2" }
1
2 Autotest.add_hook :initialize do |at|
3 at.clear_mappings
4
5 # the libraries under lib/facter
6 at.add_mapping(%r%^lib/facter/(.*)\.rb$%) { |filename, m|
7 at.files_matching %r!spec/(unit|integration)/#{m[1]}.rb!
8 }
9
10 # the actual spec files themselves
11 at.add_mapping(%r%^spec/(unit|integration)/.*\.rb$%) { |filename, _|
12 filename
13 }
14
15 # force a complete re-run for all of these:
16
17 # main facter lib
18 at.add_mapping(%r!^lib/facter\.rb$!) { |filename, _|
19 at.files_matching %r!spec/(unit|integration)/.*\.rb!
20 }
21
22 # the spec_helper
23 at.add_mapping(%r!^spec/spec_helper\.rb$!) { |filename, _|
24 at.files_matching %r!spec/(unit|integration)/.*\.rb!
25 }
26
27 # the facter spec libraries
28 at.add_mapping(%r!^spec/lib/spec.*!) { |filename, _|
29 at.files_matching %r!spec/(unit|integration)/.*\.rb!
30 }
31
32 # the monkey patches for rspec
33 at.add_mapping(%r!^spec/lib/monkey_patches/.*!) { |filename, _|
34 at.files_matching %r!spec/(unit|integration)/.*\.rb!
35 }
36 end
0 --colour
0 1.6.10
1 ===
2 35067dc Bump Facter epoch to 1
3 d6a3e91 Make package task depend on tar in Rakfile
4 f42896d (#14764) Stub architecture fact when Windows facts run on Linux
5 f44ca52 (maint) Fix hardware model fact for ruby 1.9
6 964d1f0 (#12864) Close registry key
7 ab025bb Revert "Revert "(#12864) Windows: get primary DNS from registry""
8 478386d (#10261) Detect x64 architecture on Windows
9 6cc881d Use git describe in Rakefile to determine pkg ver
10 2043244 (#13678) Remove deprecation msg triggerd by the ipaddress6 fact
11 d118d81 (#13678) Add filename extension on absolute paths on windows
12 b050eb1 (#14582) Fix noise in LSB facts
13 85654b0 (#13678) Allow passing shell built-ins to exec method on windows
14 8f4c016 (#13678) Single quote paths on unix with spaces
15 2d164e8 (#13678) Join PATHs correctly on windows
16 e7e7e8f (#13678) Extend spec tests for expand_command
17 0fea7b0 maint: Add shared context for specs to imitate windows or posix
18 60d0cd2 (#13678) Fix spec failures on windows
19 121a2ab (#13678) Fix quoting in expand_command
20 55b1125 (#13678) Add more unit tests for new methods
21 9086c0a (#13678) Add RDoc documentation for new methods
22 165ace4 (#13678) Convert command to absolute paths before executing
23
024 1.6.9
125 ===
226 b398bd8 (#14334) Fix dmidecode based facts on DragonFly BSD
1616 require 'rake/packagetask'
1717 require 'rake/gempackagetask'
1818
19 module Facter
20 FACTERVERSION = File.read('lib/facter.rb')[/FACTERVERSION *= *'(.*)'/,1] or fail "Couldn't find FACTERVERSION"
21 end
22
2319 FILES = FileList[
2420 '[A-Z]*',
2521 'install.rb',
3026 'spec/**/*'
3127 ]
3228
29 def get_version
30 `git describe`.strip
31 end
32
33 # :build_environment and :tar are mostly borrowed from puppet-dashboard Rakefile
34 task :build_environment do
35 unless ENV['FORCE'] == '1'
36 modified = `git status --porcelain | sed -e '/^\?/d'`
37 if modified.split(/\n/).length != 0
38 puts <<-HERE
39 !! ERROR: Your git working directory is not clean. You must
40 !! remove or commit your changes before you can create a package:
41
42 #{`git status | grep '^#'`.chomp}
43
44 !! To override this check, set FORCE=1 -- e.g. `rake package:deb FORCE=1`
45 HERE
46 raise
47 end
48 end
49 end
50
51 desc "Create a release .tar.gz"
52 task :tar => :build_environment do
53 name = "facter"
54 rm_rf 'pkg/tar'
55 temp=`mktemp -d -t tmpXXXXXX`.strip!
56 version = get_version
57 base = "#{temp}/#{name}-#{version}/"
58 mkdir_p base
59 sh "git checkout-index -af --prefix=#{base}"
60 mkdir_p "pkg/tar"
61 sh "tar -C #{temp} -pczf #{temp}/#{name}-#{version}.tar.gz #{name}-#{version}"
62 mv "#{temp}/#{name}-#{version}.tar.gz", "pkg/tar"
63 rm_rf temp
64 puts "Tarball is pkg/tar/#{name}-#{version}.tar.gz"
65 end
66
3367 spec = Gem::Specification.new do |spec|
3468 spec.platform = Gem::Platform::RUBY
3569 spec.name = 'facter'
3670 spec.files = FILES.to_a
3771 spec.executables = %w{facter}
38 spec.version = Facter::FACTERVERSION
72 spec.version = get_version.split('-')[0]
3973 spec.summary = 'Facter, a system inventory tool'
4074 spec.description = 'You can prove anything with facts!'
4175 spec.author = 'Puppet Labs'
4882 '--main' << 'README' <<
4983 '--line-numbers'
5084 end
51
52 Rake::PackageTask.new("facter", Facter::FACTERVERSION) do |pkg|
53 pkg.package_dir = 'pkg'
54 pkg.need_tar_gz = true
55 pkg.package_files = FILES.to_a
85 Rake::GemPackageTask.new(spec) do |pkg|
5686 end
5787
58 Rake::GemPackageTask.new(spec) do |pkg|
59 end
88 task :package => :tar
6089
6190 task :default do
6291 sh %{rake -T}
0 test_name "#7670: Facter should properly detect operatingsystem on Ubuntu after a clear"
1
2 script_contents = <<-OS_DETECT
3 require 'facter'
4 Facter['operatingsystem'].value
5 Facter.clear
6 exit Facter['operatingsystem'].value == 'Ubuntu'
7 OS_DETECT
8
9 script_name = "/tmp/facter_os_detection_test_#{$$}"
10
11 agents.each do |agent|
12 next unless agent['platform'].include? 'ubuntu'
13
14 create_remote_file(agent, script_name, script_contents)
15
16 on(agent, "ruby #{script_name}")
17 end
0 test_name "#7039: Facter having issue handling multiple facts in a single file"
1
2 fact_file= %q{
3 Facter.add(:test_fact1) do
4 setcode do
5 "test fact 1"
6 end
7 end
8
9 Facter.add(:test_fact2) do
10 setcode do
11 "test fact 2"
12 end
13 end
14 }
15
16 agent1=agents.first
17 step "Agent: Create fact file with multiple facts"
18 create_remote_file(agent1, '/tmp/test_facts.rb', fact_file )
19
20 step "Agent: Verify test_fact1 from /tmp/test_facts.rb"
21 on(agent1, "export FACTERLIB=/tmp && facter --puppet test_fact1") do
22 fail_test "Fact 1 not returned by facter --puppet test_fact1" unless
23 stdout.include? 'test fact 1'
24 end
25
26 step "Agent: Verify test_fact2 from /tmp/test_facts.rb"
27 on(agent1, "export FACTERLIB=/tmp && facter --puppet test_fact2") do
28 fail_test "Fact 1 not returned by facter --puppet test_fact2" unless
29 stdout.include? 'test fact 2'
30 end
11
22 Summary: Ruby module for collecting simple facts about a host operating system
33 Name: facter
4 Version: 1.6.9
4 Version: 1.6.10
55 Release: 1%{?dist}
6 #Release: 0.1rc1%{?dist}
6 #Release: 0.1rc1.2%{?dist}
7 Epoch: 1
78 License: Apache 2.0
89 Group: System Environment/Base
910 URL: http://www.puppetlabs.com/puppet/related-projects/%{name}
5253
5354
5455 %changelog
56 * Wed Jun 13 2012 Moses Mendoza <moses@puppetlabs.com> - 1.6.10-1
57 - Update for 1.6.10
58
59 * Fri Jun 8 2012 Moses Mendoza <moses@puppetlabs.com> - 1.6.10-0.1rc1.2
60 - Bump epoch to 1 to address errant Facter 2.0 rc release
61
62 * Wed Jun 6 2012 Moses Mendoza <moses@puppetlabs.com> - 1.6.10-0.1rc1
63 - Update for 1.6.10rc1
64
5565 * Thu May 17 2012 Moses Mendoza <moses@puppetlabs.com> - 1.6.9-1
5666 - Update for 1.6.9
5767
0 ---
1 inMenu: true
2 directoryName: Custom Facts
3 ---
4
5 Facter does everything it can to make adding custom facts easy. It will
6 autoload any files it finds in a ``facter/`` directory in its search
7 path, so you don't need to modify the package files. Also, Facter will
8 search through your environment for any variables whose names start with
9 'FACTER_' (case insensitive) and automatically add those facts.
10
11 As a simple example, here is how I publish my home directory to Puppet:
12
13 Facter.add("home") do
14 setcode do
15 ENV['HOME']
16 end
17 end
18
19 I have ~/lib/ruby in my $RUBYLIB environment variable, so I just created
20 ~/lib/ruby/facter and dropped the above code into a ``home.rb`` file
21 within that directory.
0 ---
1 inMenu: false
2 directoryName: Facter
3 ---
4
5 A cross-platform Ruby library for retrieving facts from operating systems.
6 Supports multiple resolution mechanisms, any of which can be restricted to
7 working only on certain operating systems or environments. Facter is especially
8 useful for retrieving things like operating system names, IP addresses, MAC
9 addresses, and SSH keys.
10
11 It is easy to extend Facter to include your own [custom facts](custom.html) or
12 to include additional mechanisms for retrieving facts.
13
14 * [Downloads](/downloads/facter/)
15 * [Bug Tracking](/cgi-bin/facter.cgi)
16 * [API Documentation](/downloads/facter/apidocs/)
17
18 *$Id$*
0
1 #!/usr/bin/env sh
2 #
3 # Output the difference between a facter command run on two different versions
4 # of facter. Uses unified diff format.
5
6 OPTIONS_SPEC="\
7 facter-diff [options] <rev1> <rev2> [fact]...
8
9 Example:
10
11 ./ext/facter-diff 1.5.7 1.0.2
12
13 --
14 h,help Display this help"
15
16 . "$(git --exec-path)/git-sh-setup"
17 eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
18 trap 'err=$?; cleanup; exit $err' 0
19
20 cleanup() {
21 test $origin && git checkout -q "$origin"
22 }
23
24 facter() {
25 ruby -Ilib bin/facter "$@"
26 }
27
28 log_facter_run() {
29 local ref=$1 && shift
30 local tmpfile=$1 && shift
31
32 git checkout -qf "$ref" ||
33 die "fatal: unable to checkout $ref"
34 facter "$@" > $tmpfile
35 }
36
37 verify_revision() {
38 git rev-parse --verify --quiet "$1" > /dev/null ||
39 die "fatal: '$1' is not a valid revision"
40 }
41
42 test $1 = "--" && shift # git rev-parse seems to leave the -- in
43 test $# -eq 0 && usage
44
45 test $# -gt 1 ||
46 die "fatal: must specify two revisions"
47
48 status=$(git status -s)
49 test -z "$status" ||
50 die "fatal: $0 cannot be used with a dirty working copy"
51
52 origin=$(git rev-parse --symbolic-full-name HEAD)
53 test "$origin" = "HEAD" &&
54 origin=$(git rev-parse HEAD)
55
56 test -x "bin/facter" ||
57 die "fatal: $0 must be run from the project root"
58
59 ref1="$1" && shift
60 ref2="$1" && shift
61
62 verify_revision $ref1
63 verify_revision $ref2
64
65 tmpfile1="/tmp/$(basename $0).$$.1.tmp"
66 tmpfile2="/tmp/$(basename $0).$$.2.tmp"
67
68 log_facter_run $ref1 $tmpfile1 $@
69 log_facter_run $ref2 $tmpfile2 $@
70
71 git checkout -f "$origin" > /dev/null 2>&1
72
73 diff --label "$ref1" --label "$ref2" -u $tmpfile1 $tmpfile2
2424 end
2525 when /(i[3456]86|pentium)/
2626 case Facter.value(:operatingsystem)
27 when "Gentoo"
27 when "Gentoo", "windows"
2828 "x86"
2929 else
3030 "i386"
5151 Facter.add(:domain) do
5252 confine :kernel => :windows
5353 setcode do
54 require 'facter/util/wmi'
54 require 'facter/util/registry'
5555 domain = ""
56 Facter::Util::WMI.execquery("select DNSDomain from Win32_NetworkAdapterConfiguration where IPEnabled = True").each { |nic|
57 domain = nic.DNSDomain
58 break
59 }
56 regvalue = Facter::Util::Registry.hklm_read('SYSTEM\CurrentControlSet\Services\Tcpip\Parameters', 'Domain')
57 domain = regvalue if regvalue
58 if domain == ""
59 require 'facter/util/wmi'
60 Facter::Util::WMI.execquery("select DNSDomain from Win32_NetworkAdapterConfiguration where IPEnabled = True").each { |nic|
61 domain = nic.DNSDomain
62 break
63 }
64 end
6065 domain
6166 end
6267 end
2727 Facter.add(:hardwaremodel) do
2828 confine :operatingsystem => :windows
2929 setcode do
30 require 'rbconfig'
31 RbConfig::CONFIG['host_cpu']
30 # The cryptic windows cpu architecture models are documented in these places:
31 # http://source.winehq.org/source/include/winnt.h#L568
32 # http://msdn.microsoft.com/en-us/library/windows/desktop/aa394373(v=vs.85).aspx
33 # http://msdn.microsoft.com/en-us/library/windows/desktop/windows.system.processorarchitecture.aspx
34 # Also, arm and neutral are included because they are valid for the upcoming
35 # windows 8 release. --jeffweiss 23 May 2012
36 require 'facter/util/wmi'
37 model = ""
38 Facter::Util::WMI.execquery("select Architecture, Level from Win32_Processor").each do |cpu|
39 model =
40 case cpu.Architecture
41 when 11 then 'neutral' # PROCESSOR_ARCHITECTURE_NEUTRAL
42 when 10 then 'i686' # PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
43 when 9 then 'x64' # PROCESSOR_ARCHITECTURE_AMD64
44 when 8 then 'msil' # PROCESSOR_ARCHITECTURE_MSIL
45 when 7 then 'alpha64' # PROCESSOR_ARCHITECTURE_ALPHA64
46 when 6 then 'ia64' # PROCESSOR_ARCHITECTURE_IA64
47 when 5 then 'arm' # PROCESSOR_ARCHITECTURE_ARM
48 when 4 then 'shx' # PROCESSOR_ARCHITECTURE_SHX
49 when 3 then 'powerpc' # PROCESSOR_ARCHITECTURE_PPC
50 when 2 then 'alpha' # PROCESSOR_ARCHITECTURE_ALPHA
51 when 1 then 'mips' # PROCESSOR_ARCHITECTURE_MIPS
52 when 0 then "i#{cpu.Level}86" # PROCESSOR_ARCHITECTURE_INTEL
53 else 'unknown' # PROCESSOR_ARCHITECTURE_UNKNOWN
54 end
55 break
56 end
57
58 model
3259 end
3360 end
6464 Facter.add(:ipaddress6) do
6565 confine :kernel => :windows
6666 setcode do
67 output = Facter::Util::Resolution.exec("#{ENV['SYSTEMROOT']}/system32/netsh interface ipv6 show address level=verbose")
67 output = Facter::Util::Resolution.exec("#{ENV['SYSTEMROOT']}/system32/netsh.exe interface ipv6 show address level=verbose")
6868
6969 get_address_after_token(output, 'Address', true)
7070 end
1212 Facter.add(:lsbdistcodename) do
1313 confine :kernel => [ :linux, :"gnu/kfreebsd" ]
1414 setcode do
15 Facter::Util::Resolution.exec('lsb_release -c -s')
15 Facter::Util::Resolution.exec('lsb_release -c -s 2>/dev/null')
1616 end
1717 end
1212 Facter.add(:lsbdistdescription) do
1313 confine :kernel => [ :linux, :"gnu/kfreebsd" ]
1414 setcode do
15 if output = Facter::Util::Resolution.exec('lsb_release -d -s')
15 if output = Facter::Util::Resolution.exec('lsb_release -d -s 2>/dev/null')
1616 # the output may be quoted (at least it is on gentoo)
1717 output.sub(/^"(.*)"$/,'\1')
1818 end
1212 Facter.add(:lsbdistid) do
1313 confine :kernel => [ :linux, :"gnu/kfreebsd" ]
1414 setcode do
15 Facter::Util::Resolution.exec('lsb_release -i -s')
15 Facter::Util::Resolution.exec('lsb_release -i -s 2>/dev/null')
1616 end
1717 end
1212 Facter.add(:lsbdistrelease) do
1313 confine :kernel => [ :linux, :"gnu/kfreebsd" ]
1414 setcode do
15 Facter::Util::Resolution.exec('lsb_release -r -s')
15 Facter::Util::Resolution.exec('lsb_release -r -s 2>/dev/null')
1616 end
1717 end
1212 Facter.add(:lsbrelease) do
1313 confine :kernel => [ :linux, :"gnu/kfreebsd" ]
1414 setcode do
15 Facter::Util::Resolution.exec('lsb_release -v -s')
15 Facter::Util::Resolution.exec('lsb_release -v -s 2>/dev/null')
1616 end
1717 end
7979 when 'HP-UX'
8080 output = %x{/bin/netstat -in | sed -e 1d}
8181 when 'windows'
82 output = %x|#{ENV['SYSTEMROOT']}/system32/netsh interface ip show interface|
83 output += %x|#{ENV['SYSTEMROOT']}/system32/netsh interface ipv6 show interface|
82 output = %x|#{ENV['SYSTEMROOT']}/system32/netsh.exe interface ip show interface|
83 output += %x|#{ENV['SYSTEMROOT']}/system32/netsh.exe interface ipv6 show interface|
8484 end
8585 output
8686 end
106106 return get_single_interface_output(interface) unless Facter.value(:kernel) == 'windows'
107107
108108 if label == 'ipaddress6'
109 output = %x|#{ENV['SYSTEMROOT']}/system32/netsh interface ipv6 show address \"#{interface}\"|
109 output = %x|#{ENV['SYSTEMROOT']}/system32/netsh.exe interface ipv6 show address \"#{interface}\"|
110110 else
111 output = %x|#{ENV['SYSTEMROOT']}/system32/netsh interface ip show address \"#{interface}\"|
111 output = %x|#{ENV['SYSTEMROOT']}/system32/netsh.exe interface ip show address \"#{interface}\"|
112112 end
113113 output
114114 end
0 module Facter::Util::Registry
1 class << self
2 def hklm_read(key, value)
3 require 'win32/registry'
4 reg = Win32::Registry::HKEY_LOCAL_MACHINE.open(key)
5 rval = reg[value]
6 reg.close
7 rval
8 end
9 end
10 end
1212
1313 INTERPRETER = Facter::Util::Config.is_windows? ? "cmd.exe" : "/bin/sh"
1414
15 def self.have_which
16 if ! defined?(@have_which) or @have_which.nil?
17 if Facter::Util::Config.is_windows?
18 @have_which = false
19 else
20 %x{which which >/dev/null 2>&1}
21 @have_which = $?.success?
22 end
23 end
24 @have_which
25 end
15 # Returns the locations to be searched when looking for a binary. This
16 # is currently determined by the +PATH+ environment variable plus
17 # <tt>/sbin</tt> and <tt>/usr/sbin</tt> when run on unix
18 def self.search_paths
19 if Facter::Util::Config.is_windows?
20 ENV['PATH'].split(File::PATH_SEPARATOR)
21 else
22 # Make sure facter is usable even for non-root users. Most commands
23 # in /sbin (like ifconfig) can be run as non priviledged users as
24 # long as they do not modify anything - which we do not do with facter
25 ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/sbin', '/usr/sbin' ]
26 end
27 end
28
29 # Determine the full path to a binary. If the supplied filename does not
30 # already describe an absolute path then different locations (determined
31 # by <tt>self.search_paths</tt>) will be searched for a match.
32 #
33 # Returns nil if no matching executable can be found otherwise returns
34 # the expanded pathname.
35 def self.which(bin)
36 if absolute_path?(bin)
37 return bin if File.executable?(bin)
38 if Facter::Util::Config.is_windows? and File.extname(bin).empty?
39 exts = ENV['PATHEXT']
40 exts = exts ? exts.split(File::PATH_SEPARATOR) : %w[.COM .EXE .BAT .CMD]
41 exts.each do |ext|
42 destext = bin + ext
43 if File.executable?(destext)
44 Facter.warnonce("Using Facter::Util::Resolution.which with an absolute path like #{bin} but no fileextension is deprecated. Please add the correct extension (#{ext})")
45 return destext
46 end
47 end
48 end
49 else
50 search_paths.each do |dir|
51 dest = File.join(dir, bin)
52 if Facter::Util::Config.is_windows?
53 dest.gsub!(File::SEPARATOR, File::ALT_SEPARATOR)
54 if File.extname(dest).empty?
55 exts = ENV['PATHEXT']
56 exts = exts ? exts.split(File::PATH_SEPARATOR) : %w[.COM .EXE .BAT .CMD]
57 exts.each do |ext|
58 destext = dest + ext
59 return destext if File.executable?(destext)
60 end
61 end
62 end
63 return dest if File.executable?(dest)
64 end
65 end
66 nil
67 end
68
69 # Determine in a platform-specific way whether a path is absolute. This
70 # defaults to the local platform if none is specified.
71 def self.absolute_path?(path, platform=nil)
72 # Escape once for the string literal, and once for the regex.
73 slash = '[\\\\/]'
74 name = '[^\\\\/]+'
75 regexes = {
76 :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
77 :posix => %r!^/!,
78 }
79 platform ||= Facter::Util::Config.is_windows? ? :windows : :posix
80
81 !! (path =~ regexes[platform])
82 end
83
84 # Expand the executable of a commandline to an absolute path. The executable
85 # is the first word of the commandline. If the executable contains spaces,
86 # it has be but in double quotes to be properly recognized.
87 #
88 # Returns the commandline with the expanded binary or nil if the binary
89 # can't be found. If the path to the binary contains quotes, the whole binary
90 # is put in quotes.
91 def self.expand_command(command)
92 if match = /^"(.+?)"(?:\s+(.*))?/.match(command)
93 exe, arguments = match.captures
94 exe = which(exe) and [ "\"#{exe}\"", arguments ].compact.join(" ")
95 elsif match = /^'(.+?)'(?:\s+(.*))?/.match(command) and not Facter::Util::Config.is_windows?
96 exe, arguments = match.captures
97 exe = which(exe) and [ "'#{exe}'", arguments ].compact.join(" ")
98 else
99 exe, arguments = command.split(/ /,2)
100 if exe = which(exe)
101 # the binary was not quoted which means it contains no spaces. But the
102 # full path to the binary may do so.
103 exe = "\"#{exe}\"" if exe =~ /\s/ and Facter::Util::Config.is_windows?
104 exe = "'#{exe}'" if exe =~ /\s/ and not Facter::Util::Config.is_windows?
105 [ exe, arguments ].compact.join(" ")
106 end
107 end
108 end
109
26110
27111 # Execute a program and return the output of that program.
28112 #
32116 def self.exec(code, interpreter = nil)
33117 Facter.warnonce "The interpreter parameter to 'exec' is deprecated and will be removed in a future version." if interpreter
34118
35 # Try to guess whether the specified code can be executed by looking at the
36 # first word. If it cannot be found on the PATH defer on resolving the fact
37 # by returning nil.
38 # This only fails on shell built-ins, most of which are masked by stuff in
39 # /bin or of dubious value anyways. In the worst case, "sh -c 'builtin'" can
40 # be used to work around this limitation
41 #
42 # Windows' %x{} throws Errno::ENOENT when the command is not found, so we
43 # can skip the check there. This is good, since builtins cannot be found
44 # elsewhere.
45 if have_which and !Facter::Util::Config.is_windows?
46 path = nil
47 binary = code.split.first
48 if code =~ /^\//
49 path = binary
50 else
51 path = %x{which #{binary} 2>/dev/null}.chomp
52 # we don't have the binary necessary
53 return nil if path == "" or path.match(/Command not found\./)
54 end
55
56 return nil unless FileTest.exists?(path)
119 if expanded_code = expand_command(code)
120 # if we can find the binary, we'll run the command with the expanded path to the binary
121 code = expanded_code
122 else
123 # if we cannot find the binary return nil on posix. On windows we'll still try to run the
124 # command in case it is a shell-builtin. In case it is not, windows will raise Errno::ENOENT
125 return nil unless Facter::Util::Config.is_windows?
126 return nil if absolute_path?(code)
57127 end
58128
59129 out = nil
60130
61131 begin
62132 out = %x{#{code}}.chomp
133 Facter.warnonce 'Using Facter::Util::Resolution.exec with a shell built-in is deprecated. Most built-ins can be replaced with native ruby commands. If you really have to run a built-in, pass "cmd /c your_builtin" as a command' unless expanded_code
63134 rescue Errno::ENOENT => detail
64135 # command not found on Windows
65136 return nil
2424 include Comparable
2525 include Enumerable
2626
27 FACTERVERSION = '1.6.9'
27 FACTERVERSION = '1.6.10'
2828 # = Facter
2929 # Functions as a hash of 'facts' you might care about about your
3030 # system, such as mac address, IP address, Video card, etc.
0 .TH "" "" ""
1 .SH NAME
2 \-
3 .\" Man page generated from reStructeredText.
4 .
5 .SH SYNOPSIS
6 .sp
7 Collect and display facts about the system.
8 .SH USAGE
9 .INDENT 0.0
10 .INDENT 3.5
11 .sp
12 facter [\-d|\-\-debug] [\-h|\-\-help] [\-p|\-\-puppet] [\-v|\-\-version] [\-y|\-\-yaml] [fact] [fact] [...]
13 .UNINDENT
14 .UNINDENT
15 .SH DESCRIPTION
16 .sp
17 Collect and display facts about the current system. The library behind
18 Facter is easy to expand, making Facter an easy way to collect
19 information about a system from within the shell or within Ruby.
20 .sp
21 If no facts are specifically asked for, then all facts will be returned.
22 .SH OPTIONS
23 .sp
24 debug: Enable debugging.
25 .sp
26 help: Print this help message
27 .INDENT 0.0
28 .TP
29 .B puppet: Load the Puppet libraries, thus allowing Facter to load
30 .
31 Puppet\-specific facts.
32 .UNINDENT
33 .sp
34 version: Print the version and exit.
35 .sp
36 yaml: Emit facts in YAML format.
37 .SH EXAMPLE
38 .INDENT 0.0
39 .INDENT 3.5
40 .sp
41 facter kernel
42 .UNINDENT
43 .UNINDENT
44 .SH AUTHOR
45 .sp
46 Luke Kanies
47 .SH COPYRIGHT
48 .sp
49 Copyright (c) 2006 Reductive Labs, LLC Licensed under the GNU Public
50 License
51 .\" Generated by docutils manpage writer.
52 .\"
53 .
0 # Support code for running stuff with warnings disabled.
1 module Kernel
2 def with_verbose_disabled
3 verbose, $VERBOSE = $VERBOSE, nil
4 result = yield
5 $VERBOSE = verbose
6 return result
7 end
8 end
1010 require 'puppetlabs_spec/files'
1111 require 'puppetlabs_spec/fixtures'
1212 require 'puppetlabs_spec/matchers'
13 require 'puppetlabs_spec/verbose'
1314
1415 RSpec.configure do |config|
1516 # Include PuppetlabsSpec helpers so they can be called at convenience
0 # Contexts for stubbing platforms
1 # In a describe or context block, adding :as_platform => :windows or
2 # :as_platform => :posix will stub the relevant facter config, as well as
3 # the behavior of Ruby's filesystem methods by changing File::ALT_SEPARATOR.
4 #
5 #
6 #
7 shared_context "windows", :as_platform => :windows do
8 before :each do
9 Facter.fact(:operatingsystem).stubs(:value).returns('Windows')
10 Facter::Util::Config.stubs(:is_windows?).returns true
11 end
12
13 around do |example|
14 file_alt_separator = File::ALT_SEPARATOR
15 file_path_separator = File::PATH_SEPARATOR
16 # prevent Ruby from warning about changing a constant
17 with_verbose_disabled do
18 File::ALT_SEPARATOR = '\\'
19 File::PATH_SEPARATOR = ';'
20 end
21 begin
22 example.run
23 ensure
24 with_verbose_disabled do
25 File::ALT_SEPARATOR = file_alt_separator
26 File::PATH_SEPARATOR = file_path_separator
27 end
28 end
29 end
30 end
31
32 shared_context "posix", :as_platform => :posix do
33 before :each do
34 Facter::Util::Config.stubs(:is_windows?).returns false
35 end
36
37 around do |example|
38 file_alt_separator = File::ALT_SEPARATOR
39 file_path_separator = File::PATH_SEPARATOR
40 # prevent Ruby from warning about changing a constant
41 with_verbose_disabled do
42 File::ALT_SEPARATOR = nil
43 File::PATH_SEPARATOR = ':'
44 end
45 begin
46 example.run
47 ensure
48 with_verbose_disabled do
49 File::ALT_SEPARATOR = file_alt_separator
50 File::PATH_SEPARATOR = file_path_separator
51 end
52 end
53 end
54 end
1010 require 'facter'
1111 require 'fileutils'
1212 require 'puppetlabs_spec_helper'
13 require 'pathname'
14
15 Pathname.glob("#{dir}/shared_contexts/*.rb") do |file|
16 require file.relative_path_from(Pathname.new(dir))
17 end
1318
1419 RSpec.configure do |config|
1520 config.mock_with :mocha
2020 ["Gentoo","i586"] => "x86",
2121 ["Gentoo","i686"] => "x86",
2222 ["Gentoo","pentium"] => "x86",
23 ["windows","i386"] => "x86",
24 ["windows","x64"] => "x64",
2325 }
2426 generic_archs = Hash.new
2527 generic_archs = {
9797 end
9898
9999 describe "on Windows" do
100 it "should use the DNSDomain for the first nic where ip is enabled" do
100 before(:each) do
101101 Facter.fact(:kernel).stubs(:value).returns("windows")
102 require 'facter/util/registry'
103 end
104 describe "with primary dns suffix" do
105 before(:each) do
106 Facter::Util::Registry.stubs(:hklm_read).returns('baz.com')
107 end
108 it "should get the primary dns suffix" do
109 Facter.fact(:domain).value.should == 'baz.com'
110 end
111 it "should not execute the wmi query" do
112 require 'facter/util/wmi'
113 Facter::Util::WMI.expects(:execquery).never
114 Facter.fact(:domain).value
115 end
116 end
117 describe "without primary dns suffix" do
118 before(:each) do
119 Facter::Util::Registry.stubs(:hklm_read).returns('')
120 end
121 it "should use the DNSDomain for the first nic where ip is enabled" do
122 nic = stubs 'nic'
123 nic.stubs(:DNSDomain).returns("foo.com")
102124
103 nic = stubs 'nic'
104 nic.stubs(:DNSDomain).returns("foo.com")
125 nic2 = stubs 'nic'
126 nic2.stubs(:DNSDomain).returns("bar.com")
105127
106 nic2 = stubs 'nic'
107 nic2.stubs(:DNSDomain).returns("bar.com")
128 require 'facter/util/wmi'
129 Facter::Util::WMI.stubs(:execquery).with("select DNSDomain from Win32_NetworkAdapterConfiguration where IPEnabled = True").returns([nic, nic2])
108130
109 require 'facter/util/wmi'
110 Facter::Util::WMI.stubs(:execquery).with("select DNSDomain from Win32_NetworkAdapterConfiguration where IPEnabled = True").returns([nic, nic2])
111
112 Facter.fact(:domain).value.should == 'foo.com'
131 Facter.fact(:domain).value.should == 'foo.com'
132 end
113133 end
114134 end
115135 end
7373
7474 describe "when provided code as a string" do
7575 it "should execute the code in the shell" do
76 test_command = Facter::Util::Config.is_windows? ? 'cmd.exe /c echo yup' : 'echo yup'
7677 Facter.add("shell_testing") do
77 setcode "echo yup"
78 setcode test_command
7879 end
7980
8081 Facter["shell_testing"].value.should == "yup"
0 #!/usr/bin/env ruby
1
2 require 'spec_helper'
3 require 'facter'
4
5 describe "Hardwaremodel fact" do
6 it "should match uname -m by default" do
7 Facter.fact(:kernel).stubs(:value).returns("Darwin")
8 Facter::Util::Resolution.stubs(:exec).with("uname -m").returns("Inky")
9
10 Facter.fact(:hardwaremodel).value.should == "Inky"
11 end
12
13 describe "on Windows" do
14 require 'facter/util/wmi'
15 before :each do
16 Facter.fact(:kernel).stubs(:value).returns("windows")
17 end
18
19 it "should detect i686" do
20 cpu = mock('cpu', :Architecture => 0, :Level => 6)
21 Facter::Util::WMI.expects(:execquery).returns([cpu])
22
23 Facter.fact(:hardwaremodel).value.should == "i686"
24 end
25
26 it "should detect x64" do
27 cpu = mock('cpu', :Architecture => 9)
28 Facter::Util::WMI.expects(:execquery).returns([cpu])
29
30 Facter.fact(:hardwaremodel).value.should == "x64"
31 end
32 end
33 end
4343 Facter::Util::Config.stubs(:is_windows?).returns(true)
4444
4545 fixture = netsh_fixture('windows_netsh_addresses_with_multiple_interfaces')
46 Facter::Util::Resolution.stubs(:exec).with('d:/windows/system32/netsh interface ipv6 show address level=verbose').
46 Facter::Util::Resolution.stubs(:exec).with('d:/windows/system32/netsh.exe interface ipv6 show address level=verbose').
4747 returns(fixture)
4848
4949 Facter.value(:ipaddress6).should == "2001:0:4137:9e76:2087:77a:53ef:7527"
99 Facter.fact(:kernel).stubs(:value).returns kernel
1010 end
1111
12 it "should return the codename through lsb_release -c -s" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -c -s').returns 'n/a'
12 it "should return the codename through lsb_release -c -s 2>/dev/null" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -c -s 2>/dev/null').returns 'n/a'
1414 Facter.fact(:lsbdistcodename).value.should == 'n/a'
1515 end
1616
1717 it "should return nil if lsb_release is not installed" do
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -c -s').returns nil
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -c -s 2>/dev/null').returns nil
1919 Facter.fact(:lsbdistcodename).value.should be_nil
2020 end
2121 end
99 Facter.fact(:kernel).stubs(:value).returns kernel
1010 end
1111
12 it "should return the description through lsb_release -d -s" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -d -s').returns '"Gentoo Base System release 2.1"'
12 it "should return the description through lsb_release -d -s 2>/dev/null" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -d -s 2>/dev/null').returns '"Gentoo Base System release 2.1"'
1414 Facter.fact(:lsbdistdescription).value.should == 'Gentoo Base System release 2.1'
1515 end
1616
1717 it "should return nil if lsb_release is not installed" do
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -d -s').returns nil
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -d -s 2>/dev/null').returns nil
1919 Facter.fact(:lsbdistdescription).value.should be_nil
2020 end
2121 end
99 Facter.fact(:kernel).stubs(:value).returns kernel
1010 end
1111
12 it "should return the id through lsb_release -i -s" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -i -s').returns 'Gentoo'
12 it "should return the id through lsb_release -i -s 2>/dev/null" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -i -s 2>/dev/null').returns 'Gentoo'
1414 Facter.fact(:lsbdistid).value.should == 'Gentoo'
1515 end
1616
17 it "should return nil if lsb_release is not installed" do
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -i -s').returns nil
17 it "should return nil if lsb_release is not installed 2>/dev/null" do
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -i -s 2>/dev/null').returns nil
1919 Facter.fact(:lsbdistid).value.should be_nil
2020 end
2121 end
99 Facter.fact(:kernel).stubs(:value).returns kernel
1010 end
1111
12 it "should return the release through lsb_release -r -s" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -r -s').returns '2.1'
12 it "should return the release through lsb_release -r -s 2>/dev/null" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -r -s 2>/dev/null').returns '2.1'
1414 Facter.fact(:lsbdistrelease).value.should == '2.1'
1515 end
1616
1717 it "should return nil if lsb_release is not installed" do
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -r -s').returns nil
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -r -s 2>/dev/null').returns nil
1919 Facter.fact(:lsbdistrelease).value.should be_nil
2020 end
2121 end
99 Facter.fact(:kernel).stubs(:value).returns kernel
1010 end
1111
12 it "should return the release through lsb_release -v -s" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -v -s').returns 'n/a'
12 it "should return the release through lsb_release -v -s 2>/dev/null" do
13 Facter::Util::Resolution.stubs(:exec).with('lsb_release -v -s 2>/dev/null').returns 'n/a'
1414 Facter.fact(:lsbrelease).value.should == 'n/a'
1515 end
1616
1717 it "should return nil if lsb_release is not installed" do
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -v -s').returns nil
18 Facter::Util::Resolution.stubs(:exec).with('lsb_release -v -s 2>/dev/null').returns nil
1919 Facter.fact(:lsbrelease).value.should be_nil
2020 end
2121 end
1515 def load(procs)
1616 require 'facter/util/wmi'
1717 Facter::Util::WMI.stubs(:execquery).with("select * from Win32_Processor").returns(procs)
18 # This is to workaround #14674
19 Facter.fact(:architecture).stubs(:value).returns("x64")
1820
1921 # processor facts belong to a file with a different name,
2022 # so load the file explicitly (after stubbing kernel),
0 #!/usr/bin/env rspec
1 require 'spec_helper'
2 require 'facter/operatingsystem'
3 require 'facter/util/registry'
4
5 describe Facter::Util::Registry do
6 describe "hklm_read", :if => Facter::Util::Config.is_windows? do
7 before(:all) do
8 require 'win32/registry'
9 end
10 describe "valid params" do
11 [ {:key => "valid_key", :value => "valid_value", :expected => "valid"},
12 {:key => "valid_key", :value => "", :expected => "valid"},
13 {:key => "valid_key", :value => nil, :expected => "invalid"},
14 {:key => "", :value => "valid_value", :expected => "valid"},
15 {:key => "", :value => "", :expected => "valid"},
16 {:key => "", :value => nil, :expected => "invalid"},
17 {:key => nil, :value => "valid_value", :expected => "invalid"},
18 {:key => nil, :value => "", :expected => "invalid"},
19 {:key => nil, :value => nil, :expected => "invalid"}
20 ].each do |scenario|
21 describe "with key #{scenario[:key] || "nil"} and value #{scenario[:value] || "nil"}" do
22 let :fake_registry_key do
23 fake = {}
24 fake[scenario[:value]] = scenario[:expected]
25 fake
26 end
27 it "should return #{scenario[:expected]} value" do
28 Win32::Registry::HKEY_LOCAL_MACHINE.stubs(:open).with(scenario[:key]).returns(fake_registry_key)
29 fake_registry_key.stubs(:close)
30
31 Facter::Util::Registry.hklm_read(scenario[:key], scenario[:value]).should == scenario[:expected]
32 end
33 end
34 end
35 end
36
37 describe "invalid params" do
38 [ {:key => "valid_key", :value => "invalid_value"},
39 {:key => "valid_key", :value => ""},
40 {:key => "valid_key", :value => nil},
41 ].each do |scenario|
42 describe "with valid key and value #{scenario[:value] || "nil"}" do
43 let :fake_registry_key do
44 {}
45 end
46 it "should raise an error" do
47 Win32::Registry::HKEY_LOCAL_MACHINE.stubs(:open).with(scenario[:key]).returns(fake_registry_key)
48 fake_registry_key.stubs(:close)
49
50 Facter::Util::Registry.hklm_read(scenario[:key], scenario[:value]).should raise_error
51 end
52 end
53 end
54 [ {:key => "invalid_key", :value => "valid_value"},
55 {:key => "invalid_key", :value => ""},
56 {:key => "invalid_key", :value => nil},
57 {:key => "", :value => "valid_value"},
58 {:key => "", :value => ""},
59 {:key => "", :value => nil},
60 {:key => nil, :value => "valid_value"},
61 {:key => nil, :value => ""},
62 {:key => nil, :value => nil}
63 ].each do |scenario|
64 describe "with invalid key #{scenario[:key] || "nil"} and value #{scenario[:value] || "nil"}" do
65 it "should raise an error" do
66 Win32::Registry::HKEY_LOCAL_MACHINE.stubs(:open).with(scenario[:key]).raises(Win32::Registry::Error, 2)
67 expect do
68 Facter::Util::Registry.hklm_read(scenario[:key], scenario[:value])
69 end.to raise_error Win32::Registry::Error
70 end
71 end
72 end
73 end
74 end
75 end
283283 Facter::Util::Resolution.should respond_to(:exec)
284284 end
285285
286 # taken from puppet: spec/unit/util_spec.rb
287 describe "#absolute_path?" do
288 context "when run on unix", :as_platform => :posix do
289 %w[/ /foo /foo/../bar //foo //Server/Foo/Bar //?/C:/foo/bar /\Server/Foo /foo//bar/baz].each do |path|
290 it "should return true for #{path}" do
291 Facter::Util::Resolution.should be_absolute_path(path)
292 end
293 end
294
295 %w[. ./foo \foo C:/foo \\Server\Foo\Bar \\?\C:\foo\bar \/?/foo\bar \/Server/foo foo//bar/baz].each do |path|
296 it "should return false for #{path}" do
297 Facter::Util::Resolution.should_not be_absolute_path(path)
298 end
299 end
300 end
301
302 context "when run on windows", :as_platform => :windows do
303 %w[C:/foo C:\foo \\\\Server\Foo\Bar \\\\?\C:\foo\bar //Server/Foo/Bar //?/C:/foo/bar /\?\C:/foo\bar \/Server\Foo/Bar c:/foo//bar//baz].each do |path|
304 it "should return true for #{path}" do
305 Facter::Util::Resolution.should be_absolute_path(path)
306 end
307 end
308
309 %w[/ . ./foo \foo /foo /foo/../bar //foo C:foo/bar foo//bar/baz].each do |path|
310 it "should return false for #{path}" do
311 Facter::Util::Resolution.should_not be_absolute_path(path)
312 end
313 end
314 end
315 end
316
317 describe "#search_paths" do
318 context "on windows", :as_platform => :windows do
319 it "should use the PATH environment variable to determine locations" do
320 ENV.expects(:[]).with('PATH').returns 'C:\Windows;C:\Windows\System32'
321 Facter::Util::Resolution.search_paths.should == %w{C:\Windows C:\Windows\System32}
322 end
323 end
324
325 context "on posix", :as_platform => :posix do
326 it "should use the PATH environment variable plus /sbin and /usr/sbin on unix" do
327 ENV.expects(:[]).with('PATH').returns "/bin:/usr/bin"
328 Facter::Util::Resolution.search_paths.should == %w{/bin /usr/bin /sbin /usr/sbin}
329 end
330 end
331 end
332
333 describe "#which" do
334 context "when run on posix", :as_platform => :posix do
335 before :each do
336 Facter::Util::Resolution.stubs(:search_paths).returns [ '/bin', '/sbin', '/usr/sbin']
337 end
338
339 context "and provided with an absolute path" do
340 it "should return the binary if executable" do
341 File.expects(:executable?).with('/opt/foo').returns true
342 Facter::Util::Resolution.which('/opt/foo').should == '/opt/foo'
343 end
344
345 it "should return nil if the binary is not executable" do
346 File.expects(:executable?).with('/opt/foo').returns false
347 Facter::Util::Resolution.which('/opt/foo').should be_nil
348 end
349 end
350
351 context "and not provided with an absolute path" do
352 it "should return the absolute path if found" do
353 File.expects(:executable?).with('/bin/foo').returns false
354 File.expects(:executable?).with('/sbin/foo').returns true
355 File.expects(:executable?).with('/usr/sbin/foo').never
356 Facter::Util::Resolution.which('foo').should == '/sbin/foo'
357 end
358
359 it "should return nil if not found" do
360 File.expects(:executable?).with('/bin/foo').returns false
361 File.expects(:executable?).with('/sbin/foo').returns false
362 File.expects(:executable?).with('/usr/sbin/foo').returns false
363 Facter::Util::Resolution.which('foo').should be_nil
364 end
365 end
366 end
367
368 context "when run on windows", :as_platform => :windows do
369 before :each do
370 Facter::Util::Resolution.stubs(:search_paths).returns ['C:\Windows\system32', 'C:\Windows', 'C:\Windows\System32\Wbem' ]
371 ENV.stubs(:[]).with('PATHEXT').returns nil
372 end
373
374 context "and provided with an absolute path" do
375 it "should return the binary if executable" do
376 File.expects(:executable?).with('C:\Tools\foo.exe').returns true
377 File.expects(:executable?).with('\\\\remote\dir\foo.exe').returns true
378 Facter::Util::Resolution.which('C:\Tools\foo.exe').should == 'C:\Tools\foo.exe'
379 Facter::Util::Resolution.which('\\\\remote\dir\foo.exe').should == '\\\\remote\dir\foo.exe'
380 end
381
382 it "should return the binary with added extension if executable" do
383 ['.COM', '.BAT', '.CMD', '' ].each do |ext|
384 File.stubs(:executable?).with('C:\Windows\system32\netsh'+ext).returns false
385 end
386 File.expects(:executable?).with('C:\Windows\system32\netsh.EXE').returns true
387
388 Facter.expects(:warnonce).with('Using Facter::Util::Resolution.which with an absolute path like C:\\Windows\\system32\\netsh but no fileextension is deprecated. Please add the correct extension (.EXE)')
389 Facter::Util::Resolution.which('C:\Windows\system32\netsh').should == 'C:\Windows\system32\netsh.EXE'
390 end
391
392 it "should return nil if the binary is not executable" do
393 File.expects(:executable?).with('C:\Tools\foo.exe').returns false
394 File.expects(:executable?).with('\\\\remote\dir\foo.exe').returns false
395 Facter::Util::Resolution.which('C:\Tools\foo.exe').should be_nil
396 Facter::Util::Resolution.which('\\\\remote\dir\foo.exe').should be_nil
397 end
398 end
399
400 context "and not provided with an absolute path" do
401 it "should return the absolute path if found" do
402 File.expects(:executable?).with('C:\Windows\system32\foo.exe').returns false
403 File.expects(:executable?).with('C:\Windows\foo.exe').returns true
404 File.expects(:executable?).with('C:\Windows\System32\Wbem\foo.exe').never
405 Facter::Util::Resolution.which('foo.exe').should == 'C:\Windows\foo.exe'
406 end
407
408 it "should return the absolute path with file extension if found" do
409 ['.COM', '.EXE', '.BAT', '.CMD', '' ].each do |ext|
410 File.stubs(:executable?).with('C:\Windows\system32\foo'+ext).returns false
411 File.stubs(:executable?).with('C:\Windows\System32\Wbem\foo'+ext).returns false
412 end
413 ['.COM', '.BAT', '.CMD', '' ].each do |ext|
414 File.stubs(:executable?).with('C:\Windows\foo'+ext).returns false
415 end
416 File.stubs(:executable?).with('C:\Windows\foo.EXE').returns true
417
418 Facter::Util::Resolution.which('foo').should == 'C:\Windows\foo.EXE'
419 end
420
421 it "should return nil if not found" do
422 File.expects(:executable?).with('C:\Windows\system32\foo.exe').returns false
423 File.expects(:executable?).with('C:\Windows\foo.exe').returns false
424 File.expects(:executable?).with('C:\Windows\System32\Wbem\foo.exe').returns false
425 Facter::Util::Resolution.which('foo.exe').should be_nil
426 end
427 end
428 end
429
430 describe "#expand_command" do
431 context "on windows", :as_platform => :windows do
432 it "should expand binary" do
433 Facter::Util::Resolution.expects(:which).with('cmd').returns 'C:\Windows\System32\cmd'
434 Facter::Util::Resolution.expand_command(
435 'cmd /c echo foo > C:\bar'
436 ).should == 'C:\Windows\System32\cmd /c echo foo > C:\bar'
437 end
438
439 it "should expand double quoted binary" do
440 Facter::Util::Resolution.expects(:which).with('my foo').returns 'C:\My Tools\my foo.exe'
441 Facter::Util::Resolution.expand_command('"my foo" /a /b').should == '"C:\My Tools\my foo.exe" /a /b'
442 end
443
444 it "should not expand single quoted binary" do
445 Facter::Util::Resolution.expects(:which).with('\'C:\My').returns nil
446 Facter::Util::Resolution.expand_command('\'C:\My Tools\foo.exe\' /a /b').should be_nil
447 end
448
449 it "should quote expanded binary if found in path with spaces" do
450 Facter::Util::Resolution.expects(:which).with('foo').returns 'C:\My Tools\foo.exe'
451 Facter::Util::Resolution.expand_command('foo /a /b').should == '"C:\My Tools\foo.exe" /a /b'
452 end
453
454 it "should return nil if not found" do
455 Facter::Util::Resolution.expects(:which).with('foo').returns nil
456 Facter::Util::Resolution.expand_command('foo /a | stuff >> /dev/null').should be_nil
457 end
458 end
459
460 context "on unix", :as_platform => :posix do
461 it "should expand binary" do
462 Facter::Util::Resolution.expects(:which).with('foo').returns '/bin/foo'
463 Facter::Util::Resolution.expand_command('foo -a | stuff >> /dev/null').should == '/bin/foo -a | stuff >> /dev/null'
464 end
465
466 it "should expand double quoted binary" do
467 Facter::Util::Resolution.expects(:which).with('/tmp/my foo').returns '/tmp/my foo'
468 Facter::Util::Resolution.expand_command(%q{"/tmp/my foo" bar}).should == %q{"/tmp/my foo" bar}
469 end
470
471 it "should expand single quoted binary" do
472 Facter::Util::Resolution.expects(:which).with('my foo').returns '/home/bob/my path/my foo'
473 Facter::Util::Resolution.expand_command(%q{'my foo' -a}).should == %q{'/home/bob/my path/my foo' -a}
474 end
475
476 it "should quote expanded binary if found in path with spaces" do
477 Facter::Util::Resolution.expects(:which).with('foo.sh').returns '/home/bob/my tools/foo.sh'
478 Facter::Util::Resolution.expand_command('foo.sh /a /b').should == %q{'/home/bob/my tools/foo.sh' /a /b}
479 end
480
481 it "should return nil if not found" do
482 Facter::Util::Resolution.expects(:which).with('foo').returns nil
483 Facter::Util::Resolution.expand_command('foo -a | stuff >> /dev/null').should be_nil
484 end
485 end
486 end
487
488 end
489
286490 # It's not possible, AFAICT, to mock %x{}, so I can't really test this bit.
287491 describe "when executing code" do
288492 it "should deprecate the interpreter parameter" do
291495 end
292496
293497 it "should execute the binary" do
294 Facter::Util::Resolution.exec("echo foo").should == "foo"
295 end
296 end
297
298 describe "have_which" do
299 before :each do
300 Facter::Util::Resolution.instance_variable_set(:@have_which, nil)
301
302 # we do not execute anything in the following test cases itself
303 # but we rely on $? to be an instance of Process::Status. So
304 # just execute anything here to make sure that $? is not nil
305 %x{echo foo}
306 end
307
308 it "on windows should always return false" do
309 Facter::Util::Config.stubs(:is_windows?).returns(true)
310 Facter::Util::Resolution.expects(:`).
311 with('which which >/dev/null 2>&1').never
312 Facter::Util::Resolution.have_which.should == false
313 end
314
315 it "on other platforms than windows should return true if which exists" do
316 Facter::Util::Config.stubs(:is_windows?).returns(false)
317 Facter::Util::Resolution.expects(:`).
318 with('which which >/dev/null 2>&1').returns('')
319 Process::Status.any_instance.stubs(:success?).returns true
320 Facter::Util::Resolution.have_which.should == true
321 end
322
323 it "on other platforms than windows should return false if which returns non-zero exit code" do
324 Facter::Util::Config.stubs(:is_windows?).returns(false)
325 Facter::Util::Resolution.expects(:`).
326 with('which which >/dev/null 2>&1').returns('')
327 Process::Status.any_instance.stubs(:success?).returns false
328 Facter::Util::Resolution.have_which.should == false
498 test_command = Facter::Util::Config.is_windows? ? 'cmd.exe /c echo foo' : 'echo foo'
499 Facter::Util::Resolution.exec(test_command).should == "foo"
500 end
501
502 context "when run on unix", :as_platform => :posix do
503 context "binary is present" do
504 it "should run the command if path to binary is absolute" do
505 Facter::Util::Resolution.expects(:expand_command).with('/usr/bin/uname -m').returns('/usr/bin/uname -m')
506 Facter::Util::Resolution.expects(:`).with('/usr/bin/uname -m').returns 'x86_64'
507 Facter::Util::Resolution.exec('/usr/bin/uname -m').should == 'x86_64'
508 end
509
510 it "should run the expanded command if path to binary not absolute" do
511 Facter::Util::Resolution.expects(:expand_command).with('uname -m').returns('/usr/bin/uname -m')
512 Facter::Util::Resolution.expects(:`).with('/usr/bin/uname -m').returns 'x86_64'
513 Facter::Util::Resolution.exec('uname -m').should == 'x86_64'
514 end
515 end
516
517 context "binary is not present" do
518 it "should not run the command if path to binary is absolute" do
519 Facter::Util::Resolution.expects(:expand_command).with('/usr/bin/uname -m').returns nil
520 Facter::Util::Resolution.expects(:`).with('/usr/bin/uname -m').never
521 Facter::Util::Resolution.exec('/usr/bin/uname -m').should be_nil
522 end
523 it "should not run the command if path to binary is not absolute" do
524 Facter::Util::Resolution.expects(:expand_command).with('uname -m').returns nil
525 Facter::Util::Resolution.expects(:`).with('uname -m').never
526 Facter::Util::Resolution.exec('uname -m').should be_nil
527 end
528 end
529 end
530
531 context "when run on windows", :as_platform => :windows do
532 context "binary is present" do
533 it "should run the command if path to binary is absolute" do
534 Facter::Util::Resolution.expects(:expand_command).with(%q{C:\Windows\foo.exe /a /b}).returns(%q{C:\Windows\foo.exe /a /b})
535 Facter::Util::Resolution.expects(:`).with(%q{C:\Windows\foo.exe /a /b}).returns 'bar'
536 Facter::Util::Resolution.exec(%q{C:\Windows\foo.exe /a /b}).should == 'bar'
537 end
538
539 it "should run the expanded command if path to binary not absolute" do
540 Facter::Util::Resolution.expects(:expand_command).with(%q{foo.exe /a /b}).returns(%q{C:\Windows\foo.exe /a /b})
541 Facter::Util::Resolution.expects(:`).with(%q{C:\Windows\foo.exe /a /b}).returns 'bar'
542 Facter::Util::Resolution.exec(%q{foo.exe /a /b}).should == 'bar'
543 end
544 end
545
546 context "binary is not present" do
547 it "should not run the command if path to binary is absolute" do
548 Facter::Util::Resolution.expects(:expand_command).with(%q{C:\Windows\foo.exe /a /b}).returns nil
549 Facter::Util::Resolution.expects(:`).with(%q{C:\Windows\foo.exe /a /b}).never
550 Facter::Util::Resolution.exec(%q{C:\Windows\foo.exe /a /b}).should be_nil
551 end
552 it "should try to run the command and return output of a shell-builtin" do
553 Facter::Util::Resolution.expects(:expand_command).with(%q{echo foo}).returns nil
554 Facter::Util::Resolution.expects(:`).with(%q{echo foo}).returns 'foo'
555 Facter.expects(:warnonce).with('Using Facter::Util::Resolution.exec with a shell built-in is deprecated. Most built-ins can be replaced with native ruby commands. If you really have to run a built-in, pass "cmd /c your_builtin" as a command')
556 Facter::Util::Resolution.exec(%q{echo foo}).should == 'foo'
557 end
558 it "should try to run the command and return nil if not shell-builtin" do
559 Facter::Util::Resolution.expects(:expand_command).with(%q{echo foo}).returns nil
560 Facter::Util::Resolution.stubs(:`).with(%q{echo foo}).raises Errno::ENOENT, 'some_error_message'
561 Facter.expects(:warnonce).never
562 Facter::Util::Resolution.exec(%q{echo foo}).should be_nil
563 end
564 end
329565 end
330566 end
331567 end
0 # Title: Rake task to build Apple packages for Facter.
1 # Author: Gary Larizza
2 # Date: 12/5/2011
3 # Description: This task will create a DMG-encapsulated package that will
4 # install Facter on OS X systems. This happens by building
5 # a directory tree of files that will then be fed to the
6 # packagemaker binary (can be installed by installing the
7 # XCode Tools) which will create the .pkg file.
8 #
9 require 'fileutils'
10 require 'erb'
11 require 'find'
12 require 'pathname'
13
14 # Path to Binaries (Constants)
15 TAR = '/usr/bin/tar'
16 CP = '/bin/cp'
17 INSTALL = '/usr/bin/install'
18 DITTO = '/usr/bin/ditto'
19 PACKAGEMAKER = '/Developer/usr/bin/packagemaker'
20 SED = '/usr/bin/sed'
21
22 # Setup task to populate all the variables
23 task :setup do
24 @version = `git describe`.chomp
25 @title = "facter-#{@version}"
26 @reverse_domain = 'com.puppetlabs.facter'
27 @package_major_version = @version.split('.')[0]
28 @package_minor_version = @version.split('.')[1] +
29 @version.split('.')[2].split('-')[0].split('rc')[0]
30 @pm_restart = 'None'
31 @build_date = Time.new.strftime("%Y-%m-%dT%H:%M:%SZ")
32 end
33
34 # method: make_directory_tree
35 # description: This method sets up the directory structure that packagemaker
36 # needs to build a package. A prototype.plist file (holding
37 # package-specific options) is built from an ERB template located
38 # in the tasks/rake/templates directory.
39 def make_directory_tree
40 facter_tmp = '/tmp/facter'
41 @scratch = "#{facter_tmp}/#{@title}"
42 @working_tree = {
43 'scripts' => "#{@scratch}/scripts",
44 'resources' => "#{@scratch}/resources",
45 'working' => "#{@scratch}/root",
46 'payload' => "#{@scratch}/payload",
47 }
48 puts "Cleaning Tree: #{facter_tmp}"
49 FileUtils.rm_rf(facter_tmp)
50 @working_tree.each do |key,val|
51 puts "Creating: #{val}"
52 FileUtils.mkdir_p(val)
53 end
54 File.open("#{@scratch}/#{'prototype.plist'}", "w+") do |f|
55 f.write(ERB.new(File.read('tasks/rake/templates/prototype.plist.erb')).result())
56 end
57 end
58
59 # method: build_dmg
60 # description: This method builds a package from the directory structure in
61 # /tmp/facter and puts it in the
62 # /tmp/facter/facter-#{version}/payload directory. A DMG is
63 # created, using hdiutil, based on the contents of the
64 # /tmp/facter/facter-#{version}/payload directory. The resultant
65 # DMG is placed in the pkg/apple directory.
66 #
67 def build_dmg
68 # Local Variables
69 dmg_format_code = 'UDZO'
70 zlib_level = '9'
71 dmg_format_option = "-imagekey zlib-level=#{zlib_level}"
72 dmg_format = "#{dmg_format_code} #{dmg_format_option}"
73 dmg_file = "#{@title}.dmg"
74 package_file = "#{@title}.pkg"
75 pm_extra_args = '--verbose --no-recommend --no-relocate'
76 package_target_os = '10.4'
77
78 # Build .pkg file
79 system("sudo #{PACKAGEMAKER} --root #{@working_tree['working']} \
80 --id #{@reverse_domain} \
81 --filter DS_Store \
82 --target #{package_target_os} \
83 --title #{@title} \
84 --info #{@scratch}/prototype.plist \
85 --scripts #{@working_tree['scripts']} \
86 --resources #{@working_tree['resources']} \
87 --version #{@version} \
88 #{pm_extra_args} --out #{@working_tree['payload']}/#{package_file}")
89
90 # Build .dmg file
91 system("sudo hdiutil create -volname #{@title} \
92 -srcfolder #{@working_tree['payload']} \
93 -uid 99 \
94 -gid 99 \
95 -ov \
96 -format #{dmg_format} \
97 #{dmg_file}")
98
99 if File.directory?("#{Pathname.pwd}/pkg/apple")
100 FileUtils.mv("#{Pathname.pwd}/#{dmg_file}", "#{Pathname.pwd}/pkg/apple/#{dmg_file}")
101 puts "moved: #{dmg_file} has been moved to #{Pathname.pwd}/pkg/apple/#{dmg_file}"
102 else
103 FileUtils.mkdir_p("#{Pathname.pwd}/pkg/apple")
104 FileUtils.mv(dmg_file, "#{Pathname.pwd}/pkg/apple/#{dmg_file}")
105 puts "moved: #{dmg_file} has been moved to #{Pathname.pwd}/pkg/apple/#{dmg_file}"
106 end
107 end
108
109 # method: pack_facter_source
110 # description: This method copies the facter source into a directory
111 # structure in /tmp/facter/facter-#{version}/root mirroring the
112 # structure on the target system for which the package will be
113 # installed. Anything installed into /tmp/facter/root will be
114 # installed as the package's payload.
115 #
116 def pack_facter_source
117 work = "#{@working_tree['working']}"
118 facter_source = Pathname.pwd
119
120 # Make all necessary directories
121 directories = ["#{work}/usr/bin",
122 "#{work}/usr/share/doc/facter",
123 "#{work}/usr/lib/ruby/site_ruby/1.8/facter"]
124 FileUtils.mkdir_p(directories)
125
126 # Install necessary files
127 system("#{DITTO} #{facter_source}/bin/ #{work}/usr/bin")
128 system("#{DITTO} #{facter_source}/lib/ #{work}/usr/lib/ruby/site_ruby/1.8/")
129
130 # Setup a preflight script and replace variables in the files with
131 # the correct paths.
132 system("#{INSTALL} -o root -g wheel -m 644 #{facter_source}/conf/osx/preflight #{@working_tree['scripts']}")
133 system("#{SED} -i '' \"s\#{SITELIBDIR}\#/usr/lib/ruby/site_ruby/1.8\#g\" #{@working_tree['scripts']}/preflight")
134 system("#{SED} -i '' \"s\#{BINDIR}\#/usr/bin\#g\" #{@working_tree['scripts']}/preflight")
135
136 # Install documentation (matching for files with capital letters)
137 Dir.foreach("#{facter_source}") do |file|
138 system("#{INSTALL} -o root -g wheel -m 644 #{facter_source}/#{file} #{work}/usr/share/doc/facter") if file =~ /^[A-Z][A-Z]/
139 end
140
141 # Set Permissions
142 executable_directories = [ "#{work}/usr/bin", ]
143 FileUtils.chmod_R(0755, executable_directories)
144 FileUtils.chown_R('root', 'wheel', directories)
145 FileUtils.chmod_R(0644, "#{work}/usr/lib/ruby/site_ruby/1.8/")
146 FileUtils.chown_R('root', 'wheel', "#{work}/usr/lib/ruby/site_ruby/1.8/")
147 Find.find("#{work}/usr/lib/ruby/site_ruby/1.8/") do |dir|
148 FileUtils.chmod(0755, dir) if File.directory?(dir)
149 end
150 end
151
152 namespace :package do
153 desc "Task for building an Apple Package"
154 task :apple => [:setup] do
155 # Test for Root and Packagemaker binary
156 raise "Please run rake as root to build Apple Packages" unless Process.uid == 0
157 raise "Packagemaker must be installed. Please install XCode Tools" unless \
158 File.exists?('/Developer/usr/bin/packagemaker')
159
160 make_directory_tree
161 pack_facter_source
162 build_dmg
163 FileUtils.chmod_R(0775, "#{Pathname.pwd}/pkg")
164 end
165 end
0 desc "Create a ChangeLog based on git commits."
1 task :changelog do
2 begin
3 gitc = %x{which git-changelog}
4 rescue
5 puts "This task needs the git-changelog binary - http://github.com/ReinH/git-changelog"
6 end
7
8 CHANGELOG_DIR = "#{Dir.pwd}"
9 mkdir(CHANGELOG_DIR) unless File.directory?(CHANGELOG_DIR)
10 change_body = `git-changelog --limit=99999`
11 File.open(File.join(CHANGELOG_DIR, "CHANGELOG"), 'w') do |f|
12 f << change_body
13 end
14 end
0 desc "Prep CI RSpec tests"
1 task :ci_prep do
2 require 'rubygems'
3 begin
4 gem 'ci_reporter'
5 require 'ci/reporter/rake/rspec'
6 require 'ci/reporter/rake/test_unit'
7 ENV['CI_REPORTS'] = 'results'
8 rescue LoadError
9 puts 'Missing ci_reporter gem. You must have the ci_reporter gem installed to run the CI spec tests'
10 end
11 end
12
13 desc "Run the CI RSpec tests"
14 task :ci_spec => [:ci_prep, 'ci:setup:rspec', :spec] do
15 end
0 desc "Create a Facter daily build"
1 task :daily => :changelog do
2 version = "facter" + "-" + Time.now.localtime.strftime("%Y%m%d")
3 sh "git archive --format=tar --prefix=#{version}/ HEAD^{tree} >#{version}.tar"
4 sh "pax -waf #{version}.tar -s ':^:#{version}/:' ChangeLog"
5 sh "rm ChangeLog"
6 sh "gzip -f -9 #{version}.tar"
7 end
0 desc "Send patch information to the puppet-dev list"
1 task :mail_patches do
2 if Dir.glob("00*.patch").length > 0
3 raise "Patches already exist matching '00*.patch'; clean up first"
4 end
5
6 unless %x{git status} =~ /On branch (.+)/
7 raise "Could not get branch from 'git status'"
8 end
9 branch = $1
10
11 unless branch =~ %r{^([^\/]+)/([^\/]+)/([^\/]+)$}
12 raise "Branch name does not follow <type>/<parent>/<name> model; cannot autodetect parent branch"
13 end
14
15 type, parent, name = $1, $2, $3
16
17 # Create all of the patches
18 sh "git format-patch -C -M -s -n --subject-prefix='PATCH/facter' #{parent}..HEAD"
19
20 # Add info to the patches
21 additional_info = "Local-branch: #{branch}\n"
22 files = Dir.glob("00*.patch")
23 files.each do |file|
24 contents = File.read(file)
25 contents.sub!(/^---\n/, "---\n#{additional_info}")
26 File.open(file, 'w') do |file_handle|
27 file_handle.print contents
28 end
29 end
30
31 # And then mail them out.
32
33 # If we've got more than one patch, add --compose
34 if files.length > 1
35 compose = "--compose"
36 subject = %Q{--subject "#{type} #{name} against #{parent}"}
37 else
38 compose = ""
39 subject = ""
40 end
41
42 # Now send the mail.
43 sh "git send-email #{compose} #{subject} --no-signed-off-by-cc --suppress-from --to puppet-dev@googlegroups.com 00*.patch"
44
45 # Finally, clean up the patches
46 sh "rm 00*.patch"
47 end
0 begin
1 require 'metric_fu'
2 rescue LoadError
3 # Metric-fu not installed
4 # http://metric-fu.rubyforge.org/
5 end
0 desc "Sign the package with the Puppet Labs release key"
1 task :sign_packages do
2
3 version = Facter::FACTERVERSION
4
5 # Sign package
6
7 sh "gpg --homedir $HOME/pl_release_key --detach-sign --output pkg/facter-#{version}.tar.gz.sign --armor pkg/facter-#{version}.tar.gz"
8
9 # Sign gem
10
11 sh "gpg --homedir $HOME/pl_release_key --detach-sign --output pkg/facter-#{version}.gem.sign --armor pkg/facter-#{version}.gem"
12
13 end
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2 <plist version="1.0">
3 <dict>
4 <key>CFBundleIdentifier</key>
5 <string><%= @title %></string>
6 <key>CFBundleShortVersionString</key>
7 <string><%= @version %></string>
8 <key>IFMajorVersion</key>
9 <integer><%= @package_major_version %></integer>
10 <key>IFMinorVersion</key>
11 <integer><%= @package_minor_version %></integer>
12 <key>IFPkgBuildDate</key>
13 <date><%= @build_date %></date>
14 <key>IFPkgFlagAllowBackRev</key>
15 <false/>
16 <key>IFPkgFlagAuthorizationAction</key>
17 <string>RootAuthorization</string>
18 <key>IFPkgFlagDefaultLocation</key>
19 <string>/</string>
20 <key>IFPkgFlagFollowLinks</key>
21 <true/>
22 <key>IFPkgFlagInstallFat</key>
23 <false/>
24 <key>IFPkgFlagIsRequired</key>
25 <false/>
26 <key>IFPkgFlagOverwritePermissions</key>
27 <false/>
28 <key>IFPkgFlagRelocatable</key>
29 <false/>
30 <key>IFPkgFlagRestartAction</key>
31 <string><%= @pm_restart %></string>
32 <key>IFPkgFlagRootVolumeOnly</key>
33 <true/>
34 <key>IFPkgFlagUpdateInstalledLanguages</key>
35 <false/>
36 </dict>
37 </plist>