From 7210429e2adb35794fb334196a6141b71f519fbc Mon Sep 17 00:00:00 2001 From: Rein Henrichs Date: Tue, 17 Aug 2010 16:22:43 -0700 Subject: [#4558] Refactor facter binary using optparse Simplify the binary by moving all application specific code into a new Facter::Application module. This module is then refactored to use OptionParser and to simplify invocation logic, while maintaining existing behavior. --- bin/facter | 132 ++++------------------------------------------ lib/facter/application.rb | 99 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 123 deletions(-) create mode 100644 lib/facter/application.rb diff --git a/bin/facter b/bin/facter index a6cb717..e9dfc7c 100755 --- a/bin/facter +++ b/bin/facter @@ -18,11 +18,8 @@ # # = Options # -# debug:: -# Enable debugging. -# -# help:: -# Print this help message +# yaml:: +# Emit facts in YAML format. # # puppet:: # Load the Puppet libraries, thus allowing Facter to load Puppet-specific facts. @@ -30,8 +27,11 @@ # version:: # Print the version and exit. # -# yaml:: -# Emit facts in YAML format. +# help:: +# Print this help message. +# +# debug:: +# Enable debugging. # # = Example # @@ -46,120 +46,6 @@ # Copyright (c) 2006 Reductive Labs, LLC # Licensed under the GNU Public License -require 'getoptlong' -require 'facter' - -$haveusage = true - -begin - require 'rdoc/ri/ri_paths' - require 'rdoc/usage' -rescue Exception - $haveusage = false -end - -def load_puppet - require 'puppet' - Puppet.parse_config - - # If you've set 'vardir' but not 'libdir' in your - # puppet.conf, then the hook to add libdir to $: - # won't get triggered. This makes sure that it's setup - # correctly. - unless $LOAD_PATH.include?(Puppet[:libdir]) - $LOAD_PATH << Puppet[:libdir] - end -end - -$debug = 0 - -config = nil - -result = GetoptLong.new( - [ "--version", "-v", GetoptLong::NO_ARGUMENT ], - [ "--help", "-h", GetoptLong::NO_ARGUMENT ], - [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], - [ "--yaml", "-y", GetoptLong::NO_ARGUMENT ], - [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ], - [ "--puppet", "-p", GetoptLong::NO_ARGUMENT ] -) - -options = { - :yaml => false -} - -begin - result.each { |opt,arg| - case opt - when "--version" - puts "%s" % Facter.version - exit - when "--puppet" - begin - load_puppet() - rescue LoadError => detail - $stderr.puts "Could not load Puppet: %s" % detail - end - when "--yaml" - options[:yaml] = true - when "--debug" - Facter.debugging(1) - when "--help" - if $haveusage - RDoc::usage && exit - else - puts "No help available unless you have RDoc::usage installed" - exit - end - else - $stderr.puts "Invalid option '#{opt}'" - exit(12) - end - } -rescue - exit(12) -end - -names = [] - -unless config.nil? - File.open(config) { |file| - names = file.readlines.collect { |line| - line.chomp - } - } -end - -ARGV.each { |item| - names.push item -} - -facts = Facter.to_hash - -unless names.empty? - facts = {} - names.each { |name| - begin - facts[name] = Facter.value(name) - rescue => error - STDERR.puts "Could not retrieve %s: #{error}" % name - exit 10 - end - } -end - -if options[:yaml] - require 'yaml' - puts YAML.dump(facts) - exit(0) -end +require 'facter/application' -facts.sort { |a, b| a[0].to_s <=> b[0].to_s }.each { |name,value| - if facts.length == 1 - unless value.nil? - puts value - end - else - puts "%s => %s" % [name,value] - end -} +Facter::Application.run(ARGV) diff --git a/lib/facter/application.rb b/lib/facter/application.rb new file mode 100644 index 0000000..51dbd14 --- /dev/null +++ b/lib/facter/application.rb @@ -0,0 +1,99 @@ +module Facter + module Application + def self.run(argv) + require 'optparse' + require 'facter' + + options = parse(argv) + + # Accept fact names to return from the command line + names = argv + + # Create the facts hash that is printed to standard out + if names.empty? + facts = Facter.to_hash + else + facts = {} + names.each { |name| + begin + facts[name] = Facter.value(name) + rescue => error + $stderr.puts "Could not retrieve #{name}: #{error}" + exit 10 + end + } + end + + # Print the facts as YAML and exit + if options[:yaml] + require 'yaml' + puts YAML.dump(facts) + exit(0) + end + + # Print the value of a single fact, otherwise print a list sorted by fact + # name and separated by "=>" + if facts.length == 1 + if value = facts.values.first + puts value + end + else + facts.sort_by{ |fact| fact.first }.each do |name,value| + puts "#{name} => #{value}" + end + end + + rescue => e + $stderr.puts "Error: #{e}" + exit(12) + end + + private + + def self.parse(argv) + options = {} + OptionParser.new do |opts| + opts.on("-y", "--yaml") { |v| options[:yaml] = v } + + opts.on("-d", "--debug") { |v| Facter.debugging(1) } + opts.on("-p", "--puppet") { |v| load_puppet } + + opts.on_tail("-v", "--version") do + puts Facter.version + exit(0) + end + + opts.on_tail("-h", "--help") do + begin + require 'rdoc/ri/ri_paths' + require 'rdoc/usage' + puts RDoc.usage + ensure + exit + end + end + end.parse! + + options + rescue OptionParser::InvalidOption => e + $stderr.puts e.message + exit(12) + end + + def self.load_puppet + require 'puppet' + Puppet.parse_config + + # If you've set 'vardir' but not 'libdir' in your + # puppet.conf, then the hook to add libdir to $: + # won't get triggered. This makes sure that it's setup + # correctly. + unless $LOAD_PATH.include?(Puppet[:libdir]) + $LOAD_PATH << Puppet[:libdir] + end + rescue LoadError => detail + $stderr.puts "Could not load Puppet: #{detail}" + end + + end +end -- cgit From 8c4d0cd4d25534f0f585773b6b5ff70b8a5617f9 Mon Sep 17 00:00:00 2001 From: Rein Henrichs Date: Mon, 4 Oct 2010 12:18:02 -0700 Subject: (#4558) Fail with message on --help errors If rdoc/usage fails to load, tell the user why and fail. If another failure happens, report the error message and fail. Paired With: Jacob Helwig Signed-off-by: Rein Henrichs --- lib/facter/application.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/facter/application.rb b/lib/facter/application.rb index 51dbd14..36d070b 100644 --- a/lib/facter/application.rb +++ b/lib/facter/application.rb @@ -68,8 +68,13 @@ module Facter require 'rdoc/ri/ri_paths' require 'rdoc/usage' puts RDoc.usage - ensure exit + rescue LoadError + $stderr.puts "No help available unless your RDoc has RDoc.usage" + exit(1) + rescue => e + $stderr.puts "fatal: #{e}" + exit(1) end end end.parse! -- cgit From e6bfdf9bf7a0d929dc7d882d3ea3bcb7372b75e0 Mon Sep 17 00:00:00 2001 From: William Van Hevelingen Date: Wed, 18 Aug 2010 15:40:24 -0700 Subject: Fix for bug #4569 * getTickCount.call() is not an epoch time value so compute_uptime is not necessary Signed-off-by: William Van Hevelingen --- lib/facter/util/uptime.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/facter/util/uptime.rb b/lib/facter/util/uptime.rb index 353ebf5..b62d7e9 100644 --- a/lib/facter/util/uptime.rb +++ b/lib/facter/util/uptime.rb @@ -10,7 +10,7 @@ module Facter::Util::Uptime def self.get_uptime_seconds_win require 'Win32API' getTickCount = Win32API.new("kernel32", "GetTickCount", nil, 'L') - compute_uptime(Time.at(getTickCount.call() / 1000.0)) + (getTickCount.call() / 1000.0).to_i end private -- cgit From 11544c16e514353f5fde5361a55cf04feb91fc64 Mon Sep 17 00:00:00 2001 From: Rein Henrichs Date: Wed, 18 Aug 2010 15:50:39 -0700 Subject: [#4289] operatingsystemrelease fact for oel, ovs When Facter returns operatingsystem as "oel" or "ovs", the operatingsystemrelease fact does not catch these properly, causing an error. Specs added to catch failure and case statement updated to catch "oel" and "ovs" as well as "OEL" and "OVS" --- lib/facter/operatingsystemrelease.rb | 4 ++-- spec/unit/operatingsystemrelease.rb | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 spec/unit/operatingsystemrelease.rb diff --git a/lib/facter/operatingsystemrelease.rb b/lib/facter/operatingsystemrelease.rb index 30f2989..280208b 100644 --- a/lib/facter/operatingsystemrelease.rb +++ b/lib/facter/operatingsystemrelease.rb @@ -8,9 +8,9 @@ Facter.add(:operatingsystemrelease) do releasefile = "/etc/fedora-release" when "MeeGo" releasefile = "/etc/meego-release" - when "OEL" + when "OEL", "oel" releasefile = "/etc/enterprise-release" - when "OVS" + when "OVS", "ovs" releasefile = "/etc/ovs-release" end File::open(releasefile, "r") do |f| diff --git a/spec/unit/operatingsystemrelease.rb b/spec/unit/operatingsystemrelease.rb new file mode 100644 index 0000000..31d4ae8 --- /dev/null +++ b/spec/unit/operatingsystemrelease.rb @@ -0,0 +1,39 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../spec_helper' + +require 'facter' + +describe "Operating System Release fact" do + + before do + Facter.clear + end + + after do + Facter.clear + end + + test_cases = { + "CentOS" => "/etc/redhat-release", + "RedHat" => "/etc/redhat-release", + "Fedora" => "/etc/fedora-release", + "MeeGo" => "/etc/meego-release", + "OEL" => "/etc/enterprise-release", + "oel" => "/etc/enterprise-release", + "OVS" => "/etc/ovs-release", + "ovs" => "/etc/ovs-release" + } + + test_cases.each do |system, file| + context "with operatingsystem reported as #{system.inspect}" do + it "should read the #{file.inspect} file" do + Facter.fact(:operatingsystem).stubs(:value).returns(system) + + File.expects(:open).with(file, "r").at_least(1) + + Facter.fact(:operatingsystemrelease).value + end + end + end +end -- cgit From 244d2f13d0c911081d1e99365a1770f2022b839f Mon Sep 17 00:00:00 2001 From: William Van Hevelingen Date: Thu, 19 Aug 2010 01:41:13 -0700 Subject: Better fix for Bug 4569: Uptime Fact is incorrect on Windows Patch removes reliance on clock ticks and instead queries for last boot time and subtracts from Time.now Signed-off-by: William Van Hevelingen --- lib/facter/util/uptime.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/facter/util/uptime.rb b/lib/facter/util/uptime.rb index b62d7e9..6c60ace 100644 --- a/lib/facter/util/uptime.rb +++ b/lib/facter/util/uptime.rb @@ -8,9 +8,12 @@ module Facter::Util::Uptime end def self.get_uptime_seconds_win - require 'Win32API' - getTickCount = Win32API.new("kernel32", "GetTickCount", nil, 'L') - (getTickCount.call() / 1000.0).to_i + require 'win32ole' + wmi = WIN32OLE.connect("winmgmts://") + query = wmi.ExecQuery("select * from Win32_OperatingSystem") + last_boot = "" + query.each { |x| last_boot = x.LastBootupTime} + self.compute_uptime(Time.parse(last_boot.split('.').first)) end private -- cgit From 1f387a5970d942fc297da791b1422adc80fc474a Mon Sep 17 00:00:00 2001 From: Rein Henrichs Date: Mon, 23 Aug 2010 16:13:21 -0700 Subject: [#4552] Apply patch from Dean Wilson --- bin/facter | 15 +++++++++------ lib/facter.rb | 31 +++++++++++++++++++++++++++++++ lib/facter/application.rb | 2 +- lib/facter/util/resolution.rb | 9 +++++++++ spec/unit/facter.rb | 27 +++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 7 deletions(-) diff --git a/bin/facter b/bin/facter index e9dfc7c..4e09939 100755 --- a/bin/facter +++ b/bin/facter @@ -21,18 +21,21 @@ # yaml:: # Emit facts in YAML format. # +# debug:: +# Enable debugging. +# +# timing:: +# Enable timing. +# +# help:: +# Print this help message +# # puppet:: # Load the Puppet libraries, thus allowing Facter to load Puppet-specific facts. # # version:: # Print the version and exit. # -# help:: -# Print this help message. -# -# debug:: -# Enable debugging. -# # = Example # # facter kernel diff --git a/lib/facter.rb b/lib/facter.rb index 42d5371..661831f 100644 --- a/lib/facter.rb +++ b/lib/facter.rb @@ -48,6 +48,7 @@ module Facter GREEN = "" RESET = "" @@debug = 0 + @@timing = 0 # module methods @@ -77,6 +78,20 @@ module Facter @@debug != 0 end + # show the timing information + def self.show_time(string) + if string.nil? + return + end + if self.timing? + puts GREEN + string + RESET + end + end + + def self.timing? + @@timing != 0 + end + # Return a fact object by name. If you use this, you still have to call # 'value' on it to retrieve the actual value. def self.[](name) @@ -177,6 +192,22 @@ module Facter end end + # Set timing on or off. + def self.timing(bit) + if bit + case bit + when TrueClass; @@timing = 1 + when Fixnum + if bit > 0 + @@timing = 1 + else + @@timing = 0 + end + end + else + @@timing = 0 + end + end def self.warn(msg) if Facter.debugging? and msg and not msg.empty? diff --git a/lib/facter/application.rb b/lib/facter/application.rb index 36d070b..c222e7a 100644 --- a/lib/facter/application.rb +++ b/lib/facter/application.rb @@ -54,8 +54,8 @@ module Facter options = {} OptionParser.new do |opts| opts.on("-y", "--yaml") { |v| options[:yaml] = v } - opts.on("-d", "--debug") { |v| Facter.debugging(1) } + opts.on("-t", "--timing") { |v| Facter.timing(1) } opts.on("-p", "--puppet") { |v| load_puppet } opts.on_tail("-v", "--version") do diff --git a/lib/facter/util/resolution.rb b/lib/facter/util/resolution.rb index f837f64..875b654 100644 --- a/lib/facter/util/resolution.rb +++ b/lib/facter/util/resolution.rb @@ -135,6 +135,9 @@ class Facter::Util::Resolution def value result = nil return result if @code == nil and @interpreter == nil + + starttime = Time.now.to_i + begin Timeout.timeout(limit) do if @code.is_a?(Proc) @@ -156,6 +159,12 @@ class Facter::Util::Resolution return nil end + finishtime = Time.now.to_i + + if Facter.timing? + Facter.show_time "Executing #{self.name} took #{finishtime - starttime} seconds" + end + return nil if result == "" return result end diff --git a/spec/unit/facter.rb b/spec/unit/facter.rb index 9f7b4cf..20f9ed1 100755 --- a/spec/unit/facter.rb +++ b/spec/unit/facter.rb @@ -135,6 +135,14 @@ describe Facter do Facter.should respond_to(:debugging?) end + it "should have a method to query timing mode" do + Facter.should respond_to(:timing?) + end + + it "should have a method to show timing information" do + Facter.should respond_to(:show_time) + end + it "should have a method to warn" do Facter.should respond_to(:warn) end @@ -204,6 +212,25 @@ describe Facter do end end + describe "when setting timing mode" do + it "should have timing enabled using 1" do + Facter.timing(1) + Facter.should be_timing + end + it "should have timing enabled using true" do + Facter.timing(true) + Facter.should be_timing + end + it "should have timing disabled using 0" do + Facter.timing(0) + Facter.should_not be_timing + end + it "should have timing disabled using false" do + Facter.timing(false) + Facter.should_not be_timing + end + end + describe "when registering directories to search" do after { Facter.instance_variable_set("@search_path", []) } -- cgit From 07f186d5a858412c0608c368806825e1e44efd4c Mon Sep 17 00:00:00 2001 From: Rein Henrichs Date: Mon, 23 Aug 2010 16:28:27 -0700 Subject: [#4552] Updating --timing to report in milliseconds instead of seconds --- lib/facter.rb | 7 +------ lib/facter/util/resolution.rb | 10 ++++------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/facter.rb b/lib/facter.rb index 661831f..f48138a 100644 --- a/lib/facter.rb +++ b/lib/facter.rb @@ -80,12 +80,7 @@ module Facter # show the timing information def self.show_time(string) - if string.nil? - return - end - if self.timing? - puts GREEN + string + RESET - end + puts "#{GREEN}#{string}#{RESET}" if string and Facter.timing? end def self.timing? diff --git a/lib/facter/util/resolution.rb b/lib/facter/util/resolution.rb index 875b654..4a99c35 100644 --- a/lib/facter/util/resolution.rb +++ b/lib/facter/util/resolution.rb @@ -136,7 +136,7 @@ class Facter::Util::Resolution result = nil return result if @code == nil and @interpreter == nil - starttime = Time.now.to_i + starttime = Time.now.to_f begin Timeout.timeout(limit) do @@ -159,11 +159,9 @@ class Facter::Util::Resolution return nil end - finishtime = Time.now.to_i - - if Facter.timing? - Facter.show_time "Executing #{self.name} took #{finishtime - starttime} seconds" - end + finishtime = Time.now.to_f + ms = (finishtime - starttime) * 1000 + Facter.show_time "#{self.name}: #{"%.2f" % ms}ms" return nil if result == "" return result -- cgit