host.rb
3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
require 'ostruct'
module SSHKit
UnparsableHostStringError = Class.new(SSHKit::StandardError)
class Host
attr_accessor :password, :hostname, :port, :user, :ssh_options
def key=(new_key)
@keys = [new_key]
end
def keys=(new_keys)
@keys = new_keys
end
def keys
Array(@keys)
end
def initialize(host_string_or_options_hash)
@keys = []
@local = false
if host_string_or_options_hash == :local
@local = true
@hostname = "localhost"
@user = ENV['USER'] || ENV['LOGNAME'] || ENV['USERNAME']
elsif !host_string_or_options_hash.is_a?(Hash)
@user, @hostname, @port = first_suitable_parser(host_string_or_options_hash).attributes
else
host_string_or_options_hash.each do |key, value|
if self.respond_to?("#{key}=")
send("#{key}=", value)
else
raise ArgumentError, "Unknown host property #{key}"
end
end
end
end
def local?
@local
end
def hash
user.hash ^ hostname.hash ^ port.hash
end
def username
user
end
def eql?(other_host)
other_host.hash == hash
end
alias :== :eql?
alias :equal? :eql?
def to_s
hostname
end
def netssh_options
{}.tap do |sho|
sho[:keys] = keys if keys.any?
sho[:port] = port if port
sho[:user] = user if user
sho[:password] = password if password
sho[:forward_agent] = true
end
.merge(ssh_options || {})
end
def properties
@properties ||= OpenStruct.new
end
def first_suitable_parser(host)
parser = PARSERS.find{|p| p.suitable?(host) }
fail UnparsableHostStringError, "Cannot parse host string #{host}" if parser.nil?
parser.new(host)
end
end
# @private
# :nodoc:
class SimpleHostParser
def self.suitable?(host_string)
!host_string.match(/:|@/)
end
def initialize(host_string)
@host_string = host_string
end
def username
end
def port
end
def hostname
@host_string
end
def attributes
[username, hostname, port]
end
end
class HostWithPortParser < SimpleHostParser
def self.suitable?(host_string)
!host_string.match(/@|\[|\]/)
end
def port
@host_string.split(':').last.to_i
end
def hostname
@host_string.split(':').first
end
end
# @private
# :nodoc:
class HostWithUsernameAndPortParser < SimpleHostParser
def self.suitable?(host_string)
host_string.match(/@.*:\d+/)
end
def username
@host_string.split(/:|@/)[0]
end
def hostname
@host_string.split(/:|@/)[1]
end
def port
@host_string.split(/:|@/)[2].to_i
end
end
# @private
# :nodoc:
class IPv6HostWithPortParser < SimpleHostParser
def self.suitable?(host_string)
host_string.match(/[a-fA-F0-9:]+:\d+/)
end
def port
@host_string.split(':').last.to_i
end
def hostname
@host_string.gsub!(/\[|\]/, '')
@host_string.split(':')[0..-2].join(':')
end
end
# @private
# :nodoc:
class HostWithUsernameParser < SimpleHostParser
def self.suitable?(host_string)
host_string.match(/@/) && !host_string.match(/\:/)
end
def username
@host_string.split('@').first
end
def hostname
@host_string.split('@').last
end
end
PARSERS = [
SimpleHostParser,
HostWithPortParser,
HostWithUsernameAndPortParser,
IPv6HostWithPortParser,
HostWithUsernameParser,
].freeze
end