machinery-tool 1.16.4 → 1.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.git_revision +1 -1
- data/NEWS +10 -0
- data/filters/default_filters.json +21 -20
- data/html/assets/machinery-base.js +4 -0
- data/html/index.html.haml +1 -1
- data/html/partials/changed_managed_files.html.haml +2 -2
- data/html/partials/compare/changed_managed_file_list.html.haml +2 -2
- data/html/partials/compare/changed_managed_files.html.haml +3 -3
- data/html/partials/compare/config_file_list.html.haml +2 -2
- data/html/partials/compare/config_files.html.haml +3 -3
- data/html/partials/compare/packages.html.haml +21 -4
- data/html/partials/compare/repositories.html.haml +10 -7
- data/html/partials/compare/repository_list_apt.html.haml +15 -0
- data/html/partials/compare/repository_list_yum.html.haml +35 -0
- data/html/partials/compare/{repository_list.html.haml → repository_list_zypp.html.haml} +0 -0
- data/html/partials/compare/service_list.html.haml +1 -1
- data/html/partials/compare/services.html.haml +3 -3
- data/html/partials/compare/unmanaged_file_list.html.haml +2 -2
- data/html/partials/compare/unmanaged_files.html.haml +1 -1
- data/html/partials/config_files.html.haml +39 -41
- data/html/partials/repositories.html.haml +1 -23
- data/html/partials/repositories_apt.html.haml +15 -0
- data/html/partials/repositories_yum.html.haml +30 -0
- data/html/partials/repositories_zypp.html.haml +24 -0
- data/html/partials/services.html.haml +2 -2
- data/html/partials/unmanaged_files.html.haml +2 -2
- data/inspect_helpers/dpkg_unmanaged_files.sh +47 -0
- data/inspect_helpers/yum_repositories.py +3 -5
- data/lib/analyze_config_file_diffs_task.rb +11 -1
- data/lib/array.rb +97 -35
- data/lib/autoyast.rb +13 -2
- data/lib/cli.rb +10 -2
- data/lib/config.rb +4 -4
- data/lib/dpkg_database.rb +68 -0
- data/lib/element_filter.rb +2 -0
- data/lib/file_diff.rb +2 -2
- data/lib/file_scope.rb +10 -49
- data/lib/file_validator.rb +10 -4
- data/lib/filter.rb +6 -6
- data/lib/filter_option_parser.rb +1 -1
- data/lib/kiwi_config.rb +13 -10
- data/lib/machinery.rb +2 -0
- data/lib/machinery_helper.rb +1 -1
- data/lib/managed_files_database.rb +200 -0
- data/lib/object.rb +5 -3
- data/lib/remote_system.rb +43 -10
- data/lib/renderer.rb +3 -4
- data/lib/rpm_database.rb +7 -183
- data/lib/scope_file_access_archive.rb +3 -3
- data/lib/scope_file_access_flat.rb +1 -1
- data/lib/server.rb +7 -2
- data/lib/system.rb +50 -22
- data/lib/system_description.rb +3 -3
- data/lib/version.rb +1 -1
- data/lib/workload_mapper.rb +2 -2
- data/machinery-helper/machinery_helper.go +252 -178
- data/machinery-helper/machinery_helper_test.go +121 -121
- data/machinery-helper/mountpoints.go +28 -28
- data/machinery-helper/tar.go +105 -104
- data/machinery-helper/version.go +1 -1
- data/man/generated/machinery.1.gz +0 -0
- data/man/generated/machinery.1.html +19 -8
- data/plugins/changed_managed_files/changed_managed_files_inspector.rb +3 -3
- data/plugins/changed_managed_files/changed_managed_files_model.rb +3 -1
- data/plugins/changed_managed_files/changed_managed_files_renderer.rb +2 -2
- data/plugins/changed_managed_files/schema/system-description-changed-managed-files.schema-v6.json +168 -0
- data/plugins/config_files/config_files_inspector.rb +4 -4
- data/plugins/config_files/config_files_model.rb +3 -1
- data/plugins/config_files/config_files_renderer.rb +2 -2
- data/plugins/config_files/schema/system-description-config-files.schema-v6.json +160 -0
- data/plugins/environment/schema/system-description-environment.schema-v6.json +17 -0
- data/plugins/groups/schema/system-description-groups.schema-v6.json +49 -0
- data/plugins/os/schema/system-description-os.schema-v6.json +21 -0
- data/plugins/packages/packages_inspector.rb +76 -6
- data/plugins/packages/packages_model.rb +31 -12
- data/plugins/packages/packages_renderer.rb +5 -2
- data/plugins/packages/schema/system-description-packages.schema-v6.json +115 -0
- data/plugins/patterns/patterns_inspector.rb +26 -2
- data/plugins/patterns/schema/system-description-patterns.schema-v6.json +58 -0
- data/plugins/repositories/repositories_inspector.rb +41 -14
- data/plugins/repositories/repositories_model.rb +55 -12
- data/plugins/repositories/repositories_renderer.rb +23 -7
- data/plugins/repositories/schema/system-description-repositories.schema-v6.json +165 -0
- data/plugins/services/schema/system-description-services.schema-v6.json +93 -0
- data/plugins/services/services_inspector.rb +88 -22
- data/plugins/services/services_model.rb +9 -15
- data/plugins/services/services_renderer.rb +2 -2
- data/plugins/unmanaged_files/schema/system-description-unmanaged-files.schema-v6.json +162 -0
- data/plugins/unmanaged_files/unmanaged_files_inspector.rb +80 -30
- data/plugins/unmanaged_files/unmanaged_files_model.rb +22 -18
- data/plugins/unmanaged_files/unmanaged_files_renderer.rb +3 -3
- data/plugins/users/schema/system-description-users.schema-v6.json +86 -0
- data/schema/migrations/migrate5to6.rb +101 -0
- data/schema/system-description-global.schema-v6.json +43 -0
- metadata +24 -4
- data/html/assets/landing_page/landing_page.js +0 -10
data/lib/object.rb
CHANGED
@@ -29,10 +29,12 @@ module Machinery
|
|
29
29
|
value.is_a?(property_class) ? value : property_class.from_json(value)
|
30
30
|
else
|
31
31
|
case value
|
32
|
-
when ::Array
|
33
|
-
Machinery::Array.from_json(value)
|
34
32
|
when Hash
|
35
|
-
|
33
|
+
if value.keys.include?("_elements")
|
34
|
+
Machinery::Array.from_json(value)
|
35
|
+
else
|
36
|
+
Machinery::Object.from_json(value)
|
37
|
+
end
|
36
38
|
else
|
37
39
|
value
|
38
40
|
end
|
data/lib/remote_system.rb
CHANGED
@@ -16,16 +16,23 @@
|
|
16
16
|
# you may find current contact information at www.suse.com
|
17
17
|
|
18
18
|
class RemoteSystem < System
|
19
|
-
|
20
|
-
attr_accessor :remote_user
|
19
|
+
attr_reader :host, :remote_user, :ssh_port, :ssh_identity_file
|
21
20
|
|
22
21
|
def type
|
23
22
|
"remote"
|
24
23
|
end
|
25
24
|
|
26
|
-
def initialize(host,
|
25
|
+
def initialize(host, opts = {})
|
26
|
+
options = {
|
27
|
+
remote_user: "root",
|
28
|
+
ssh_port: nil,
|
29
|
+
ssh_identity_file: nil
|
30
|
+
}.merge(opts)
|
31
|
+
|
27
32
|
@host = host
|
28
|
-
@remote_user = remote_user
|
33
|
+
@remote_user = options[:remote_user]
|
34
|
+
@ssh_port = options[:ssh_port]
|
35
|
+
@ssh_identity_file = options[:ssh_identity_file]
|
29
36
|
|
30
37
|
connect
|
31
38
|
end
|
@@ -78,12 +85,13 @@ class RemoteSystem < System
|
|
78
85
|
|
79
86
|
sudo = ["sudo", "-n"] if options[:privileged] && remote_user != "root"
|
80
87
|
cmds = [
|
81
|
-
|
82
|
-
"LC_ALL=#{locale}", *piped_args, options
|
88
|
+
*build_command(:ssh), "#{remote_user}@#{host}", "-o", \
|
89
|
+
"LogLevel=ERROR", sudo, "LANGUAGE=", "LC_ALL=#{locale}", *piped_args, options
|
83
90
|
].compact.flatten
|
91
|
+
|
84
92
|
cheetah_class.run(*cmds)
|
85
93
|
rescue Cheetah::ExecutionFailed => e
|
86
|
-
if e.stderr.include?("password is required")
|
94
|
+
if e.stderr && e.stderr.include?("password is required")
|
87
95
|
raise Machinery::Errors::InsufficientPrivileges.new(remote_user, host)
|
88
96
|
else
|
89
97
|
raise e
|
@@ -93,7 +101,8 @@ class RemoteSystem < System
|
|
93
101
|
# Tries to run the noop-command(:) on the remote system as root (without a password or passphrase)
|
94
102
|
# and raises an Machinery::Errors::SshConnectionFailed exception when it's not successful.
|
95
103
|
def connect
|
96
|
-
LoggedCheetah.run
|
104
|
+
LoggedCheetah.run(*build_command(:ssh), "-q", "-o", "BatchMode=yes",
|
105
|
+
"#{remote_user}@#{host}", ":")
|
97
106
|
rescue Cheetah::ExecutionFailed
|
98
107
|
raise Machinery::Errors::SshConnectionFailed.new(
|
99
108
|
"Could not establish SSH connection to host '#{host}'. Please make sure that " \
|
@@ -117,7 +126,7 @@ class RemoteSystem < System
|
|
117
126
|
|
118
127
|
cmd = [
|
119
128
|
"rsync",
|
120
|
-
"-e",
|
129
|
+
"-e", build_command(:ssh).join(" "),
|
121
130
|
"--chmod=go-rwx",
|
122
131
|
"--files-from=-",
|
123
132
|
"--rsync-path=#{rsync_path}",
|
@@ -153,7 +162,7 @@ class RemoteSystem < System
|
|
153
162
|
destination = "#{remote_user}@#{host}:#{destination}"
|
154
163
|
|
155
164
|
cmd = [
|
156
|
-
|
165
|
+
*build_command(:scp),
|
157
166
|
source,
|
158
167
|
destination
|
159
168
|
]
|
@@ -175,4 +184,28 @@ class RemoteSystem < System
|
|
175
184
|
"Could not remove file '#{file}' on host '#{host}'.\nError: #{e}"
|
176
185
|
)
|
177
186
|
end
|
187
|
+
|
188
|
+
private
|
189
|
+
|
190
|
+
def build_command(name)
|
191
|
+
raise Machinery::Errors::MachineryError.new("You must set one of these flags in " \
|
192
|
+
"build_command: :ssh or :scp") unless [:ssh, :scp].include?(name)
|
193
|
+
|
194
|
+
command = [name.to_s]
|
195
|
+
|
196
|
+
if name == :ssh && @ssh_port
|
197
|
+
command.push("-p")
|
198
|
+
command.push(@ssh_port.to_s)
|
199
|
+
elsif name == :scp && @ssh_port
|
200
|
+
command.push("-P")
|
201
|
+
command.push(@ssh_port.to_s)
|
202
|
+
end
|
203
|
+
|
204
|
+
if @ssh_identity_file
|
205
|
+
command.push("-i")
|
206
|
+
command.push(@ssh_identity_file)
|
207
|
+
end
|
208
|
+
|
209
|
+
command
|
210
|
+
end
|
178
211
|
end
|
data/lib/renderer.rb
CHANGED
@@ -147,7 +147,7 @@ class Renderer
|
|
147
147
|
end
|
148
148
|
|
149
149
|
def render_comparison_only_in(description)
|
150
|
-
return if !description[scope]
|
150
|
+
return if !description[scope] || description[scope].elements.try(:empty?)
|
151
151
|
|
152
152
|
puts "Only in '#{description.name}':"
|
153
153
|
indent { compare_content_only_in(description) }
|
@@ -208,7 +208,7 @@ class Renderer
|
|
208
208
|
print_indented "#{s}"
|
209
209
|
end
|
210
210
|
|
211
|
-
def list(name = nil, &block)
|
211
|
+
def list(name = nil, options = {}, &block)
|
212
212
|
unless block_given?
|
213
213
|
raise InvalidStructureError.new(
|
214
214
|
"'list' was called without a block"
|
@@ -217,7 +217,6 @@ class Renderer
|
|
217
217
|
|
218
218
|
@stack << :list
|
219
219
|
|
220
|
-
|
221
220
|
if name && !name.empty?
|
222
221
|
print_indented "#{name}:"
|
223
222
|
indent do
|
@@ -226,7 +225,7 @@ class Renderer
|
|
226
225
|
else
|
227
226
|
block.call
|
228
227
|
end
|
229
|
-
@buffer += "\n" unless @buffer.end_with?("\n\n")
|
228
|
+
@buffer += "\n" unless @buffer.end_with?("\n\n") || options[:sublist]
|
230
229
|
|
231
230
|
@stack.pop
|
232
231
|
end
|
data/lib/rpm_database.rb
CHANGED
@@ -15,193 +15,17 @@
|
|
15
15
|
# To contact SUSE about this file by physical or electronic mail,
|
16
16
|
# you may find current contact information at www.suse.com
|
17
17
|
|
18
|
-
class RpmDatabase
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
def initialize(type, attrs)
|
23
|
-
super(attrs)
|
24
|
-
@type = type
|
25
|
-
end
|
26
|
-
|
27
|
-
def config_file?
|
28
|
-
@type == "c"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize(system)
|
33
|
-
@system = system
|
34
|
-
end
|
35
|
-
|
36
|
-
def changed_files(&block)
|
37
|
-
return @changed_files if @changed_files
|
38
|
-
check_requirements
|
39
|
-
|
40
|
-
out = @system.run_script_with_progress("changed_files.sh", &block)
|
41
|
-
result = out.each_line.map do |line|
|
42
|
-
line.chomp!
|
43
|
-
next unless line.match(/^[^ ]+[ ]+. \/.*$/)
|
44
|
-
|
45
|
-
file, changes, type = parse_rpm_changes_line(line)
|
46
|
-
|
47
|
-
package = @system.run_command("rpm", "-qf", file, stdout: :capture).split.first
|
48
|
-
package_name, package_version = package.scan(/(.*)-([^-]*)-[^-]/).first
|
49
|
-
|
50
|
-
ChangedFile.new(
|
51
|
-
type,
|
52
|
-
name: file,
|
53
|
-
package_name: package_name,
|
54
|
-
package_version: package_version,
|
55
|
-
status: "changed",
|
56
|
-
changes: changes
|
57
|
-
)
|
58
|
-
end.compact.uniq
|
59
|
-
|
60
|
-
paths = result.reject { |f| f.changes == Machinery::Array.new(["deleted"]) }.map(&:name)
|
61
|
-
path_data = get_path_data(paths)
|
62
|
-
result.each do |pkg|
|
63
|
-
next unless path_data[pkg.name]
|
64
|
-
|
65
|
-
path_data[pkg.name].each do |key, value|
|
66
|
-
pkg[key] = value
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
@changed_files = result
|
71
|
-
end
|
72
|
-
|
73
|
-
def expected_tag?(character, position)
|
74
|
-
if @rpm_changes[position] == character
|
75
|
-
true
|
76
|
-
else
|
77
|
-
@unknown_tag ||= ![".", "?"].include?(@rpm_changes[position])
|
78
|
-
false
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def parse_rpm_changes_line(line)
|
83
|
-
# rpm provides lines per config file where first 9 characters indicate which
|
84
|
-
# properties of the file are modified
|
85
|
-
@rpm_changes, *fields = line.split(" ")
|
86
|
-
# nine rpm changes are known
|
87
|
-
@unknown_tag = @rpm_changes.size > 9
|
88
|
-
|
89
|
-
# For config or documentation files there's an additional field which
|
90
|
-
# contains "c" or "d"
|
91
|
-
type = fields[0].start_with?("/") ? "" : fields.shift
|
92
|
-
path = fields.join(" ")
|
93
|
-
|
94
|
-
changes = []
|
95
|
-
if @rpm_changes == "missing"
|
96
|
-
changes << "deleted"
|
97
|
-
elsif @rpm_changes == "........." && path.end_with?(" (replaced)")
|
98
|
-
changes << "replaced"
|
99
|
-
path.slice!(/ \(replaced\)$/)
|
100
|
-
else
|
101
|
-
changes << "size" if expected_tag?("S", 0)
|
102
|
-
changes << "mode" if expected_tag?("M", 1)
|
103
|
-
changes << "md5" if expected_tag?("5", 2)
|
104
|
-
changes << "device_number" if expected_tag?("D", 3)
|
105
|
-
changes << "link_path" if expected_tag?("L", 4)
|
106
|
-
changes << "user" if expected_tag?("U", 5)
|
107
|
-
changes << "group" if expected_tag?("G", 6)
|
108
|
-
changes << "time" if expected_tag?("T", 7)
|
109
|
-
changes << "capabilities" if @rpm_changes.size > 8 && expected_tag?("P", 8)
|
110
|
-
end
|
111
|
-
|
112
|
-
if @unknown_tag
|
113
|
-
changes << "other_rpm_changes"
|
114
|
-
end
|
115
|
-
|
116
|
-
if @rpm_changes.include?("?")
|
117
|
-
message = "Could not perform all tests on rpm changes for file '#{path}'."
|
118
|
-
Machinery.logger.warn(message)
|
119
|
-
Machinery::Ui.warn("Warning: #{message}")
|
120
|
-
end
|
121
|
-
|
122
|
-
[path, changes, type]
|
123
|
-
end
|
124
|
-
|
125
|
-
def parse_stat_line(line)
|
126
|
-
mode, user, group, uid, gid, type, *path_line = line.split(":")
|
127
|
-
path = path_line.join(":").chomp
|
128
|
-
|
129
|
-
user = uid if user == "UNKNOWN"
|
130
|
-
group = gid if group == "UNKNOWN"
|
131
|
-
|
132
|
-
type = case type
|
133
|
-
when "directory"
|
134
|
-
"dir"
|
135
|
-
when "symbolic link"
|
136
|
-
"link"
|
137
|
-
when /file$/
|
138
|
-
"file"
|
139
|
-
else
|
140
|
-
raise(
|
141
|
-
"The inspection failed because of the unknown type `#{type}` of file `#{path}`."
|
142
|
-
)
|
143
|
-
end
|
144
|
-
|
145
|
-
[path,
|
146
|
-
{
|
147
|
-
mode: mode,
|
148
|
-
user: user,
|
149
|
-
group: group,
|
150
|
-
type: type
|
151
|
-
}
|
152
|
-
]
|
153
|
-
end
|
154
|
-
|
155
|
-
def get_link_target(link)
|
156
|
-
@system.run_command(
|
157
|
-
"find", link, "-prune", "-printf", "%l",
|
158
|
-
stdout: :capture,
|
159
|
-
privileged: true
|
160
|
-
).strip
|
161
|
-
end
|
162
|
-
|
163
|
-
# get path data for list of files
|
164
|
-
# cur_files is guaranteed to not exceed max command line length
|
165
|
-
def get_file_properties(cur_files)
|
166
|
-
ret = {}
|
167
|
-
out = @system.run_command(
|
168
|
-
"stat", "--printf", "%a:%U:%G:%u:%g:%F:%n\\n",
|
169
|
-
*cur_files,
|
170
|
-
stdout: :capture,
|
171
|
-
privileged: true
|
172
|
-
)
|
173
|
-
out.each_line do |l|
|
174
|
-
path, values = parse_stat_line(l)
|
175
|
-
ret[path] = values
|
176
|
-
ret[path][:target] = get_link_target(path) if values[:type] == "link"
|
177
|
-
end
|
178
|
-
ret
|
18
|
+
class RpmDatabase < ManagedFilesDatabase
|
19
|
+
def managed_files_list(&block)
|
20
|
+
@system.run_script_with_progress("changed_files.sh", &block)
|
179
21
|
end
|
180
22
|
|
181
|
-
def
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
max_len = 50000
|
186
|
-
cur_files = []
|
187
|
-
cur_len = 0
|
188
|
-
while path_index < paths.size
|
189
|
-
if cur_files.empty? || paths[path_index].size + cur_len + 1 < max_len
|
190
|
-
cur_files << paths[path_index]
|
191
|
-
cur_len += paths[path_index].size + 1
|
192
|
-
path_index += 1
|
193
|
-
else
|
194
|
-
ret.merge!(get_file_properties(cur_files))
|
195
|
-
cur_files.clear
|
196
|
-
cur_len = 0
|
197
|
-
end
|
198
|
-
end
|
199
|
-
ret.merge!(get_file_properties(cur_files)) unless cur_files.empty?
|
200
|
-
ret
|
23
|
+
def package_for_file_path(file)
|
24
|
+
package = @system.run_command("rpm", "-qf", file, stdout: :capture).split.first
|
25
|
+
package_name, package_version = package.scan(/(.*)-([^-]*)-[^-]/).first
|
26
|
+
[package_name, package_version]
|
201
27
|
end
|
202
28
|
|
203
|
-
private
|
204
|
-
|
205
29
|
def check_requirements
|
206
30
|
@system.check_requirement("rpm", "--version")
|
207
31
|
@system.check_requirement("stat", "--version")
|
@@ -22,7 +22,7 @@ module ScopeFileAccessArchive
|
|
22
22
|
FileUtils.cp(File.join(scope_file_store.path, "files.tgz"), destination)
|
23
23
|
|
24
24
|
target = File.join(destination, "trees")
|
25
|
-
|
25
|
+
self.select(&:directory?).each do |system_file|
|
26
26
|
raise Machinery::Errors::FileUtilsError if !system_file.directory?
|
27
27
|
|
28
28
|
tarball_target = File.join(target, File.dirname(system_file.name))
|
@@ -33,8 +33,8 @@ module ScopeFileAccessArchive
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def has_file?(name)
|
36
|
-
return true if
|
37
|
-
if
|
36
|
+
return true if any? { |file| file.name == name }
|
37
|
+
if any? { |file| file.name == File.join(File.dirname(name), "") }
|
38
38
|
tgz_file = File.join(scope_file_store.path, "trees", "#{File.dirname(name)}.tgz")
|
39
39
|
return Cheetah.run("tar", "ztf", tgz_file, stdout: :capture).split(/\n/).
|
40
40
|
any? { |f| "/#{f}" == name }
|
data/lib/server.rb
CHANGED
@@ -88,6 +88,11 @@ class Server < Sinatra::Base
|
|
88
88
|
object.length.to_s + " " + Machinery.pluralize(object.length, singular, plural)
|
89
89
|
end
|
90
90
|
|
91
|
+
def repository_changes
|
92
|
+
klass = @diff["repositories"].changed.first.first.class
|
93
|
+
changed_elements("repositories", attributes: klass.attributes, key: klass.key)
|
94
|
+
end
|
95
|
+
|
91
96
|
def changed_elements(scope, opts)
|
92
97
|
optional_attributes = opts[:optional_attributes] || []
|
93
98
|
|
@@ -199,7 +204,7 @@ class Server < Sinatra::Base
|
|
199
204
|
description = SystemDescription.load(params[:id], settings.system_description_store)
|
200
205
|
filename = File.join("/", params["splat"].first)
|
201
206
|
|
202
|
-
file = description[params[:scope]].
|
207
|
+
file = description[params[:scope]].find { |f| f.name == filename }
|
203
208
|
|
204
209
|
if request.accept.first.to_s == "text/plain" && file.binary?
|
205
210
|
status 406
|
@@ -298,7 +303,7 @@ class Server < Sinatra::Base
|
|
298
303
|
diffs_dir = @description.scope_file_store("analyze/config_file_diffs").path
|
299
304
|
if @description.config_files && diffs_dir
|
300
305
|
# Enrich description with the config file diffs
|
301
|
-
@description.config_files.
|
306
|
+
@description.config_files.each do |file|
|
302
307
|
path = File.join(diffs_dir, file.name + ".diff")
|
303
308
|
file.diff = diff_to_object(File.read(path)) if File.exists?(path)
|
304
309
|
end
|
data/lib/system.rb
CHANGED
@@ -33,9 +33,9 @@ class System
|
|
33
33
|
|
34
34
|
attr_writer :locale
|
35
35
|
|
36
|
-
def self.for(host,
|
36
|
+
def self.for(host, opts = {})
|
37
37
|
if host && host != "localhost"
|
38
|
-
RemoteSystem.new(host,
|
38
|
+
RemoteSystem.new(host, opts)
|
39
39
|
else
|
40
40
|
LocalSystem.new
|
41
41
|
end
|
@@ -113,14 +113,61 @@ class System
|
|
113
113
|
# Machinery::Ui.progress("Found #{count} changed files...")
|
114
114
|
# end
|
115
115
|
def run_script_with_progress(*script, &callback)
|
116
|
+
run_with_progress(*script, :script, &callback)
|
117
|
+
end
|
118
|
+
|
119
|
+
def run_command_with_progress(*command, &callback)
|
120
|
+
run_with_progress(*command, :command, &callback)
|
121
|
+
end
|
122
|
+
|
123
|
+
def has_command?(command)
|
124
|
+
run_command("bash", "-c", "type -P #{command}", stdout: :capture)
|
125
|
+
true
|
126
|
+
rescue Cheetah::ExecutionFailed
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
def arch
|
131
|
+
run_command("uname", "-m", stdout: :capture).chomp
|
132
|
+
end
|
133
|
+
|
134
|
+
def locale
|
135
|
+
@locale || "C"
|
136
|
+
end
|
137
|
+
|
138
|
+
def managed_files_database
|
139
|
+
if @managed_files_database
|
140
|
+
return @managed_files_database
|
141
|
+
elsif has_command?("rpm")
|
142
|
+
@managed_files_database = RpmDatabase.new(self)
|
143
|
+
elsif has_command?("dpkg")
|
144
|
+
@managed_files_database = DpkgDatabase.new(self)
|
145
|
+
else
|
146
|
+
raise Machinery::Errors::MissingRequirement.new(
|
147
|
+
"Need binary 'rpm' or 'dpkg' to be available on the inspected system."
|
148
|
+
)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def run_with_progress(*command, type, &callback)
|
116
155
|
output = ""
|
117
156
|
error = ""
|
118
157
|
write_io = StringIO.new(output, "a")
|
119
158
|
error_io = StringIO.new(error, "a")
|
120
159
|
read_io = StringIO.new(output, "r")
|
121
160
|
|
161
|
+
options = command.last.is_a?(Hash) ? command.pop : {}
|
162
|
+
options[:stdout] = write_io
|
163
|
+
options[:stderr] = error_io
|
164
|
+
|
122
165
|
inspect_thread = Thread.new do
|
123
|
-
|
166
|
+
if type == :script
|
167
|
+
run_script(*command, options)
|
168
|
+
else
|
169
|
+
run_command(*command, options)
|
170
|
+
end
|
124
171
|
end
|
125
172
|
|
126
173
|
while inspect_thread.alive?
|
@@ -135,23 +182,4 @@ class System
|
|
135
182
|
|
136
183
|
output
|
137
184
|
end
|
138
|
-
|
139
|
-
def has_command?(command)
|
140
|
-
run_command("bash", "-c", "type -P #{command}", stdout: :capture)
|
141
|
-
true
|
142
|
-
rescue Cheetah::ExecutionFailed
|
143
|
-
false
|
144
|
-
end
|
145
|
-
|
146
|
-
def arch
|
147
|
-
run_command("uname", "-m", stdout: :capture).chomp
|
148
|
-
end
|
149
|
-
|
150
|
-
def locale
|
151
|
-
@locale || "C"
|
152
|
-
end
|
153
|
-
|
154
|
-
def rpm_database
|
155
|
-
@rpm_database ||= RpmDatabase.new(self)
|
156
|
-
end
|
157
185
|
end
|