diff --git a/lib/hub.rb b/lib/hub.rb index fa8239b8069ecff86bf9a1e39ec7402420feb725..baf1f65cd5601dddaf4eb5be1bba8aac6560e7ba 100644 --- a/lib/hub.rb +++ b/lib/hub.rb @@ -1,6 +1,7 @@ require 'hub/version' require 'hub/args' require 'hub/context' +require 'hub/ssh_config' require 'hub/json' require 'hub/commands' require 'hub/runner' diff --git a/lib/hub/context.rb b/lib/hub/context.rb index b8b9a519812fcb8319defbf0eda75592aed50ac8..fef0b26f234d628536a70aa631fbc97bc6cdb0c5 100644 --- a/lib/hub/context.rb +++ b/lib/hub/context.rb @@ -513,91 +513,5 @@ module Hub def command?(name) !which(name).nil? end - - class SshConfig - CONFIG_FILES = %w(~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config) - - def initialize files = nil - @settings = Hash.new {|h,k| h[k] = {} } - Array(files || CONFIG_FILES).each do |path| - file = File.expand_path path - parse_file file if File.exist? file - end - end - - # yields if not found - def get_value hostname, key - key = key.to_s.downcase - @settings.each do |pattern, settings| - if pattern.match? hostname and found = settings[key] - return found - end - end - yield - end - - class HostPattern - def initialize pattern - @pattern = pattern.to_s.downcase - end - - def to_s() @pattern end - def ==(other) other.to_s == self.to_s end - - def matcher - @matcher ||= - if '*' == @pattern - Proc.new { true } - elsif @pattern !~ /[?*]/ - lambda { |hostname| hostname.to_s.downcase == @pattern } - else - re = self.class.pattern_to_regexp @pattern - lambda { |hostname| re =~ hostname } - end - end - - def match? hostname - matcher.call hostname - end - - def self.pattern_to_regexp pattern - escaped = Regexp.escape(pattern) - escaped.gsub!('\*', '.*') - escaped.gsub!('\?', '.') - /^#{escaped}$/i - end - end - - def parse_file file - host_patterns = [HostPattern.new('*')] - - IO.foreach(file) do |line| - case line - when /^\s*(#|$)/ then next - when /^\s*(\S+)\s*=/ - key, value = $1, $' - else - key, value = line.strip.split(/\s+/, 2) - end - - next if value.nil? - key.downcase! - value = $1 if value =~ /^"(.*)"$/ - value.chomp! - - if 'host' == key - host_patterns = value.split(/\s+/).map {|p| HostPattern.new p } - else - record_setting key, value, host_patterns - end - end - end - - def record_setting key, value, patterns - patterns.each do |pattern| - @settings[pattern][key] ||= value - end - end - end end end diff --git a/lib/hub/ssh_config.rb b/lib/hub/ssh_config.rb new file mode 100644 index 0000000000000000000000000000000000000000..580d2b8a8d78ce44f7dc9af6dbeaf3bded22f580 --- /dev/null +++ b/lib/hub/ssh_config.rb @@ -0,0 +1,91 @@ +module Hub + # Reads ssh configuration files and records each setting under its host + # pattern so it can be looked up by hostname. + class SshConfig + CONFIG_FILES = %w(~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config) + + def initialize files = nil + @settings = Hash.new {|h,k| h[k] = {} } + Array(files || CONFIG_FILES).each do |path| + file = File.expand_path path + parse_file file if File.exist? file + end + end + + # Public: Get a setting as it would apply to a specific hostname. + # + # Yields if not found. + def get_value hostname, key + key = key.to_s.downcase + @settings.each do |pattern, settings| + if pattern.match? hostname and found = settings[key] + return found + end + end + yield + end + + class HostPattern + def initialize pattern + @pattern = pattern.to_s.downcase + end + + def to_s() @pattern end + def ==(other) other.to_s == self.to_s end + + def matcher + @matcher ||= + if '*' == @pattern + Proc.new { true } + elsif @pattern !~ /[?*]/ + lambda { |hostname| hostname.to_s.downcase == @pattern } + else + re = self.class.pattern_to_regexp @pattern + lambda { |hostname| re =~ hostname } + end + end + + def match? hostname + matcher.call hostname + end + + def self.pattern_to_regexp pattern + escaped = Regexp.escape(pattern) + escaped.gsub!('\*', '.*') + escaped.gsub!('\?', '.') + /^#{escaped}$/i + end + end + + def parse_file file + host_patterns = [HostPattern.new('*')] + + IO.foreach(file) do |line| + case line + when /^\s*(#|$)/ then next + when /^\s*(\S+)\s*=/ + key, value = $1, $' + else + key, value = line.strip.split(/\s+/, 2) + end + + next if value.nil? + key.downcase! + value = $1 if value =~ /^"(.*)"$/ + value.chomp! + + if 'host' == key + host_patterns = value.split(/\s+/).map {|p| HostPattern.new p } + else + record_setting key, value, host_patterns + end + end + end + + def record_setting key, value, patterns + patterns.each do |pattern| + @settings[pattern][key] ||= value + end + end + end +end diff --git a/test/hub_test.rb b/test/hub_test.rb index 91d20243a5a312dba360d4e2beb70fe0b821a346..37fd4b438aea1423be5d7126f36882e0f0ec5e6c 100644 --- a/test/hub_test.rb +++ b/test/hub_test.rb @@ -36,7 +36,7 @@ class HubTest < Test::Unit::TestCase super COMMANDS.replace %w[open groff] Hub::Context::PWD.replace '/path/to/hub' - Hub::Context::SshConfig::CONFIG_FILES.replace [] + Hub::SshConfig::CONFIG_FILES.replace [] @git_reader = Hub::Context::GitReader.new 'git' do |cache, cmd| unless cmd.index('config --get alias.') == 0 @@ -1444,7 +1444,7 @@ config def with_ssh_config config_file = File.expand_path '../ssh_config', __FILE__ - Hub::Context::SshConfig::CONFIG_FILES.replace [config_file] + Hub::SshConfig::CONFIG_FILES.replace [config_file] yield end