lib/mcollective/util.rb in mcollective-client-2.0.0 vs lib/mcollective/util.rb in mcollective-client-2.2.0
- old
+ new
@@ -127,14 +127,14 @@
end
# Creates an empty filter
def self.empty_filter
{"fact" => [],
- "cf_class" => [],
- "agent" => [],
- "identity" => [],
- "compound" => []}
+ "cf_class" => [],
+ "agent" => [],
+ "identity" => [],
+ "compound" => []}
end
# Picks a config file defaults to ~/.mcollective
# else /etc/mcollective/client.cfg
def self.config_file_for_user
@@ -154,16 +154,18 @@
return config
end
# Creates a standard options hash
def self.default_options
- {:verbose => false,
- :disctimeout => 2,
- :timeout => 5,
- :config => config_file_for_user,
- :collective => nil,
- :filter => empty_filter}
+ {:verbose => false,
+ :disctimeout => nil,
+ :timeout => 5,
+ :config => config_file_for_user,
+ :collective => nil,
+ :discovery_method => nil,
+ :discovery_options => Config.instance.default_discovery_options,
+ :filter => empty_filter}
end
def self.make_subscriptions(agent, type, collective=nil)
config = Config.instance
@@ -245,30 +247,199 @@
def self.windows?
!!(RbConfig::CONFIG['host_os'] =~ /mswin|win32|dos|mingw|cygwin/i)
end
- def self.eval_compound_statement(expression)
- if expression.values.first =~ /^\//
- return Util.has_cf_class?(expression.values.first)
- elsif expression.values.first =~ />=|<=|=|<|>/
- optype = expression.values.first.match(/>=|<=|=|<|>/)
- name, value = expression.values.first.split(optype[0])
- unless value.split("")[0] == "/"
- optype[0] == "=" ? optype = "==" : optype = optype[0]
- else
- optype = "=~"
- end
+ # Return color codes, if the config color= option is false
+ # just return a empty string
+ def self.color(code)
+ colorize = Config.instance.color
- return Util.has_fact?(name,value, optype).to_s
+ colors = {:red => "[31m",
+ :green => "[32m",
+ :yellow => "[33m",
+ :cyan => "[36m",
+ :bold => "[1m",
+ :reset => "[0m"}
+
+ if colorize
+ return colors[code] || ""
else
- return Util.has_cf_class?(expression.values.first)
+ return ""
end
end
+ # Helper to return a string in specific color
+ def self.colorize(code, msg)
+ "%s%s%s" % [ color(code), msg, color(:reset) ]
+ end
+
# Returns the current ruby version as per RUBY_VERSION, mostly
# doing this here to aid testing
def self.ruby_version
RUBY_VERSION
+ end
+
+ def self.mcollective_version
+ MCollective::VERSION
+ end
+
+ # Returns an aligned_string of text relative to the size of the terminal
+ # window. If a line in the string exceeds the width of the terminal window
+ # the line will be chopped off at the whitespace chacter closest to the
+ # end of the line and prepended to the next line, keeping all indentation.
+ #
+ # The terminal size is detected by default, but custom line widths can
+ # passed. All strings will also be left aligned with 5 whitespace characters
+ # by default.
+ def self.align_text(text, console_cols = nil, preamble = 5)
+ unless console_cols
+ console_cols = terminal_dimensions[0]
+
+ # if unknown size we default to the typical unix default
+ console_cols = 80 if console_cols == 0
+ end
+
+ console_cols -= preamble
+
+ # Return unaligned text if console window is too small
+ return text if console_cols <= 0
+
+ # If console is 0 this implies unknown so we assume the common
+ # minimal unix configuration of 80 characters
+ console_cols = 80 if console_cols <= 0
+
+ text = text.split("\n")
+ piece = ''
+ whitespace = 0
+
+ text.each_with_index do |line, i|
+ whitespace = 0
+
+ while whitespace < line.length && line[whitespace].chr == ' '
+ whitespace += 1
+ end
+
+ # If the current line is empty, indent it so that a snippet
+ # from the previous line is aligned correctly.
+ if line == ""
+ line = (" " * whitespace)
+ end
+
+ # If text was snipped from the previous line, prepend it to the
+ # current line after any current indentation.
+ if piece != ''
+ # Reset whitespaces to 0 if there are more whitespaces than there are
+ # console columns
+ whitespace = 0 if whitespace >= console_cols
+
+ # If the current line is empty and being prepended to, create a new
+ # empty line in the text so that formatting is preserved.
+ if text[i + 1] && line == (" " * whitespace)
+ text.insert(i + 1, "")
+ end
+
+ # Add the snipped text to the current line
+ line.insert(whitespace, "#{piece} ")
+ end
+
+ piece = ''
+
+ # Compare the line length to the allowed line length.
+ # If it exceeds it, snip the offending text from the line
+ # and store it so that it can be prepended to the next line.
+ if line.length > (console_cols + preamble)
+ reverse = console_cols
+
+ while line[reverse].chr != ' '
+ reverse -= 1
+ end
+
+ piece = line.slice!(reverse, (line.length - 1)).lstrip
+ end
+
+ # If a snippet exists when all the columns in the text have been
+ # updated, create a new line and append the snippet to it, using
+ # the same left alignment as the last line in the text.
+ if piece != '' && text[i+1].nil?
+ text[i+1] = "#{' ' * (whitespace)}#{piece}"
+ piece = ''
+ end
+
+ # Add the preamble to the line and add it to the text
+ line = ((' ' * preamble) + line)
+ text[i] = line
+ end
+
+ text.join("\n")
+ end
+
+ # Figures out the columns and lines of the current tty
+ #
+ # Returns [0, 0] if it can't figure it out or if you're
+ # not running on a tty
+ def self.terminal_dimensions(stdout = STDOUT, environment = ENV)
+ return [0, 0] unless stdout.tty?
+
+ return [80, 40] if Util.windows?
+
+ if environment["COLUMNS"] && environment["LINES"]
+ return [environment["COLUMNS"].to_i, environment["LINES"].to_i]
+
+ elsif environment["TERM"] && command_in_path?("tput")
+ return [`tput cols`.to_i, `tput lines`.to_i]
+
+ elsif command_in_path?('stty')
+ return `stty size`.scan(/\d+/).map {|s| s.to_i }
+ else
+ return [0, 0]
+ end
+ rescue
+ [0, 0]
+ end
+
+ # Checks in PATH returns true if the command is found
+ def self.command_in_path?(command)
+ found = ENV["PATH"].split(File::PATH_SEPARATOR).map do |p|
+ File.exist?(File.join(p, command))
+ end
+
+ found.include?(true)
+ end
+
+ # compare two software versions as commonly found in
+ # package versions.
+ #
+ # returns 0 if a == b
+ # returns -1 if a < b
+ # returns 1 if a > b
+ #
+ # Code originally from Puppet but refactored to a more
+ # ruby style that fits in better with this code base
+ def self.versioncmp(version_a, version_b)
+ vre = /[-.]|\d+|[^-.\d]+/
+ ax = version_a.scan(vre)
+ bx = version_b.scan(vre)
+
+ until ax.empty? || bx.empty?
+ a = ax.shift
+ b = bx.shift
+
+ next if a == b
+ next if a == '-' && b == '-'
+ return -1 if a == '-'
+ return 1 if b == '-'
+ next if a == '.' && b == '.'
+ return -1 if a == '.'
+ return 1 if b == '.'
+
+ if a =~ /^[^0]\d+$/ && b =~ /^[^0]\d+$/
+ return Integer(a) <=> Integer(b)
+ else
+ return a.upcase <=> b.upcase
+ end
+ end
+
+ version_a <=> version_b
end
end
end