train-core 3.2.14 → 3.2.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4a9a2b3342fe17d7bcbfe3fcee05215b867798a4c8f01a6924e8ac57846fa9d
4
- data.tar.gz: 0041aaaeeb3405feda9ec52c0cdc04867245e3b9b2259a122ed9db44f4506504
3
+ metadata.gz: ebf0e0aa7d97a1c6b4f63c707bba2daf62b2fa53df072dc0884c727dfff1016d
4
+ data.tar.gz: 345f982e6e7966172ba88817689a73ac021cd692d97f9d4ae13f6b772d987c13
5
5
  SHA512:
6
- metadata.gz: a8d25991efa5582a917b6eb8b89cfc4bb04c54202558043c601fa29be600f384885672cb7371f76cca5709fecb06b0c3fbdd735b6898c4fea96f39f200b987ce
7
- data.tar.gz: c9421752289a00b535b7fdff660e9e1e19ff23e37647741e8e042a5ec31e36c9b6af1eef8445217f05905b0178981000681f1c0b0b028b623b7ef2408371da6b
6
+ metadata.gz: 5884539b913f79cdc135a05f6e4ed47ddd5bd051ad919977804adcc9e36e2ddbd85bda8dec3185be32cd2de1d1027628d755c5188728ee524e567bc914713116
7
+ data.tar.gz: a061b7dc4e62f0722a2720e13e0634e077565b6dbd52adc1c56a002e2c58c395dbc8c6cb44a9bb033cab14a186883332b35d23ed9efd5941bb657481c2c9a006
@@ -7,7 +7,7 @@ require_relative "train/options"
7
7
  require_relative "train/plugins"
8
8
  require_relative "train/errors"
9
9
  require_relative "train/platforms"
10
- require "uri"
10
+ require "addressable/uri"
11
11
 
12
12
  module Train
13
13
  # Create a new transport instance, with the plugin indicated by the
@@ -101,7 +101,7 @@ module Train
101
101
  creds[:path] ||= uri.path
102
102
  creds[:password] ||=
103
103
  if opts[:www_form_encoded_password] && !uri.password.nil?
104
- URI.decode_www_form_component(uri.password)
104
+ Addressable::URI.unencode_component(uri.password)
105
105
  else
106
106
  uri.password
107
107
  end
@@ -121,24 +121,24 @@ module Train
121
121
  # Parse a URI. Supports empty URI's with paths, e.g. `mock://`
122
122
  #
123
123
  # @param string [string] URI string, e.g. `schema://domain.com`
124
- # @return [URI::Generic] parsed URI object
124
+ # @return [Addressable::URI] parsed URI object
125
125
  def self.parse_uri(string)
126
- URI.parse(string)
127
- rescue URI::InvalidURIError => e
126
+ u = Addressable::URI.parse(string)
128
127
  # A use-case we want to catch is parsing empty URIs with a schema
129
128
  # e.g. mock://. To do this, we match it manually and fake the hostname
130
- case string
131
- when %r{^([a-z]+)://$}
132
- string += "dummy"
133
- when /^([a-z]+):$/
134
- string += "//dummy"
135
- else
136
- raise Train::UserError, e
129
+ if u.scheme && (u.host.nil? || u.host.empty?) && u.path.empty?
130
+ case string
131
+ when %r{^([a-z]+)://$}
132
+ string += "dummy"
133
+ when /^([a-z]+):$/
134
+ string += "//dummy"
135
+ end
136
+ u = Addressable::URI.parse(string)
137
+ u.host = nil
137
138
  end
138
-
139
- uri = URI.parse(string)
140
- uri.host = nil
141
- uri
139
+ u
140
+ rescue Addressable::URI::InvalidURIError => e
141
+ raise Train::UserError, e
142
142
  end
143
143
  private_class_method :parse_uri
144
144
 
@@ -19,16 +19,19 @@ module Train::Platforms
19
19
  end
20
20
 
21
21
  def detect(&block)
22
- if block_given?
23
- @detect = block
24
- self
25
- elsif @detect.nil?
26
- # we are returning a block that just returns false here
27
- # to skip the family/platform evaluation if detect is not set
28
- ->(_) { false }
29
- else
30
- @detect
31
- end
22
+ @detect = block if block
23
+
24
+ # TODO: detect shouldn't be a setter and getter at the same time
25
+ @detect ||= ->(_) { false }
26
+ end
27
+
28
+ def to_s
29
+ be = backend ? backend.backend_type : "unknown"
30
+ "%s:%s:%s" % [self.class, be, name]
31
+ end
32
+
33
+ def inspect
34
+ to_s
32
35
  end
33
36
  end
34
37
  end
@@ -70,11 +70,8 @@ module Train::Platforms::Detect::Helpers
70
70
  res = command_output("version")
71
71
 
72
72
  m = res.match(/^Fabric OS:\s+v(\S+)$/)
73
- unless m.nil?
74
- return @cache[:brocade] = { version: m[1], type: "fos" }
75
- end
76
73
 
77
- @cache[:brocade] = nil
74
+ @cache[:brocade] = m && { version: m[1], type: "fos" }
78
75
  end
79
76
 
80
77
  def cisco_show_version
@@ -156,5 +153,24 @@ module Train::Platforms::Detect::Helpers
156
153
  # rubocop:disable Style/FormatString
157
154
  "%08x-%04x-%04x-%04x-%04x%08x" % ary
158
155
  end
156
+
157
+ def json_cmd(cmd)
158
+ cmd = @backend.run_command(cmd)
159
+ if cmd.exit_status == 0 && !cmd.stdout.empty?
160
+ require "json"
161
+ eos_ver = JSON.parse(cmd.stdout)
162
+ @platform[:release] = eos_ver["version"]
163
+ @platform[:arch] = eos_ver["architecture"]
164
+ true
165
+ end
166
+ rescue JSON::ParserError
167
+ nil
168
+ end
169
+
170
+ def set_from_uname
171
+ @platform[:name] = unix_uname_s.lines.first.chomp
172
+ @platform[:release] = unix_uname_r.lines.first.chomp
173
+ true
174
+ end
159
175
  end
160
176
  end
@@ -19,6 +19,13 @@ module Train::Platforms::Detect::Helpers
19
19
  end
20
20
  end
21
21
 
22
+ def redhatish(path)
23
+ if (raw = unix_file_contents(path))
24
+ @platform[:release] = redhatish_version(raw)
25
+ true
26
+ end
27
+ end
28
+
22
29
  def linux_os_release
23
30
  data = unix_file_contents("/etc/os-release")
24
31
  return if data.nil?
@@ -44,6 +44,11 @@ module Train::Platforms::Detect::Helpers
44
44
  true
45
45
  end
46
46
 
47
+ def local_windows?
48
+ @backend.class.to_s == "Train::Transports::Local::Connection" &&
49
+ ruby_host_os(/mswin|mingw32|windows/)
50
+ end
51
+
47
52
  # reads os name and version from wmic
48
53
  # @see https://msdn.microsoft.com/en-us/library/bb742610.aspx#EEAA
49
54
  # Thanks to Matt Wrock (https://github.com/mwrock) for this hint
@@ -27,7 +27,7 @@ module Train::Platforms::Detect
27
27
  top.each do |_name, plat|
28
28
  # we are doing a instance_eval here to make sure we have the proper
29
29
  # context with all the detect helper methods
30
- next unless instance_eval(&plat.detect) == true
30
+ next unless instance_eval(&plat.detect)
31
31
 
32
32
  # if we have a match start looking at the children
33
33
  plat_result = scan_children(plat)
@@ -43,7 +43,7 @@ module Train::Platforms::Detect
43
43
 
44
44
  def scan_children(parent)
45
45
  parent.children.each do |plat, condition|
46
- next unless instance_eval(&plat.detect) == true
46
+ next unless instance_eval(&plat.detect)
47
47
 
48
48
  if plat.class == Train::Platforms::Platform
49
49
  return plat if condition.empty? || check_condition(condition)
@@ -1,629 +1,519 @@
1
- # encoding: utf-8
2
-
3
- # rubocop:disable Style/Next
4
- # rubocop:disable Metrics/AbcSize
5
- # rubocop:disable Metrics/CyclomaticComplexity
6
- # rubocop:disable Metrics/ClassLength
7
- # rubocop:disable Metrics/MethodLength
8
- # rubocop:disable Metrics/PerceivedComplexity
1
+ # rubocop:disable Style/ParenthesesAroundCondition
9
2
 
10
3
  module Train::Platforms::Detect::Specifications
11
4
  class OS
12
5
  def self.load
13
- plat = Train::Platforms
6
+ load_toplevel
7
+ load_windows
8
+ load_unix
9
+ load_other
10
+ end
14
11
 
15
- # master family
12
+ def self.load_toplevel
16
13
  plat.family("os").detect { true }
14
+ end
17
15
 
18
- plat.family("windows").in_family("os")
19
- .detect do
20
- # Can't return from a `proc` thus the `is_windows` shenanigans
21
- is_windows = false
22
- is_windows = true if winrm?
23
-
24
- if @backend.class.to_s == "Train::Transports::Local::Connection"
25
- is_windows = true if ruby_host_os(/mswin|mingw32|windows/)
26
- end
16
+ def self.load_windows
17
+ declare_category("windows", "os") do
18
+ (winrm? ||
19
+ local_windows? ||
20
+ detect_windows) # ssh
21
+ end
27
22
 
28
- # Try to detect windows even for ssh transport
29
- if !is_windows && detect_windows == true
30
- is_windows = true
31
- end
23
+ declare_family("windows", "windows") do
24
+ detect_windows
25
+ end
26
+ end
32
27
 
33
- is_windows
34
- end
35
- # windows platform
36
- plat.name("windows").in_family("windows")
37
- .detect do
38
- true if detect_windows == true
28
+ def self.load_unix
29
+ declare_category("unix", "os") do
30
+ # we want to catch a special case here where cisco commands
31
+ # don't return an exit status and still print to stdout
32
+ uname = unix_uname_s
33
+ unless (uname.empty? ||
34
+ uname.start_with?("Line has invalid autocommand") ||
35
+ uname.start_with?("The command you have entered"))
36
+ @platform[:arch] = unix_uname_m
37
+ true
39
38
  end
39
+ end
40
40
 
41
- # unix master family
42
- plat.family("unix").in_family("os")
43
- .detect do
44
- # we want to catch a special case here where cisco commands
45
- # don't return an exit status and still print to stdout
46
- if unix_uname_s =~ /./ && !unix_uname_s.start_with?("Line has invalid autocommand ") && !unix_uname_s.start_with?("The command you have entered")
47
- @platform[:arch] = unix_uname_m
48
- true
49
- end
50
- end
41
+ load_linux
42
+ load_other_unix
43
+ load_bsd
44
+ end
51
45
 
52
- # linux master family
53
- plat.family("linux").in_family("unix")
54
- .detect do
55
- true if unix_uname_s =~ /linux/i
56
- end
46
+ def self.load_linux
47
+ declare_category("linux", "unix") do
48
+ unix_uname_s =~ /linux/i
49
+ end
57
50
 
58
- # debian family
59
- plat.family("debian").in_family("linux")
60
- .detect do
61
- true unless unix_file_contents("/etc/debian_version").nil?
62
- end
63
- plat.name("ubuntu").title("Ubuntu Linux").in_family("debian")
64
- .detect do
65
- lsb = read_linux_lsb
66
- if lsb && lsb[:id] =~ /ubuntu/i
67
- @platform[:release] = lsb[:release]
68
- true
69
- end
70
- end
71
- plat.name("linuxmint").title("LinuxMint").in_family("debian")
72
- .detect do
73
- lsb = read_linux_lsb
74
- if lsb && lsb[:id] =~ /linuxmint/i
75
- @platform[:release] = lsb[:release]
76
- true
77
- end
78
- end
79
- plat.name("raspbian").title("Raspbian Linux").in_family("debian")
80
- .detect do
81
- if (linux_os_release && linux_os_release["NAME"] =~ /raspbian/i) || \
82
- unix_file_exist?("/usr/bin/raspi-config")
83
- @platform[:release] = unix_file_contents("/etc/debian_version").chomp
84
- true
85
- end
86
- end
87
- plat.name("debian").title("Debian Linux").in_family("debian")
88
- .detect do
89
- lsb = read_linux_lsb
90
- if lsb && lsb[:id] =~ /debian/i
91
- @platform[:release] = lsb[:release]
92
- true
93
- end
51
+ declare_category("debian", "linux") do
52
+ unix_file_exist?("/etc/debian_version")
53
+ end
94
54
 
95
- # if we get this far we have to be some type of debian
96
- @platform[:release] = unix_file_contents("/etc/debian_version").chomp
55
+ declare_lsb("ubuntu", "Ubuntu Linux", "debian", /ubuntu/i)
56
+
57
+ declare_lsb("linuxmint", "LinuxMint", "debian", /linuxmint/i)
58
+
59
+ declare_instance("kali", "Kali Linux", "debian") do
60
+ l_o_r = linux_os_release
61
+ if l_o_r && l_o_r["ID"] == "kali"
62
+ @platform[:release] = l_o_r["VERSION"]
97
63
  true
98
64
  end
65
+ end
66
+
67
+ declare_instance("raspbian", "Raspbian Linux", "debian") do
68
+ rel = linux_os_release
69
+ if (rel && rel["NAME"] =~ /raspbian/i) ||
70
+ unix_file_exist?("/usr/bin/raspi-config")
71
+ @platform[:release] = unix_file_contents("/etc/debian_version").chomp
99
72
 
100
- # fedora family
101
- plat.family("fedora").in_family("linux")
102
- .detect do
103
- true if linux_os_release && linux_os_release["NAME"] =~ /fedora/i
104
- end
105
- plat.name("fedora").title("Fedora").in_family("fedora")
106
- .detect do
107
- @platform[:release] = linux_os_release["VERSION_ID"]
108
73
  true
109
74
  end
75
+ end
76
+
77
+ declare_instance("debian", "Debian Linux", "debian") do
78
+ # if we get this far we have to be some type of debian
79
+ @platform[:release] = unix_file_contents("/etc/debian_version").chomp
80
+
81
+ true
82
+ end
83
+
84
+ declare_category("fedora", "linux") do
85
+ rel = linux_os_release
86
+ rel && rel["NAME"] =~ /fedora/i
87
+ end
88
+
89
+ declare_instance("fedora", "Fedora", "fedora") do
90
+ @platform[:release] = linux_os_release["VERSION_ID"]
91
+ true
92
+ end
110
93
 
111
- # arista_eos family
112
- # this checks for the arista bash shell
113
94
  # must come before redhat as it uses fedora under the hood
114
95
  plat.family("arista_eos").title("Arista EOS Family").in_family("linux")
115
96
  .detect do
116
97
  true
117
98
  end
118
- plat.name("arista_eos_bash").title("Arista EOS Bash Shell").in_family("arista_eos")
119
- .detect do
120
- if unix_file_exist?("/usr/bin/FastCli")
121
- cmd = @backend.run_command('FastCli -p 15 -c "show version | json"')
122
- if cmd.exit_status == 0 && !cmd.stdout.empty?
123
- require "json"
124
- begin
125
- eos_ver = JSON.parse(cmd.stdout)
126
- @platform[:release] = eos_ver["version"]
127
- @platform[:arch] = eos_ver["architecture"]
128
- true
129
- rescue JSON::ParserError
130
- nil
131
- end
132
- end
133
- end
99
+
100
+ declare_instance("arista_eos_bash", "Arista EOS Bash Shell", "arista_eos") do
101
+ # this checks for the arista bash shell
102
+ if unix_file_exist?("/usr/bin/FastCli")
103
+ # TODO: no tests
104
+ json_cmd('FastCli -p 15 -c "show version | json"')
134
105
  end
106
+ end
135
107
 
136
- # redhat family
137
- plat.family("redhat").in_family("linux")
138
- .detect do
139
- # I am not sure this returns true for all redhats in this family
140
- # for now we are going to just try each platform
141
- # return true unless unix_file_contents('/etc/redhat-release').nil?
108
+ declare_category("redhat", "linux") do
109
+ true
110
+ end
142
111
 
112
+ declare_instance("centos", "Centos Linux", "redhat") do
113
+ lsb = read_linux_lsb
114
+ if lsb && lsb[:id] =~ /centos/i
115
+ # TODO: no tests
116
+ @platform[:release] = lsb[:release]
117
+ true
118
+ elsif (rel = linux_os_release) && rel["NAME"] =~ /centos/i
119
+ @platform[:release] = redhatish_version(unix_file_contents("/etc/redhat-release"))
143
120
  true
144
121
  end
145
- plat.name("centos").title("Centos Linux").in_family("redhat")
146
- .detect do
147
- lsb = read_linux_lsb
148
- if lsb && lsb[:id] =~ /centos/i
149
- @platform[:release] = lsb[:release]
150
- true
151
- elsif linux_os_release && linux_os_release["NAME"] =~ /centos/i
152
- @platform[:release] = redhatish_version(unix_file_contents("/etc/redhat-release"))
153
- true
154
- end
155
- end
156
- plat.name("oracle").title("Oracle Linux").in_family("redhat")
157
- .detect do
158
- if !(raw = unix_file_contents("/etc/oracle-release")).nil?
159
- @platform[:release] = redhatish_version(raw)
160
- true
161
- elsif !(raw = unix_file_contents("/etc/enterprise-release")).nil?
162
- @platform[:release] = redhatish_version(raw)
163
- true
164
- end
165
- end
166
- plat.name("scientific").title("Scientific Linux").in_family("redhat")
167
- .detect do
168
- lsb = read_linux_lsb
169
- if lsb && lsb[:id] =~ /scientific/i
170
- @platform[:release] = lsb[:release]
171
- true
172
- end
173
- end
174
- plat.name("xenserver").title("Xenserer Linux").in_family("redhat")
175
- .detect do
176
- lsb = read_linux_lsb
177
- if lsb && lsb[:id] =~ /xenserver/i
178
- @platform[:release] = lsb[:release]
179
- true
180
- end
181
- end
182
- plat.name("parallels-release").title("Parallels Linux").in_family("redhat")
183
- .detect do
184
- unless (raw = unix_file_contents("/etc/parallels-release")).nil?
185
- @platform[:name] = redhatish_platform(raw)
186
- @platform[:release] = raw[/(\d\.\d\.\d)/, 1]
187
- true
188
- end
189
- end
190
- plat.name("wrlinux").title("Wind River Linux").in_family("redhat")
191
- .detect do
192
- if linux_os_release && linux_os_release["ID_LIKE"] =~ /wrlinux/i
193
- @platform[:release] = linux_os_release["VERSION"]
194
- true
195
- end
196
- end
197
- plat.name("amazon").title("Amazon Linux").in_family("redhat")
198
- .detect do
199
- lsb = read_linux_lsb
200
- if lsb && lsb[:id] =~ /amazon/i
201
- @platform[:release] = lsb[:release]
202
- true
203
- elsif (raw = unix_file_contents("/etc/system-release")) =~ /amazon/i
204
- @platform[:name] = redhatish_platform(raw)
205
- @platform[:release] = redhatish_version(raw)
206
- true
207
- end
122
+ end
123
+
124
+ declare_instance("oracle", "Oracle Linux", "redhat") do
125
+ (redhatish("/etc/oracle-release") ||
126
+ redhatish("/etc/enterprise-release"))
127
+ end
128
+
129
+ declare_lsb("scientific", "Scientific Linux", "redhat", /scientific/i)
130
+
131
+ declare_lsb("xenserver", "Xenserer Linux", "redhat", /xenserver/i)
132
+
133
+ declare_instance("parallels-release", "Parallels Linux", "redhat") do
134
+ if (raw = unix_file_contents("/etc/parallels-release"))
135
+ @platform[:name] = redhatish_platform(raw)
136
+ @platform[:release] = raw[/(\d\.\d\.\d)/, 1]
137
+ # TODO: no tests
138
+ true
208
139
  end
209
- plat.name("cloudlinux").title("CloudLinux").in_family("redhat")
210
- .detect do
211
- lsb = read_linux_lsb
212
- if lsb && lsb[:id] =~ /cloudlinux/i
213
- @platform[:release] = lsb[:release]
214
- true
215
- elsif (raw = unix_file_contents("/etc/redhat-release")) =~ /cloudlinux/i
216
- @platform[:name] = redhatish_platform(raw)
217
- @platform[:release] = redhatish_version(raw)
218
- true
219
- end
140
+ end
141
+
142
+ declare_instance("wrlinux", "Wind River Linux", "redhat") do
143
+ rel = linux_os_release
144
+ if rel && rel["ID_LIKE"] =~ /wrlinux/i
145
+ @platform[:release] = rel["VERSION"]
146
+ true
220
147
  end
148
+ end
149
+
150
+ declare_lsb_or_content("amazon", "Amazon Linux", "redhat", "/etc/system-release", /amazon/i)
151
+
152
+ declare_lsb_or_content("cloudlinux", "CloudLinux", "redhat", "/etc/redhat-release", /cloudlinux/i)
153
+
221
154
  # keep redhat at the end as a fallback for anything with a redhat-release
222
- plat.name("redhat").title("Red Hat Linux").in_family("redhat")
223
- .detect do
224
- lsb = read_linux_lsb
225
- if lsb && lsb[:id] =~ /redhat/i
226
- @platform[:release] = lsb[:release]
227
- true
228
- elsif !(raw = unix_file_contents("/etc/redhat-release")).nil?
229
- # must be some type of redhat
230
- @platform[:name] = redhatish_platform(raw)
231
- @platform[:release] = redhatish_version(raw)
232
- true
233
- end
234
- end
155
+ declare_lsb_or_content("redhat", "Red Hat Linux", "redhat", "/etc/redhat-release", /redhat/i, /./)
235
156
 
236
- # suse family
237
- plat.family("suse").in_family("linux")
238
- .detect do
239
- if linux_os_release && linux_os_release["ID_LIKE"] =~ /suse/i
240
- @platform[:release] = linux_os_release["VERSION"]
241
- true
242
- elsif !(suse = unix_file_contents("/etc/SuSE-release")).nil?
243
- # https://rubular.com/r/UKaYWolCYFMfp1
244
- version = suse.scan(/VERSION = (\d+)\nPATCHLEVEL = (\d+)/).flatten.join(".")
245
- # https://rubular.com/r/b5PN3hZDxa5amV
246
- version = suse[/VERSION\s?=\s?"?([\d\.]{2,})"?/, 1] if version == ""
247
- @platform[:release] = version
248
- true
249
- end
250
- end
251
- plat.name("opensuse").title("OpenSUSE Linux").in_family("suse")
252
- .detect do
253
- true if (linux_os_release && linux_os_release["NAME"] =~ /^opensuse/i) ||
254
- unix_file_contents("/etc/SuSE-release") =~ /^opensuse/i
255
- end
256
- plat.name("suse").title("Suse Linux").in_family("suse")
257
- .detect do
258
- true if (linux_os_release && linux_os_release["NAME"] =~ /^sles/i) ||
259
- unix_file_contents("/etc/SuSE-release") =~ /suse/i
157
+ declare_category("suse", "linux") do
158
+ rel = linux_os_release
159
+ if rel && rel["ID_LIKE"] =~ /suse/i
160
+ @platform[:release] = rel["VERSION"]
161
+ true
162
+ elsif (suse = unix_file_contents("/etc/SuSE-release"))
163
+ # https://rubular.com/r/UKaYWolCYFMfp1
164
+ version = suse.scan(/VERSION = (\d+)\nPATCHLEVEL = (\d+)/).flatten.join(".")
165
+ # https://rubular.com/r/b5PN3hZDxa5amV
166
+ version = suse[/VERSION\s?=\s?"?([\d\.]{2,})"?/, 1] if version == ""
167
+ @platform[:release] = version
168
+ true
260
169
  end
170
+ end
261
171
 
262
- # arch
263
- plat.name("arch").title("Arch Linux").in_family("linux")
264
- .detect do
265
- unless unix_file_contents("/etc/arch-release").nil?
266
- # Because this is a rolling release distribution,
267
- # use the kernel release, ex. 4.1.6-1-ARCH
268
- @platform[:release] = unix_uname_r
269
- true
270
- end
271
- end
172
+ declare_os_or_file("opensuse", "OpenSUSE Linux", "suse", "/etc/SuSE-release", /^opensuse/i)
272
173
 
273
- # slackware
274
- plat.name("slackware").title("Slackware Linux").in_family("linux")
275
- .detect do
276
- unless (raw = unix_file_contents("/etc/slackware-version")).nil?
277
- @platform[:release] = raw.scan(/(\d+|\.+)/).join
278
- true
279
- end
280
- end
174
+ declare_os_or_file("suse", "Suse Linux", "suse", "/etc/SuSE-release", /^sles/i, /suse/i)
281
175
 
282
- # gentoo
283
- plat.name("gentoo").title("Gentoo Linux").in_family("linux")
284
- .detect do
285
- unless (raw = unix_file_contents("/etc/gentoo-release")).nil?
286
- @platform[:release] = raw.scan(/(\d+|\.+)/).join
287
- true
288
- end
289
- end
176
+ declare_path_and_uname("arch", "Arch Linux", "linux", "/etc/arch-release")
290
177
 
291
- # exherbo
292
- plat.name("exherbo").title("Exherbo Linux").in_family("linux")
293
- .detect do
294
- unless unix_file_contents("/etc/exherbo-release").nil?
295
- # Because this is a rolling release distribution,
296
- # use the kernel release, ex. 4.1.6
297
- @platform[:release] = unix_uname_r
298
- true
299
- end
300
- end
178
+ declare_file_content("slackware", "Slackware Linux", "linux", "/etc/slackware-version")
301
179
 
302
- # alpine
303
- plat.name("alpine").title("Alpine Linux").in_family("linux")
304
- .detect do
305
- unless (raw = unix_file_contents("/etc/alpine-release")).nil?
306
- @platform[:release] = raw.strip
307
- true
308
- end
309
- end
180
+ declare_file_content("gentoo", "Gentoo Linux", "linux", "/etc/gentoo-release")
310
181
 
311
- # coreos
312
- plat.name("coreos").title("CoreOS Linux").in_family("linux")
313
- .detect do
314
- unless unix_file_contents("/etc/coreos/update.conf").nil?
315
- lsb = read_linux_lsb
316
- @platform[:release] = lsb[:release]
317
- true
318
- end
182
+ declare_path_and_uname("exherbo", "Exherbo Linux", "linux", "/etc/exherbo-release")
183
+
184
+ # TODO: try using declare_path
185
+ declare_instance("alpine", "Alpine Linux", "linux") do
186
+ if (raw = unix_file_contents("/etc/alpine-release"))
187
+ @platform[:release] = raw.strip
188
+ # TODO: no tests
189
+ true
319
190
  end
191
+ end
320
192
 
321
- # yocto family
322
- plat.family("yocto").in_family("linux")
323
- .detect do
324
- # /etc/issue isn't specific to yocto, but it's the only way to detect
325
- # the platform because there are no other identifying files
326
- if unix_file_contents("/etc/issue") &&
327
- (unix_file_contents("/etc/issue").match?("Poky") ||
328
- unix_file_contents("/etc/issue").match?("balenaOS"))
329
- true
330
- end
193
+ declare_instance("coreos", "CoreOS Linux", "linux") do
194
+ if unix_file_exist?("/etc/coreos/update.conf")
195
+ lsb = read_linux_lsb
196
+ @platform[:release] = lsb[:release]
197
+ true
331
198
  end
332
- plat.name("yocto").title("Yocto Project Linux").in_family("yocto")
333
- .detect do
334
- if unix_file_contents("/etc/issue").match?("Poky")
335
- # assuming the Poky version is preferred over the /etc/version build
336
- @platform[:release] = unix_file_contents("/etc/issue").match('\d+(\.\d+)+')[0]
337
- true
338
- end
199
+ end
200
+
201
+ declare_category("yocto", "linux") do
202
+ # /etc/issue isn't specific to yocto, but it's the only way to detect
203
+ # the platform because there are no other identifying files
204
+ issue = unix_file_contents("/etc/issue")
205
+
206
+ issue && issue.match?(/Poky|balenaOS/)
207
+ end
208
+
209
+ declare_instance("yocto", "Yocto Project Linux", "yocto") do
210
+ issue = unix_file_contents("/etc/issue")
211
+ if issue.match?("Poky")
212
+ # assuming the Poky version is preferred over the /etc/version build
213
+ @platform[:release] = issue[/\d+(\.\d+)+/]
214
+ true
339
215
  end
340
- plat.name("balenaos").title("balenaOS Linux").in_family("yocto")
341
- .detect do
342
- # balenaOS does have the /etc/os-release file
343
- if unix_file_contents("/etc/issue").match?("balenaOS") &&
344
- linux_os_release["NAME"] =~ /balenaos/i
345
- @platform[:release] = linux_os_release["META_BALENA_VERSION"]
346
- true
347
- end
216
+ end
217
+
218
+ declare_instance("balenaos", "balenaOS Linux", "yocto") do
219
+ # balenaOS does have the /etc/os-release file
220
+ issue = unix_file_contents("/etc/issue")
221
+ if issue.match?("balenaOS") && linux_os_release["NAME"] =~ /balenaos/i
222
+ @platform[:release] = linux_os_release["META_BALENA_VERSION"]
223
+ true
348
224
  end
225
+ end
349
226
 
350
227
  # brocade family detected here if device responds to 'uname' command,
351
228
  # happens when logging in as root
352
229
  plat.family("brocade").title("Brocade Family").in_family("linux")
353
230
  .detect do
354
- !brocade_version.nil?
231
+ # TODO: no tests
232
+ brocade_version
355
233
  end
356
234
 
357
- # generic linux
358
235
  # this should always be last in the linux family list
359
- plat.name("linux").title("Generic Linux").in_family("linux")
360
- .detect do
361
- true
362
- end
236
+ declare_instance("linux", "Generic Linux", "linux") do
237
+ true
238
+ end
239
+ end
363
240
 
364
- # openvms
365
- plat.name("openvms").title("OpenVMS").in_family("unix")
366
- .detect do
367
- if unix_uname_s =~ /unrecognized command verb/i
368
- cmd = @backend.run_command("show system/noprocess")
369
- unless cmd.exit_status != 0 || cmd.stdout.empty?
370
- @platform[:name] = cmd.stdout.downcase.split(" ")[0]
371
- cmd = @backend.run_command('write sys$output f$getsyi("VERSION")')
372
- @platform[:release] = cmd.stdout.downcase.split("\n")[1][1..-1]
373
- cmd = @backend.run_command('write sys$output f$getsyi("ARCH_NAME")')
374
- @platform[:arch] = cmd.stdout.downcase.split("\n")[1]
375
- true
376
- end
377
- end
378
- end
241
+ def self.load_other_unix
242
+ declare_instance("openvms", "OpenVMS", "unix") do
243
+ if unix_uname_s =~ /unrecognized command verb/i
244
+ # TODO: no tests
245
+ cmd = @backend.run_command("show system/noprocess")
379
246
 
380
- # aix
381
- plat.family("aix").in_family("unix")
382
- .detect do
383
- true if unix_uname_s =~ /aix/i
384
- end
385
- plat.name("aix").title("Aix").in_family("aix")
386
- .detect do
387
- out = @backend.run_command("uname -rvp").stdout
388
- m = out.match(/(\d+)\s+(\d+)\s+(.*)/)
389
- unless m.nil?
390
- @platform[:release] = "#{m[2]}.#{m[1]}"
391
- @platform[:arch] = m[3].to_s
247
+ if cmd.exit_status == 0 && !cmd.stdout.empty?
248
+ # TODO: no tests
249
+ @platform[:name] = cmd.stdout.downcase.split(" ")[0]
250
+ cmd = @backend.run_command('write sys$output f$getsyi("VERSION")')
251
+ @platform[:release] = cmd.stdout.downcase.split("\n")[1][1..-1]
252
+ cmd = @backend.run_command('write sys$output f$getsyi("ARCH_NAME")')
253
+ @platform[:arch] = cmd.stdout.downcase.split("\n")[1]
254
+ true
392
255
  end
393
- true
394
256
  end
257
+ end
395
258
 
396
- # solaris family
397
- plat.family("solaris").in_family("unix")
398
- .detect do
399
- if unix_uname_s =~ /sunos/i
400
- unless (version = /^5\.(?<release>\d+)$/.match(unix_uname_r)).nil?
401
- @platform[:release] = version["release"]
402
- end
259
+ declare_category("aix", "unix") do
260
+ unix_uname_s =~ /aix/i
261
+ end
403
262
 
404
- arch = @backend.run_command("uname -p")
405
- @platform[:arch] = arch.stdout.chomp if arch.exit_status == 0
406
- true
407
- end
408
- end
409
- plat.name("smartos").title("SmartOS").in_family("solaris")
410
- .detect do
411
- rel = unix_file_contents("/etc/release")
412
- if /^.*(SmartOS).*$/ =~ rel
413
- true
414
- end
415
- end
416
- plat.name("omnios").title("Omnios").in_family("solaris")
417
- .detect do
418
- rel = unix_file_contents("/etc/release")
419
- unless (m = /^\s*(OmniOS).*r(\d+).*$/.match(rel)).nil?
420
- @platform[:release] = m[2]
421
- true
422
- end
423
- end
424
- plat.name("openindiana").title("Openindiana").in_family("solaris")
425
- .detect do
426
- rel = unix_file_contents("/etc/release")
427
- unless (m = /^\s*(OpenIndiana).*oi_(\d+).*$/.match(rel)).nil?
428
- @platform[:release] = m[2]
429
- true
430
- end
263
+ declare_instance("aix", "Aix", "aix") do
264
+ out = @backend.run_command("uname -rvp").stdout
265
+ if out =~ /(\d+)\s+(\d+)\s+(.*)/
266
+ # TODO: no tests
267
+ @platform[:release] = "#{$2}.#{$1}"
268
+ @platform[:arch] = "#{$3}"
431
269
  end
432
- plat.name("opensolaris").title("Open Solaris").in_family("solaris")
433
- .detect do
434
- rel = unix_file_contents("/etc/release")
435
- unless (m = /^\s*(OpenSolaris).*snv_(\d+).*$/.match(rel)).nil?
436
- @platform[:release] = m[2]
437
- true
438
- end
439
- end
440
- plat.name("nexentacore").title("Nexentacore").in_family("solaris")
441
- .detect do
442
- rel = unix_file_contents("/etc/release")
443
- if /^\s*(NexentaCore)\s.*$/ =~ rel
444
- true
445
- end
446
- end
447
- plat.name("solaris").title("Solaris").in_family("solaris")
448
- .detect do
449
- rel = unix_file_contents("/etc/release")
450
- if !(m = /Oracle Solaris (\d+)/.match(rel)).nil?
451
- # TODO: should be string!
452
- @platform[:release] = m[1]
453
- true
454
- elsif /^\s*(Solaris)\s.*$/ =~ rel
455
- true
456
- end
270
+ true
271
+ end
457
272
 
458
- # must be some unknown solaris
459
- true
460
- end
273
+ declare_category("solaris", "unix") do
274
+ if unix_uname_s =~ /sunos/i
275
+ # TODO: no tests
461
276
 
462
- # hpux
463
- plat.family("hpux").in_family("unix")
464
- .detect do
465
- true if unix_uname_s =~ /hp-ux/i
466
- end
467
- plat.name("hpux").title("Hpux").in_family("hpux")
468
- .detect do
469
- @platform[:release] = unix_uname_r.lines[0].chomp
470
- true
471
- end
277
+ @platform[:release] = $1 if unix_uname_r =~ /^5\.(\d+)$/
472
278
 
473
- # qnx
474
- plat.family("qnx").in_family("unix")
475
- .detect do
476
- true if unix_uname_s =~ /qnx/i
477
- end
478
- plat.name("qnx").title("QNX").in_family("qnx")
479
- .detect do
480
- @platform[:name] = unix_uname_s.lines[0].chomp.downcase
481
- @platform[:release] = unix_uname_r.lines[0].chomp
482
- @platform[:arch] = unix_uname_m
279
+ arch = @backend.run_command("uname -p")
280
+ @platform[:arch] = arch.stdout.chomp if arch.exit_status == 0
483
281
  true
484
282
  end
283
+ end
485
284
 
486
- # bsd family
487
- plat.family("bsd").in_family("unix")
488
- .detect do
489
- # we need a better way to determine this family
490
- # for now we are going to just try each platform
285
+ # TODO: these regexps are probably needlessly wasteful
286
+ declare_path_regexp("smartos", "SmartOS", "solaris", "/etc/release", /^.*(SmartOS).*$/)
287
+
288
+ declare_path("omnios", "Omnios", "solaris", "/etc/release", /^\s*OmniOS.*r(\d+).*$/)
289
+ declare_path("openindiana", "Openindiana", "solaris", "/etc/release", /^\s*OpenIndiana.*oi_(\d+).*$/)
290
+
291
+ declare_path("opensolaris", "Open Solaris", "solaris", "/etc/release", /^\s*OpenSolaris.*snv_(\d+).*$/)
292
+
293
+ # TODO: these regexps are probably needlessly wasteful
294
+ declare_path_regexp("nexentacore", "Nexentacore", "solaris", "/etc/release", /^\s*(NexentaCore)\s.*$/)
295
+
296
+ declare_instance("solaris", "Solaris", "solaris") do
297
+ rel = unix_file_contents("/etc/release")
298
+ if rel =~ /Oracle Solaris (\d+)/
299
+ @platform[:release] = $1
300
+ # TODO: no tests
491
301
  true
492
- end
493
- plat.family("darwin").in_family("bsd")
494
- .detect do
495
- if unix_uname_s =~ /darwin/i
496
- cmd = unix_file_contents("/usr/bin/sw_vers")
497
- unless cmd.nil?
498
- m = cmd.match(/^ProductVersion:\s+(.+)$/)
499
- @platform[:release] = m.nil? ? nil : m[1]
500
- m = cmd.match(/^BuildVersion:\s+(.+)$/)
501
- @platform[:build] = m.nil? ? nil : m[1]
502
- end
503
- @platform[:release] = unix_uname_r.lines[0].chomp if @platform[:release].nil?
504
- @platform[:arch] = unix_uname_m
505
- true
506
- end
507
- end
508
- plat.name("mac_os_x").title("macOS X").in_family("darwin")
509
- .detect do
510
- cmd = unix_file_contents("/System/Library/CoreServices/SystemVersion.plist")
511
- @platform[:uuid_command] = "system_profiler SPHardwareDataType | awk '/UUID/ { print $3; }'"
512
- true if cmd =~ /Mac OS X/i
513
- end
514
- plat.name("darwin").title("Darwin").in_family("darwin")
515
- .detect do
516
- # must be some other type of darwin
517
- @platform[:name] = unix_uname_s.lines[0].chomp
302
+ elsif rel =~ /^\s*(Solaris)\s.*$/
303
+ # TODO: no tests
518
304
  true
519
305
  end
520
- plat.name("freebsd").title("Freebsd").in_family("bsd")
521
- .detect do
522
- if unix_uname_s =~ /freebsd/i
523
- @platform[:name] = unix_uname_s.lines[0].chomp
524
- @platform[:release] = unix_uname_r.lines[0].chomp
525
- true
526
- end
527
- end
528
- plat.name("openbsd").title("Openbsd").in_family("bsd")
529
- .detect do
530
- if unix_uname_s =~ /openbsd/i
531
- @platform[:name] = unix_uname_s.lines[0].chomp
532
- @platform[:release] = unix_uname_r.lines[0].chomp
533
- true
534
- end
535
- end
536
- plat.name("netbsd").title("Netbsd").in_family("bsd")
537
- .detect do
538
- if unix_uname_s =~ /netbsd/i
539
- @platform[:name] = unix_uname_s.lines[0].chomp
540
- @platform[:release] = unix_uname_r.lines[0].chomp
541
- true
542
- end
306
+
307
+ # TODO: no tests
308
+
309
+ # must be some unknown solaris
310
+ true
311
+ end
312
+
313
+ declare_category("hpux", "unix") do
314
+ unix_uname_s =~ /hp-ux/i
315
+ end
316
+
317
+ declare_instance("hpux", "Hpux", "hpux") do
318
+ @platform[:release] = unix_uname_r.lines[0].chomp
319
+ # TODO: no tests
320
+ true
321
+ end
322
+
323
+ declare_category("qnx", "unix") do
324
+ unix_uname_s =~ /qnx/i
325
+ end
326
+
327
+ declare_instance("qnx", "QNX", "qnx") do
328
+ # TODO: refactor these uname patterns
329
+ @platform[:name] = unix_uname_s.lines[0].chomp.downcase
330
+ @platform[:release] = unix_uname_r.lines[0].chomp
331
+ @platform[:arch] = unix_uname_m
332
+ true
333
+ end
334
+ end
335
+
336
+ def self.load_bsd
337
+ declare_category("bsd", "unix") do
338
+ # we need a better way to determine this family
339
+ # for now we are going to just try each platform
340
+ true
341
+ end
342
+
343
+ declare_category("darwin", "bsd") do
344
+ # rubocop:disable Layout/ExtraSpacing
345
+ # rubocop:disable Layout/SpaceAroundOperators
346
+ if unix_uname_s =~ /darwin/i
347
+ @platform[:release] ||= unix_uname_r.lines[0].chomp
348
+ @platform[:arch] = unix_uname_m
349
+ cmd = @backend.run_command("sw_vers -buildVersion")
350
+ @platform[:build] = cmd.stdout.chomp if cmd.exit_status == 0
351
+ true
543
352
  end
353
+ # rubocop:enable Layout/ExtraSpacing
354
+ # rubocop:enable Layout/SpaceAroundOperators
355
+ end
356
+
357
+ declare_instance("mac_os_x", "macOS X", "darwin") do
358
+ cmd = unix_file_contents("/System/Library/CoreServices/SystemVersion.plist")
359
+ @platform[:uuid_command] = "system_profiler SPHardwareDataType | awk '/UUID/ { print $3; }'"
360
+ cmd =~ /Mac OS X/i
361
+ end
362
+
363
+ declare_instance("darwin", "Darwin", "darwin") do
364
+ # must be some other type of darwin
365
+ @platform[:name] = unix_uname_s.lines[0].chomp
366
+ true
367
+ end
368
+
369
+ declare_bsd("freebsd", "Freebsd", "bsd", /freebsd/i)
370
+ declare_bsd("openbsd", "Openbsd", "bsd", /openbsd/i)
371
+ declare_bsd("netbsd", "Netbsd", "bsd", /netbsd/i)
372
+ end
544
373
 
545
- # arista_eos family
374
+ def self.load_other
546
375
  plat.family("arista_eos").title("Arista EOS Family").in_family("os")
547
376
  .detect do
548
377
  true
549
378
  end
550
- plat.name("arista_eos").title("Arista EOS").in_family("arista_eos")
551
- .detect do
552
- cmd = @backend.run_command("show version | json")
553
- if cmd.exit_status == 0 && !cmd.stdout.empty?
554
- require "json"
555
- begin
556
- eos_ver = JSON.parse(cmd.stdout)
557
- @platform[:release] = eos_ver["version"]
558
- @platform[:arch] = eos_ver["architecture"]
559
- true
560
- rescue JSON::ParserError
561
- nil
562
- end
563
- end
564
- end
565
379
 
566
- # esx
380
+ declare_instance("arista_eos", "Arista EOS", "arista_eos") do
381
+ json_cmd("show version | json")
382
+ end
383
+
567
384
  plat.family("esx").title("ESXi Family").in_family("os")
568
385
  .detect do
569
- true if unix_uname_s =~ /vmkernel/i
386
+ unix_uname_s =~ /vmkernel/i
570
387
  end
388
+
571
389
  plat.name("vmkernel").in_family("esx")
572
390
  .detect do
573
- @platform[:name] = unix_uname_s.lines[0].chomp
574
- @platform[:release] = unix_uname_r.lines[0].chomp
575
- true
391
+ # TODO: no tests
392
+ set_from_uname
576
393
  end
577
394
 
578
- # cisco_ios family
579
395
  plat.family("cisco").title("Cisco Family").in_family("os")
580
396
  .detect do
581
- !cisco_show_version.nil?
397
+ cisco_show_version
582
398
  end
583
- plat.name("cisco_ios").title("Cisco IOS").in_family("cisco")
584
- .detect do
585
- v = cisco_show_version
586
- next unless v[:type] == "ios"
587
399
 
588
- @platform[:release] = v[:version]
589
- @platform[:arch] = nil
590
- true
591
- end
592
- plat.name("cisco_ios_xe").title("Cisco IOS XE").in_family("cisco")
400
+ declare_cisco("cisco_ios", "Cisco IOS", "cisco", :cisco_show_version, "ios")
401
+ declare_cisco("cisco_ios_xe", "Cisco IOS XE", "cisco", :cisco_show_version, "ios-xe")
402
+ declare_cisco("cisco_nexus", "Cisco Nexus", "cisco", :cisco_show_version, "nexus", "show version | include Processor")
403
+
404
+ plat.family("brocade").title("Brocade Family").in_family("os")
593
405
  .detect do
594
- v = cisco_show_version
595
- next unless v[:type] == "ios-xe"
406
+ brocade_version
407
+ end
408
+
409
+ declare_cisco("brocade_fos", "Brocade FOS", "brocade", :brocade_version, "fos")
410
+ end
411
+
412
+ ######################################################################
413
+ # Helpers (keep these sorted)
414
+
415
+ def self.plat
416
+ Train::Platforms
417
+ end
418
+
419
+ def self.declare_category(family, parent, &block)
420
+ plat.family(family).in_family(parent).detect(&block)
421
+ end
422
+
423
+ def self.declare_family(name, title = nil, family, &block)
424
+ thingy = plat.name(name).in_family(family)
425
+ thingy.title(title) if title
426
+ thingy.detect(&block)
427
+ end
428
+
429
+ def self.declare_instance(name, title, family, &block)
430
+ plat.name(name).title(title).in_family(family).detect(&block)
431
+ end
432
+
433
+ def self.declare_bsd(name, title, family, regexp)
434
+ declare_instance(name, title, family) do
435
+ # TODO: no tests
436
+ set_from_uname if unix_uname_s =~ regexp
437
+ end
438
+ end
439
+
440
+ def self.declare_cisco(name, title, family, detect, type, uuid = nil)
441
+ declare_instance(name, title, family) do
442
+ v = send(detect)
443
+
444
+ next unless v[:type] == type
596
445
 
597
- @platform[:release] = v[:version]
598
- @platform[:arch] = nil
446
+ @platform[:release] = v[:version]
447
+ @platform[:arch] = nil
448
+ @platform[:uuid_command] = uuid if uuid
449
+ true
450
+ end
451
+ end
452
+
453
+ def self.declare_file_content(name, title, family, path)
454
+ declare_instance(name, title, family) do
455
+ if (raw = unix_file_contents(path))
456
+ # TODO: no tests
457
+ @platform[:release] = raw.scan(/[\d.]+/).join
599
458
  true
600
459
  end
601
- plat.name("cisco_nexus").title("Cisco Nexus").in_family("cisco")
602
- .detect do
603
- v = cisco_show_version
604
- next unless v[:type] == "nexus"
460
+ end
461
+ end
605
462
 
606
- @platform[:release] = v[:version]
607
- @platform[:arch] = nil
608
- @platform[:uuid_command] = "show version | include Processor"
463
+ def self.declare_lsb(name, title, family, regexp)
464
+ declare_lsb_or_content(name, title, family, nil, regexp)
465
+ end
466
+
467
+ def self.declare_lsb_or_content(name, title, family, path, regexp1, regexp2 = regexp1)
468
+ declare_instance(name, title, family) do
469
+ lsb = read_linux_lsb
470
+ if lsb && lsb[:id] =~ regexp1
471
+ @platform[:release] = lsb[:release]
472
+ true
473
+ elsif path && (raw = unix_file_contents(path)) =~ regexp2
474
+ @platform[:name] = redhatish_platform(raw)
475
+ @platform[:release] = redhatish_version(raw)
609
476
  true
610
477
  end
478
+ end
479
+ end
611
480
 
612
- # brocade family
613
- plat.family("brocade").title("Brocade Family").in_family("os")
614
- .detect do
615
- !brocade_version.nil?
616
- end
481
+ def self.declare_os_or_file(name, title, family, path, regexp1, regexp2 = regexp1)
482
+ declare_instance(name, title, family) do
483
+ rel = linux_os_release
484
+ (rel && rel["NAME"] =~ regexp1) ||
485
+ unix_file_contents(path) =~ regexp2
486
+ end
487
+ end
617
488
 
618
- plat.name("brocade_fos").title("Brocade FOS").in_family("brocade")
619
- .detect do
620
- v = brocade_version
621
- next unless v[:type] == "fos"
489
+ def self.declare_path(name, title, family, path, regexp)
490
+ declare_instance(name, title, family) do
491
+ rel = unix_file_contents(path)
492
+ if rel =~ regexp
493
+ # TODO: no tests
494
+ @platform[:release] = $1
495
+ true
496
+ end
497
+ end
498
+ end
622
499
 
623
- @platform[:release] = v[:version]
624
- @platform[:arch] = nil
500
+ def self.declare_path_and_uname(name, title, family, path)
501
+ declare_instance(name, title, family) do
502
+ if unix_file_exist?(path)
503
+ # Because this is a rolling release distribution,
504
+ # use the kernel release, ex. 4.1.6-1-ARCH
505
+ # TODO: unix_uname_r.lines[0].chomp ? -- no tests for /etc/exherbo-release or /etc/arch-release
506
+ @platform[:release] = unix_uname_r
625
507
  true
626
508
  end
509
+ end
510
+ end
511
+
512
+ def self.declare_path_regexp(name, title, family, path, regexp)
513
+ declare_instance(name, title, family) do
514
+ # TODO: no tests
515
+ regexp =~ unix_file_contents(path)
516
+ end
627
517
  end
628
518
  end
629
519
  end