Skip to content

Instantly share code, notes, and snippets.

@m87h
Last active September 9, 2015 06:45
Show Gist options
  • Save m87h/08aaa22f6860204606ae to your computer and use it in GitHub Desktop.
Save m87h/08aaa22f6860204606ae to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'erb'
require 'ipaddr'
class HostParseError < StandardError; end
class Host
attr_accessor :fqhn, :port, :user, :name, :proxy
def proxied?
!!@proxy
end
def ip?
!(IPAddr.new(@fqhn) rescue nil).nil?
end
end
class ERBContext
def initialize(hash)
hash.each_pair do |key, value|
instance_variable_set('@' + key.to_s, value)
end
end
def get_binding
binding
end
end
FQDN_RE = /([^\.]+)/
HOST_SPEC_RE = /(?:(?<proxy>[^\s]+)\s+->\s+)?(?:(?<user>[^@]+)@)?(?<fqhn>[^\s:]+)(?:\:(?<port>\d+))?(?:\s+\((?<name>[^\)]+)\))?/
def parse_host_spec(spec)
data = HOST_SPEC_RE.match(spec)
raise HostParseError, 'Malformed syntax' unless data
host = Host.new
host.fqhn = data['fqhn']
host.proxy = data['proxy']
host.port = data['port'] || 22
host.user = data['user']
host.name =
if data['name']
data['name']
elsif not host.ip?
FQDN_RE.match(data['fqhn'])[1]
else
raise HostParseError, 'Cannot infer name'
end
host
end
def render_hosts
Dir.glob(File.expand_path('~/.ssh/hosts.d/*.hosts')).each do |hosts_file|
config_file = File.join(File.expand_path('~/.ssh/config.d'), File.basename(hosts_file, '.hosts'))
config = ERB.new(File.new(config_file + '.config').read, nil, '%')
File.readlines(hosts_file).each_with_index do |spec, i|
line = i + 1
spec = spec.chomp
begin
host = parse_host_spec(spec)
yield config.result(ERBContext.new(host: host).get_binding)
rescue HostParseError => e
STDERR.puts "warning: parse error in #{hosts_file}:#{line} \"#{spec}\" (#{e.message}), skipping."
end
end
end
end
File.open(File.expand_path('~/.ssh/config'), File::CREAT|File::TRUNC|File::RDWR, 0644) do |io|
render_hosts do |host|
io.puts host
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment