machinery-tool 1.11.1 → 1.11.2
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 +4 -4
- data/NEWS +6 -0
- data/lib/build_task.rb +1 -2
- data/lib/cli.rb +12 -7
- data/lib/compare_task.rb +1 -3
- data/lib/config.rb +4 -2
- data/lib/config_base.rb +8 -10
- data/lib/deploy_task.rb +1 -1
- data/lib/exceptions.rb +1 -0
- data/lib/html.rb +18 -209
- data/lib/inspector.rb +4 -1
- data/lib/local_system.rb +33 -9
- data/lib/machinery.rb +4 -1
- data/lib/server.rb +181 -0
- data/lib/show_task.rb +1 -3
- data/lib/version.rb +1 -1
- data/man/generated/machinery.1.gz +0 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5d39b671ef2bf800e50ffe8cb48003f1ad6cf50
|
4
|
+
data.tar.gz: a5f739eb08389646bd1d6e8d26ee29d6f21b1595
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1992072db448872c81e4179fa7f2a7518179ecf15f12c433b9cd0f6c6a1811bdb4e7f68b4776ea69ac649fcdf8b5c813af213aa7e786f40d0cb02638f2462d1e
|
7
|
+
data.tar.gz: 651d2cfa1150a857ca265db080d113d61f845c8ed2cfdaeb626b81b058b5b52193239b751c2385cdf2978f86e7ff42510265f5efdb1dbc6f9f57f8031797a5c0
|
data/NEWS
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# Machinery Release Notes
|
2
2
|
|
3
3
|
|
4
|
+
## Version 1.11.2 - Thu Jul 30 14:42:44 CEST 2015 - thardeck@suse.de
|
5
|
+
|
6
|
+
* Fix issue with showing HTML view when not all file scopes are inspected
|
7
|
+
(gh#SUSE/machinery#1150)
|
8
|
+
* Fix `--all` option of `remove` command (gh#SUSE/machinery#1128)
|
9
|
+
|
4
10
|
## Version 1.11.1 - Tue Jul 21 09:44:16 CEST 2015 - thardeck@suse.de
|
5
11
|
|
6
12
|
* Fix unmanaged-files diff in HTML view (gh#SUSE/machinery#1143)
|
data/lib/build_task.rb
CHANGED
@@ -19,8 +19,7 @@ class BuildTask
|
|
19
19
|
def build(system_description, output_path, options = {})
|
20
20
|
LocalSystem.validate_architecture("x86_64")
|
21
21
|
LocalSystem.validate_build_compatibility(system_description)
|
22
|
-
LocalSystem.
|
23
|
-
LocalSystem.validate_existence_of_package("kiwi-desc-vmxboot")
|
22
|
+
LocalSystem.validate_existence_of_packages(["kiwi", "kiwi-desc-vmxboot"])
|
24
23
|
|
25
24
|
tmp_config_dir = Dir.mktmpdir("machinery-config", "/tmp")
|
26
25
|
tmp_image_dir = Dir.mktmpdir("machinery-image", "/tmp")
|
data/lib/cli.rb
CHANGED
@@ -35,7 +35,9 @@ class Cli
|
|
35
35
|
Machinery.logger.level = Logger::INFO
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
validate_command_line(command.arguments, args)
|
39
|
+
|
40
|
+
true
|
39
41
|
end
|
40
42
|
|
41
43
|
post do |global_options,command,options,args|
|
@@ -55,8 +57,8 @@ class Cli
|
|
55
57
|
|
56
58
|
GLI::Commands::Help.skips_post = false
|
57
59
|
|
58
|
-
def self.
|
59
|
-
if defined.any?(&:multiple?) && parsed.empty?
|
60
|
+
def self.validate_command_line(defined, parsed)
|
61
|
+
if defined.any?(&:multiple?) && !defined.any?(&:optional?) && parsed.empty?
|
60
62
|
message = "No arguments given. Nothing to do."
|
61
63
|
raise GLI::BadCommandLine.new(message)
|
62
64
|
elsif !defined.any?(&:multiple?) && parsed.size > defined.size
|
@@ -65,8 +67,6 @@ class Cli
|
|
65
67
|
message = "Too many arguments: got #{parsed_arguments}, expected #{defined_arguments}"
|
66
68
|
raise GLI::BadCommandLine.new(message)
|
67
69
|
end
|
68
|
-
|
69
|
-
true
|
70
70
|
end
|
71
71
|
|
72
72
|
def self.buildable_distributions
|
@@ -594,7 +594,7 @@ class Cli
|
|
594
594
|
|
595
595
|
The success of a removal can be shown with the verbose option.
|
596
596
|
LONGDESC
|
597
|
-
arg "NAME", :multiple
|
597
|
+
arg "NAME", [:multiple, :optional]
|
598
598
|
|
599
599
|
command :remove do |c|
|
600
600
|
c.switch :all, negatable: false,
|
@@ -603,6 +603,10 @@ class Cli
|
|
603
603
|
desc: "Explain what is being done"
|
604
604
|
|
605
605
|
c.action do |global_options,options,args|
|
606
|
+
if !options[:all] && args.empty?
|
607
|
+
raise GLI::BadCommandLine.new, "You need to either specify `--all` or a list of system descriptions"
|
608
|
+
end
|
609
|
+
|
606
610
|
task = RemoveTask.new
|
607
611
|
task.remove(system_description_store, args, verbose: options[:verbose], all: options[:all])
|
608
612
|
end
|
@@ -755,7 +759,8 @@ class Cli
|
|
755
759
|
LONGDESC
|
756
760
|
arg "NAME"
|
757
761
|
command "serve" do |c|
|
758
|
-
c.flag [:port, :p], type: Integer, required: false,
|
762
|
+
c.flag [:port, :p], type: Integer, required: false,
|
763
|
+
default_value: Machinery::Config.new.http_server_port,
|
759
764
|
desc: "Listen on port PORT", arg_name: "PORT"
|
760
765
|
c.flag [:ip, :i], type: String, required: false, default_value: "127.0.0.1",
|
761
766
|
desc: "Listen on ip IP", arg_name: "IP"
|
data/lib/compare_task.rb
CHANGED
@@ -39,9 +39,7 @@ There is a web server running, serving the comparison result on #{url}.
|
|
39
39
|
The server can be closed with Ctrl+C.
|
40
40
|
EOF
|
41
41
|
|
42
|
-
server = Html.run_server(description1.store, port: options[:port], ip: options[:ip])
|
43
|
-
|
44
|
-
Html.when_server_ready(options[:ip], options[:port]) do
|
42
|
+
server = Html.run_server(description1.store, port: options[:port], ip: options[:ip]) do
|
45
43
|
LoggedCheetah.run("xdg-open", url)
|
46
44
|
end
|
47
45
|
|
data/lib/config.rb
CHANGED
@@ -21,9 +21,11 @@
|
|
21
21
|
|
22
22
|
module Machinery
|
23
23
|
class Config < ConfigBase
|
24
|
-
def
|
25
|
-
|
24
|
+
def default_config_file
|
25
|
+
ENV["MACHINERY_CONFIG_FILE"] || Machinery::DEFAULT_CONFIG_FILE
|
26
|
+
end
|
26
27
|
|
28
|
+
def define_entries
|
27
29
|
entry("hints",
|
28
30
|
default: true,
|
29
31
|
description: "Show hints about usage of Machinery in the context of the commands ran by" \
|
data/lib/config_base.rb
CHANGED
@@ -20,16 +20,18 @@
|
|
20
20
|
# the file 'machinery_config.rb'.
|
21
21
|
|
22
22
|
class ConfigBase
|
23
|
-
|
23
|
+
attr_reader :file
|
24
|
+
|
25
|
+
def initialize(file = default_config_file)
|
24
26
|
@entries = {}
|
25
|
-
@file =
|
27
|
+
@file = file
|
26
28
|
define_entries
|
27
29
|
apply_custom_config(@file) if File.exist?(@file)
|
28
30
|
end
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
abstract_method :default_config_files
|
33
|
+
|
34
|
+
abstract_method :define_entries
|
33
35
|
|
34
36
|
def entry(key, parameters = {})
|
35
37
|
key = normalize_key(key)
|
@@ -39,10 +41,6 @@ class ConfigBase
|
|
39
41
|
create_method("#{key}=".to_sym) { |value| set(key, value) }
|
40
42
|
end
|
41
43
|
|
42
|
-
def define_entries
|
43
|
-
raise NotImplementedError.new("No config entries defined for #{self.class}")
|
44
|
-
end
|
45
|
-
|
46
44
|
def each(&block)
|
47
45
|
@entries.map { |key, value| [unnormalize_key(key), value] }.each(&block)
|
48
46
|
end
|
@@ -82,7 +80,7 @@ class ConfigBase
|
|
82
80
|
config_table_stripped[key] = value[:value]
|
83
81
|
end
|
84
82
|
|
85
|
-
FileUtils.mkdir_p(
|
83
|
+
FileUtils.mkdir_p(File.dirname(file))
|
86
84
|
|
87
85
|
begin
|
88
86
|
File.write(@file, config_table_stripped.to_yaml)
|
data/lib/deploy_task.rb
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
class DeployTask
|
19
19
|
def deploy(description, cloud_config, options = {})
|
20
20
|
LocalSystem.validate_architecture("x86_64")
|
21
|
-
LocalSystem.
|
21
|
+
LocalSystem.validate_existence_of_packages(["python-glanceclient", "kiwi", "kiwi-desc-vmxboot"])
|
22
22
|
LocalSystem.validate_build_compatibility(description)
|
23
23
|
|
24
24
|
if !File.exists?(cloud_config)
|
data/lib/exceptions.rb
CHANGED
data/lib/html.rb
CHANGED
@@ -16,184 +16,14 @@
|
|
16
16
|
# you may find current contact information at www.suse.com
|
17
17
|
|
18
18
|
class Html
|
19
|
-
module Helpers
|
20
|
-
def scope_help(scope)
|
21
|
-
text = File.read(File.join(Machinery::ROOT, "plugins", "#{scope}/#{scope}.md"))
|
22
|
-
Kramdown::Document.new(text).to_html
|
23
|
-
end
|
24
|
-
|
25
|
-
def diff_to_object(diff)
|
26
|
-
diff = Machinery.scrub(diff)
|
27
|
-
lines = diff.lines[2..-1]
|
28
|
-
diff_object = {
|
29
|
-
file: diff[/--- a(.*)/, 1],
|
30
|
-
additions: lines.select { |l| l.start_with?("+") }.length,
|
31
|
-
deletions: lines.select { |l| l.start_with?("-") }.length
|
32
|
-
}
|
33
|
-
|
34
|
-
original_line_number = 0
|
35
|
-
new_line_number = 0
|
36
|
-
diff_object[:lines] = lines.map do |line|
|
37
|
-
line = ERB::Util.html_escape(line.chomp).
|
38
|
-
gsub("\\", "\").
|
39
|
-
gsub("\t", " " * 8)
|
40
|
-
case line
|
41
|
-
when /^@.*/
|
42
|
-
entry = {
|
43
|
-
type: "header",
|
44
|
-
content: line
|
45
|
-
}
|
46
|
-
original_line_number = line[/-(\d+)/, 1].to_i
|
47
|
-
new_line_number = line[/\+(\d+)/, 1].to_i
|
48
|
-
when /^ .*/, ""
|
49
|
-
entry = {
|
50
|
-
type: "common",
|
51
|
-
new_line_number: new_line_number,
|
52
|
-
original_line_number: original_line_number,
|
53
|
-
content: line[1..-1]
|
54
|
-
}
|
55
|
-
new_line_number += 1
|
56
|
-
original_line_number += 1
|
57
|
-
when /^\+.*/
|
58
|
-
entry = {
|
59
|
-
type: "addition",
|
60
|
-
new_line_number: new_line_number,
|
61
|
-
content: line[1..-1]
|
62
|
-
}
|
63
|
-
new_line_number += 1
|
64
|
-
when /^\-.*/
|
65
|
-
entry = {
|
66
|
-
type: "deletion",
|
67
|
-
original_line_number: original_line_number,
|
68
|
-
content: line[1..-1]
|
69
|
-
}
|
70
|
-
original_line_number += 1
|
71
|
-
end
|
72
|
-
|
73
|
-
entry
|
74
|
-
end
|
75
|
-
|
76
|
-
diff_object
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# this is required for the #generate_comparison method which renders a HAML template manually with
|
81
|
-
# the local binding, so it expects the helper methods to be available in Html. It can be removed
|
82
|
-
# once the comparison was move to the webserver approach as well
|
83
|
-
extend Helpers
|
84
|
-
|
85
19
|
# Creates a new thread running a sinatra webserver which serves the local system descriptions
|
86
20
|
# The Thread object is returned so that the caller can `.join` it until it's finished.
|
87
|
-
def self.run_server(system_description_store, opts)
|
21
|
+
def self.run_server(system_description_store, opts, &block)
|
88
22
|
Thread.new do
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
set :port, opts[:port] || 7585
|
94
|
-
set :bind, opts[:ip] || "localhost"
|
95
|
-
set :public_folder, File.join(Machinery::ROOT, "html")
|
96
|
-
|
97
|
-
helpers Helpers
|
98
|
-
|
99
|
-
get "/descriptions/:id.js" do
|
100
|
-
description = SystemDescription.load(params[:id], system_description_store)
|
101
|
-
diffs_dir = description.scope_file_store("analyze/config_file_diffs").path
|
102
|
-
if description.config_files && diffs_dir
|
103
|
-
# Enrich description with the config file diffs
|
104
|
-
description.config_files.files.each do |file|
|
105
|
-
path = File.join(diffs_dir, file.name + ".diff")
|
106
|
-
file.diff = diff_to_object(File.read(path)) if File.exists?(path)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# Enrich file information with downloadable flag
|
111
|
-
["config_files", "changed_managed_files", "unmanaged_files"].each do |scope|
|
112
|
-
description[scope].files.each do |file|
|
113
|
-
file.downloadable = file.on_disk?
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
description.to_hash.to_json
|
118
|
-
end
|
119
|
-
|
120
|
-
get "/descriptions/:id/files/:scope/*" do
|
121
|
-
description = SystemDescription.load(params[:id], system_description_store)
|
122
|
-
filename = File.join("/", params["splat"].first)
|
123
|
-
|
124
|
-
file = description[params[:scope]].files.find { |f| f.name == filename }
|
125
|
-
|
126
|
-
if request.accept.first.to_s == "text/plain" && file.binary?
|
127
|
-
status 406
|
128
|
-
return "binary file"
|
129
|
-
end
|
130
|
-
|
131
|
-
content = file.content
|
132
|
-
type = MimeMagic.by_path(filename) || MimeMagic.by_magic(content) || "text/plain"
|
133
|
-
|
134
|
-
content_type type
|
135
|
-
attachment File.basename(filename)
|
136
|
-
|
137
|
-
content
|
138
|
-
end
|
139
|
-
|
140
|
-
get "/compare/:a/:b.json" do
|
141
|
-
description_a = SystemDescription.load(params[:a], system_description_store)
|
142
|
-
description_b = SystemDescription.load(params[:b], system_description_store)
|
143
|
-
|
144
|
-
diff = {
|
145
|
-
meta: {
|
146
|
-
description_a: description_a.name,
|
147
|
-
description_b: description_b.name,
|
148
|
-
}
|
149
|
-
}
|
150
|
-
|
151
|
-
Inspector.all_scopes.each do |scope|
|
152
|
-
if description_a[scope] && description_b[scope]
|
153
|
-
comparison = Comparison.compare_scope(description_a, description_b, scope)
|
154
|
-
diff[scope] = comparison.as_json
|
155
|
-
else
|
156
|
-
diff[:meta][:uninspected] ||= Hash.new
|
157
|
-
|
158
|
-
if !description_a[scope] && description_b[scope]
|
159
|
-
diff[:meta][:uninspected][description_a.name] ||= Array.new
|
160
|
-
diff[:meta][:uninspected][description_a.name] << scope
|
161
|
-
end
|
162
|
-
if !description_b[scope] && description_a[scope]
|
163
|
-
diff[:meta][:uninspected][description_b.name] ||= Array.new
|
164
|
-
diff[:meta][:uninspected][description_b.name] << scope
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
diff.to_json
|
170
|
-
end
|
171
|
-
|
172
|
-
get "/compare/:a/:b" do
|
173
|
-
haml File.read(File.join(Machinery::ROOT, "html/comparison.html.haml")),
|
174
|
-
locals: { description_a: params[:a], description_b: params[:b] }
|
175
|
-
end
|
176
|
-
|
177
|
-
get "/compare/:a/:b/files/:scope/*" do
|
178
|
-
description1 = SystemDescription.load(params[:a], system_description_store)
|
179
|
-
description2 = SystemDescription.load(params[:b], system_description_store)
|
180
|
-
filename = File.join("/", params["splat"].first)
|
181
|
-
|
182
|
-
begin
|
183
|
-
diff = FileDiff.diff(description1, description2, params[:scope], filename)
|
184
|
-
rescue Machinery::Errors::BinaryDiffError
|
185
|
-
status 406
|
186
|
-
return "binary file"
|
187
|
-
end
|
188
|
-
|
189
|
-
diff.to_s(:html)
|
190
|
-
end
|
191
|
-
|
192
|
-
get "/:id" do
|
193
|
-
haml File.read(File.join(Machinery::ROOT, "html/index.html.haml")),
|
194
|
-
locals: { description_name: params[:id] }
|
195
|
-
end
|
196
|
-
end
|
23
|
+
Server.set :system_description_store, system_description_store
|
24
|
+
Server.set :port, opts[:port] || Machinery::Config.new.http_server_port
|
25
|
+
Server.set :bind, opts[:ip] || "localhost"
|
26
|
+
Server.set :public_folder, File.join(Machinery::ROOT, "html")
|
197
27
|
|
198
28
|
if opts[:ip] != "localhost" && opts[:ip] != "127.0.0.1"
|
199
29
|
Machinery::Ui.puts <<EOF
|
@@ -205,27 +35,24 @@ EOF
|
|
205
35
|
|
206
36
|
begin
|
207
37
|
setup_output_redirection
|
208
|
-
|
38
|
+
begin
|
39
|
+
Server.run! do
|
40
|
+
Thread.new { block.call }
|
41
|
+
end
|
42
|
+
rescue Errno::EADDRINUSE
|
43
|
+
servefailed_error = <<-EOF.chomp
|
44
|
+
Port #{Server.settings.port} is already in use.
|
45
|
+
Stop the already running server on port #{Server.settings.port} or specify a new port by using --port option.
|
46
|
+
EOF
|
47
|
+
raise Machinery::Errors::ServeFailed, servefailed_error
|
48
|
+
end
|
49
|
+
remove_output_redirection
|
209
50
|
rescue => e
|
51
|
+
remove_output_redirection
|
210
52
|
# Re-raise exception in main thread
|
211
53
|
Thread.main.raise e
|
212
|
-
ensure
|
213
|
-
remove_output_redirection
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
def self.when_server_ready(ip, port, &block)
|
219
|
-
20.times do
|
220
|
-
begin
|
221
|
-
TCPSocket.new(ip, port).close
|
222
|
-
block.call
|
223
|
-
return
|
224
|
-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
225
|
-
sleep 0.1
|
226
54
|
end
|
227
55
|
end
|
228
|
-
raise Machinery::Errors::MachineryError, "The web server did not come up in time."
|
229
56
|
end
|
230
57
|
|
231
58
|
def self.setup_output_redirection
|
@@ -240,22 +67,4 @@ EOF
|
|
240
67
|
STDOUT.reopen @orig_stdout
|
241
68
|
STDERR.reopen @orig_stderr
|
242
69
|
end
|
243
|
-
|
244
|
-
def self.generate_comparison(diff, target)
|
245
|
-
FileUtils.mkdir_p(File.join(target, "assets"))
|
246
|
-
template = Haml::Engine.new(
|
247
|
-
File.read(File.join(Machinery::ROOT, "html", "comparison.html.haml"))
|
248
|
-
)
|
249
|
-
|
250
|
-
FileUtils.cp_r(File.join(Machinery::ROOT, "html", "assets"), target)
|
251
|
-
File.write(File.join(target, "index.html"), template.render(binding))
|
252
|
-
json = diff.to_json.gsub("'", "\\\\'").gsub("\"", "\\\\\"")
|
253
|
-
File.write(File.join(target, "assets/diff.js"),<<-EOT
|
254
|
-
function getDiff() {
|
255
|
-
return JSON.parse('#{json}'
|
256
|
-
)
|
257
|
-
}
|
258
|
-
EOT
|
259
|
-
)
|
260
|
-
end
|
261
70
|
end
|
data/lib/inspector.rb
CHANGED
@@ -68,7 +68,10 @@ class Inspector
|
|
68
68
|
scope_priority = {}
|
69
69
|
|
70
70
|
scope_list.each do |scope|
|
71
|
-
|
71
|
+
inspector = self.for(scope)
|
72
|
+
next if !inspector
|
73
|
+
|
74
|
+
scope_priority[inspector.priority] = scope
|
72
75
|
end
|
73
76
|
|
74
77
|
scope_priority.sort.map do |key, value|
|
data/lib/local_system.rb
CHANGED
@@ -30,17 +30,41 @@ class LocalSystem < System
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def validate_existence_of_package(package)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
33
|
+
validate_existence_of_packages([package])
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate_existence_of_packages(packages)
|
37
|
+
missing_packages = []
|
38
|
+
needed_modules = []
|
39
|
+
|
40
|
+
packages.each do |package|
|
41
|
+
begin
|
42
|
+
Cheetah.run("rpm", "-q", package)
|
43
|
+
rescue Cheetah::ExecutionFailed
|
44
|
+
missing_packages << package
|
45
|
+
needed_module = os.module_required_by_package(package)
|
46
|
+
if needed_module
|
47
|
+
needed_modules << package
|
48
|
+
if needed_module
|
49
|
+
output = <<-EOF
|
50
|
+
You need the package '#{package}' from module '#{needed_module}'. You can install it as follows:
|
51
|
+
If you haven't selected the module '#{needed_module}' before, run `yast2 scc` and choose 'Select Extensions' and activate '#{needed_module}'.
|
52
|
+
Run `zypper install #{package}` to install the package.
|
53
|
+
EOF
|
54
|
+
raise(Machinery::Errors::MissingRequirement.new(output))
|
55
|
+
end
|
56
|
+
end
|
42
57
|
end
|
43
58
|
end
|
59
|
+
|
60
|
+
if !missing_packages.empty?
|
61
|
+
count = missing_packages.count
|
62
|
+
error_string = <<-EOF
|
63
|
+
You need the #{Machinery::pluralize(count, "package")} '#{missing_packages.join("\',\'")}'.
|
64
|
+
You can install it by running `zypper install #{missing_packages.join(" ")}`.
|
65
|
+
EOF
|
66
|
+
raise(Machinery::Errors::MissingRequirement.new(error_string))
|
67
|
+
end
|
44
68
|
end
|
45
69
|
|
46
70
|
def validate_machinery_compatibility
|
data/lib/machinery.rb
CHANGED
@@ -35,6 +35,8 @@ require "pathname"
|
|
35
35
|
require "nokogiri"
|
36
36
|
require "socket"
|
37
37
|
require "diffy"
|
38
|
+
require "sinatra/base"
|
39
|
+
require "mimemagic"
|
38
40
|
|
39
41
|
require_relative "machinery_logger"
|
40
42
|
require_relative "zypper"
|
@@ -76,7 +78,6 @@ require_relative "ui"
|
|
76
78
|
require_relative "validate_task"
|
77
79
|
require_relative "migration"
|
78
80
|
require_relative "upgrade_format_task"
|
79
|
-
require_relative "html"
|
80
81
|
require_relative "hint"
|
81
82
|
require_relative "mountpoints"
|
82
83
|
require_relative "config_base"
|
@@ -99,6 +100,8 @@ require_relative "man_task"
|
|
99
100
|
require_relative "comparison"
|
100
101
|
require_relative "serve_html_task"
|
101
102
|
require_relative "file_diff"
|
103
|
+
require_relative "server"
|
104
|
+
require_relative "html"
|
102
105
|
|
103
106
|
Dir[File.join(Machinery::ROOT, "plugins", "**", "*.rb")].each { |f| require(f) }
|
104
107
|
|
data/lib/server.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
# Copyright (c) 2013-2015 SUSE LLC
|
2
|
+
#
|
3
|
+
# This program is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of version 3 of the GNU General Public License as
|
5
|
+
# published by the Free Software Foundation.
|
6
|
+
#
|
7
|
+
# This program is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
10
|
+
# GNU General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program; if not, contact SUSE LLC.
|
14
|
+
#
|
15
|
+
# To contact SUSE about this file by physical or electronic mail,
|
16
|
+
# you may find current contact information at www.suse.com
|
17
|
+
|
18
|
+
class Server < Sinatra::Base
|
19
|
+
module Helpers
|
20
|
+
def scope_help(scope)
|
21
|
+
text = File.read(File.join(Machinery::ROOT, "plugins", "#{scope}/#{scope}.md"))
|
22
|
+
Kramdown::Document.new(text).to_html
|
23
|
+
end
|
24
|
+
|
25
|
+
def diff_to_object(diff)
|
26
|
+
diff = Machinery.scrub(diff)
|
27
|
+
lines = diff.lines[2..-1]
|
28
|
+
diff_object = {
|
29
|
+
file: diff[/--- a(.*)/, 1],
|
30
|
+
additions: lines.select { |l| l.start_with?("+") }.length,
|
31
|
+
deletions: lines.select { |l| l.start_with?("-") }.length
|
32
|
+
}
|
33
|
+
|
34
|
+
original_line_number = 0
|
35
|
+
new_line_number = 0
|
36
|
+
diff_object[:lines] = lines.map do |line|
|
37
|
+
line = ERB::Util.html_escape(line.chomp).
|
38
|
+
gsub("\\", "\").
|
39
|
+
gsub("\t", " " * 8)
|
40
|
+
case line
|
41
|
+
when /^@.*/
|
42
|
+
entry = {
|
43
|
+
type: "header",
|
44
|
+
content: line
|
45
|
+
}
|
46
|
+
original_line_number = line[/-(\d+)/, 1].to_i
|
47
|
+
new_line_number = line[/\+(\d+)/, 1].to_i
|
48
|
+
when /^ .*/, ""
|
49
|
+
entry = {
|
50
|
+
type: "common",
|
51
|
+
new_line_number: new_line_number,
|
52
|
+
original_line_number: original_line_number,
|
53
|
+
content: line[1..-1]
|
54
|
+
}
|
55
|
+
new_line_number += 1
|
56
|
+
original_line_number += 1
|
57
|
+
when /^\+.*/
|
58
|
+
entry = {
|
59
|
+
type: "addition",
|
60
|
+
new_line_number: new_line_number,
|
61
|
+
content: line[1..-1]
|
62
|
+
}
|
63
|
+
new_line_number += 1
|
64
|
+
when /^\-.*/
|
65
|
+
entry = {
|
66
|
+
type: "deletion",
|
67
|
+
original_line_number: original_line_number,
|
68
|
+
content: line[1..-1]
|
69
|
+
}
|
70
|
+
original_line_number += 1
|
71
|
+
end
|
72
|
+
|
73
|
+
entry
|
74
|
+
end
|
75
|
+
|
76
|
+
diff_object
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
helpers Helpers
|
81
|
+
|
82
|
+
get "/descriptions/:id.js" do
|
83
|
+
description = SystemDescription.load(params[:id], settings.system_description_store)
|
84
|
+
diffs_dir = description.scope_file_store("analyze/config_file_diffs").path
|
85
|
+
if description.config_files && diffs_dir
|
86
|
+
# Enrich description with the config file diffs
|
87
|
+
description.config_files.files.each do |file|
|
88
|
+
path = File.join(diffs_dir, file.name + ".diff")
|
89
|
+
file.diff = diff_to_object(File.read(path)) if File.exists?(path)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Enrich file information with downloadable flag
|
94
|
+
["config_files", "changed_managed_files", "unmanaged_files"].each do |scope|
|
95
|
+
next if !description[scope]
|
96
|
+
|
97
|
+
description[scope].files.each do |file|
|
98
|
+
file.downloadable = file.on_disk?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
description.to_hash.to_json
|
103
|
+
end
|
104
|
+
|
105
|
+
get "/descriptions/:id/files/:scope/*" do
|
106
|
+
description = SystemDescription.load(params[:id], settings.system_description_store)
|
107
|
+
filename = File.join("/", params["splat"].first)
|
108
|
+
|
109
|
+
file = description[params[:scope]].files.find { |f| f.name == filename }
|
110
|
+
|
111
|
+
if request.accept.first.to_s == "text/plain" && file.binary?
|
112
|
+
status 406
|
113
|
+
return "binary file"
|
114
|
+
end
|
115
|
+
|
116
|
+
content = file.content
|
117
|
+
type = MimeMagic.by_path(filename) || MimeMagic.by_magic(content) || "text/plain"
|
118
|
+
|
119
|
+
content_type type
|
120
|
+
attachment File.basename(filename)
|
121
|
+
|
122
|
+
content
|
123
|
+
end
|
124
|
+
|
125
|
+
get "/compare/:a/:b.json" do
|
126
|
+
description_a = SystemDescription.load(params[:a], settings.system_description_store)
|
127
|
+
description_b = SystemDescription.load(params[:b], settings.system_description_store)
|
128
|
+
|
129
|
+
diff = {
|
130
|
+
meta: {
|
131
|
+
description_a: description_a.name,
|
132
|
+
description_b: description_b.name,
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
Inspector.all_scopes.each do |scope|
|
137
|
+
if description_a[scope] && description_b[scope]
|
138
|
+
comparison = Comparison.compare_scope(description_a, description_b, scope)
|
139
|
+
diff[scope] = comparison.as_json
|
140
|
+
else
|
141
|
+
diff[:meta][:uninspected] ||= Hash.new
|
142
|
+
|
143
|
+
if !description_a[scope] && description_b[scope]
|
144
|
+
diff[:meta][:uninspected][description_a.name] ||= Array.new
|
145
|
+
diff[:meta][:uninspected][description_a.name] << scope
|
146
|
+
end
|
147
|
+
if !description_b[scope] && description_a[scope]
|
148
|
+
diff[:meta][:uninspected][description_b.name] ||= Array.new
|
149
|
+
diff[:meta][:uninspected][description_b.name] << scope
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
diff.to_json
|
155
|
+
end
|
156
|
+
|
157
|
+
get "/compare/:a/:b" do
|
158
|
+
haml File.read(File.join(Machinery::ROOT, "html/comparison.html.haml")),
|
159
|
+
locals: { description_a: params[:a], description_b: params[:b] }
|
160
|
+
end
|
161
|
+
|
162
|
+
get "/compare/:a/:b/files/:scope/*" do
|
163
|
+
description1 = SystemDescription.load(params[:a], settings.system_description_store)
|
164
|
+
description2 = SystemDescription.load(params[:b], settings.system_description_store)
|
165
|
+
filename = File.join("/", params["splat"].first)
|
166
|
+
|
167
|
+
begin
|
168
|
+
diff = FileDiff.diff(description1, description2, params[:scope], filename)
|
169
|
+
rescue Machinery::Errors::BinaryDiffError
|
170
|
+
status 406
|
171
|
+
return "binary file"
|
172
|
+
end
|
173
|
+
|
174
|
+
diff.to_s(:html)
|
175
|
+
end
|
176
|
+
|
177
|
+
get "/:id" do
|
178
|
+
haml File.read(File.join(Machinery::ROOT, "html/index.html.haml")),
|
179
|
+
locals: { description_name: params[:id] }
|
180
|
+
end
|
181
|
+
end
|
data/lib/show_task.rb
CHANGED
@@ -41,9 +41,7 @@ There is a web server running, serving the description on #{url}.
|
|
41
41
|
The server can be closed with Ctrl+C.
|
42
42
|
EOF
|
43
43
|
|
44
|
-
server = Html.run_server(description.store, port: options[:port], ip: options[:ip])
|
45
|
-
|
46
|
-
Html.when_server_ready(options[:ip], options[:port]) do
|
44
|
+
server = Html.run_server(description.store, port: options[:port], ip: options[:ip]) do
|
47
45
|
LoggedCheetah.run("xdg-open", url)
|
48
46
|
end
|
49
47
|
|
data/lib/version.rb
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: machinery-tool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.11.
|
4
|
+
version: 1.11.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SUSE
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cheetah
|
@@ -337,6 +337,7 @@ files:
|
|
337
337
|
- lib/scope_file_access_flat.rb
|
338
338
|
- lib/scope_file_store.rb
|
339
339
|
- lib/serve_html_task.rb
|
340
|
+
- lib/server.rb
|
340
341
|
- lib/show_task.rb
|
341
342
|
- lib/system.rb
|
342
343
|
- lib/system_description.rb
|