machinery-tool 1.15.0 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b7bb69c63715c0f27c39688ddb791ee35a6467e4
4
- data.tar.gz: a214db91229631088de485747ef4e1907d10f561
3
+ metadata.gz: a4b7c4fc1cda138bae3373d5557bb65bd30481a5
4
+ data.tar.gz: c9f706f3cb00c6eac9c8a3b01eaf0ba1a5345704
5
5
  SHA512:
6
- metadata.gz: a062352d64c37f3e67e1082cdef8a0958b74b0f4f2adc8edcd1eede673686e2940994542066811b91ebe51cb55af7cf3c72a578f348331a3f9f7a65381abdb30
7
- data.tar.gz: 489b549c5188697403a50e29525ece98e46e3e12bf987c71a2faaccd029e167bbd43265bae9a09b923c6981f219d5887aa94b779b5317fda4f43d41b98275d7f
6
+ metadata.gz: e3806f42441561cc01b2b6c927627ab69b673feb65194bacedd7d460507af95070cf8ae3d087560b40ea2d9c64f158825469030a129d78458555af6137435393
7
+ data.tar.gz: 2212be5d36387f90dbb05b66b31cc1af51ae829a39b9208d04b8218e93590c05ae6eb21bba91db285c3f45d8e2823f35706d6d460d69054432abcfa34235e8cd
data/.git_revision CHANGED
@@ -1 +1 @@
1
- b333b1358568df9a508e7d92c61d3280395911d9
1
+ f5f2a71bd21d86dcbc1b90e30b8af0f466b335bd
data/NEWS CHANGED
@@ -1,6 +1,27 @@
1
1
  # Machinery Release Notes
2
2
 
3
3
 
4
+ ## Version 1.16.0 - Fri Nov 06 14:20:47 CET 2015 - thardeck@suse.de
5
+
6
+ * The error message "There is already a server with the same port running" has
7
+ been cleaned up and is no longer misleading (gh#SUSE/machinery#1541)
8
+ * Add OpenSUSE Leap as supported system
9
+ * HTML comparison is now available without the experimental feature flag
10
+ * Add error message to recommend using `--name` when a container with a slash is
11
+ inspected (gh#SUSE/machinery#1490)
12
+ * Fixed crash during inspection of a folder which contains special characters
13
+ in its name (gh#SUSE/machinery#1580)
14
+ * Speed up inspection of config and changed managed files
15
+ * Fix docker inspection when specifying a docker image with tag
16
+ (gh#SUSE/machinery#1491)
17
+ * GConf XML files are no longer treated as binary files in HTML view
18
+ (gh#SUSE/machinery#1154)
19
+ * Add current outgoing ip and export directory to Autoyast README.md during
20
+ export (gh#SUSE/machinery#1543)
21
+ * Handle invalid utf-8 characters in /etc/passwd
22
+ * Fix: "changed" link in compare view is visible while scope is collapsed but
23
+ doesn't do anything (gh#SUSE/machinery#1555)
24
+
4
25
  ## Version 1.15.0 - Mon Oct 26 17:42:25 CET 2015 - thardeck@suse.de
5
26
 
6
27
  * No information is cut off in the HTML view
@@ -11,18 +11,18 @@ The export directory contains both the AutoYaST profile and additional data that
11
11
  is required during installation. This directory needs to be made available to
12
12
  the installer via network, e.g. by running:
13
13
 
14
- cd /path/to/autoyast_export; python -m SimpleHTTPServer
14
+ cd <path>; python -m SimpleHTTPServer
15
15
 
16
16
  You can then point the installer to the profile by specifying the AutoYaST
17
17
  option on the kernel command line.
18
18
 
19
19
  For SLES12 and openSUSE 13.2:
20
20
 
21
- autoyast2=http://192.168.121.1:8000/autoinst.xml
21
+ autoyast2=http://<ip>:8000/autoinst.xml
22
22
 
23
23
  For SLES11:
24
24
 
25
- autoyast=http://192.168.121.1:8000/autoinst.xml netsetup=dhcp
25
+ autoyast=http://<ip>:8000/autoinst.xml netsetup=dhcp
26
26
 
27
27
  ## Changing permissions of the AutoYaST export
28
28
 
@@ -33,7 +33,7 @@ The installation via for example an HTTP server is only possible if all files
33
33
  and sub directories are readable by the HTTP server user.
34
34
  To make the export directory readable for all users run:
35
35
 
36
- chmod -R a+rX /path/to/autoyast_export
36
+ chmod -R a+rX <path>
37
37
 
38
38
  ## Reference
39
39
 
@@ -70,6 +70,18 @@ $(document).ready(function () {
70
70
  return false;
71
71
  });
72
72
 
73
+ $(".show-changed-elements").click(function(){
74
+ $scope = $(this).closest(".scope");
75
+ if ($scope.find(".toggle").hasClass("collapsed")){
76
+ $scope.find(".scope_content").collapse("show");
77
+ $scope.find(".toggle").removeClass("collapsed");
78
+ }
79
+ if ($(this).attr("href")){
80
+ $('html,body').animate({scrollTop: $($(this).attr("href")).offset().top}, 'slow');
81
+ }
82
+ return false;
83
+ });
84
+
73
85
  // Unmanaged files diffs
74
86
  $("#diff-unmanaged-files").on("show.bs.modal", function(e) {
75
87
  var trigger = $(e.relatedTarget);
@@ -223,6 +223,7 @@ h1 {
223
223
 
224
224
  .diff-unmanaged-files {
225
225
  padding-left: 10px;
226
+ cursor: pointer;
226
227
  }
227
228
 
228
229
  .well .dismiss{
@@ -25,7 +25,7 @@
25
25
  (#{@diff["services"].only_in2.init_system})
26
26
  - if @diff["services"].changed && @diff["services"].changed.length > 0
27
27
  %span.summary-part
28
- %a{ href: "#services_changed" }
28
+ %a.show-changed-elements{ href: "#services_changed" }
29
29
  changed
30
30
  = ": #{pluralize_scope(@diff["services"].changed, "service", "services")}"
31
31
  - if @diff["services"].common && @diff["services"].common.length > 0
@@ -7,7 +7,7 @@
7
7
  #{@description_b.name}: #{pluralize_scope(@diff[scope].only_in2, singular, plural)}
8
8
  - if @diff[scope].changed && @diff[scope].changed.length > 0
9
9
  %span.summary-part
10
- %a{ href: "#" + scope + "_changed" }
10
+ %a.show-changed-elements{ href: "#" + scope + "_changed" }
11
11
  changed
12
12
  = ": #{pluralize_scope(@diff[scope].changed, singular, plural)}"
13
13
  - if @diff[scope].common && @diff[scope].common.length > 0
@@ -23,7 +23,7 @@
23
23
  = pluralize_scope(@diff["unmanaged_files"].only_in2, "file", "files")
24
24
  - if @diff["unmanaged_files"].changed
25
25
  %span.summary-part
26
- %a{ href: "#unmanaged_files_changed" }
26
+ %a.show-changed-elements{ href: "#unmanaged_files_changed" }
27
27
  changed
28
28
  = ": #{pluralize_scope(@diff["unmanaged_files"].changed, "file", "files")}"
29
29
  - if @diff["unmanaged_files"].common
@@ -27,24 +27,6 @@
27
27
  # Exit immediately if a command exits with a non-zero status.
28
28
  set -e
29
29
 
30
- scope=$1
31
- package=$2 # for scope config-files only
32
-
33
- if [[ -z "$scope" || "$scope" != "config-files" && "$scope" != "changed-managed-files" ]]; then
34
- echo "Error: Expect scope 'config-files' or 'changed-managed-files' as first argument." >&2
35
- exit 1
36
- fi
37
-
38
- if [[ "$scope" == "changed-managed-files" && $# != 1 ]]; then
39
- echo "Error: Expect no extra arguments after changed-managed-files " >&2
40
- exit 1
41
- fi
42
-
43
- if [[ "$scope" == "config-files" && $# != 2 ]]; then
44
- echo "Error: Expect one argument with package name after config-files" >&2
45
- exit 1
46
- fi
47
-
48
30
  if [ $UID -ne "0" ]; then
49
31
  sudoprefix="sudo -n"
50
32
  fi
@@ -61,45 +43,4 @@ package_contains_verify_script () {
61
43
  rpm --scripts -q $1 | grep "verify scriptlet" > /dev/null
62
44
  }
63
45
 
64
- check_output () {
65
- # rpm returns 1 as exit code when modified config files are detected
66
- # that's why we explicitly detect if sudo failed
67
- regex="^sudo:.*password is required"
68
- if [[ "$1" =~ $regex ]]; then
69
- echo "$1" >&2
70
- exit 1
71
- fi
72
- }
73
-
74
- inspect_package () {
75
- package=$1
76
- output=`$sudoprefix rpm -V --nodeps --nodigest --nosignature --nomtime $noscripts $package 2>&1 || true`
77
-
78
- check_output "$output"
79
-
80
- if [ -z "$noscripts" ] && ( package_contains_verify_script $package ); then
81
- # remove the lines printed by verify scripts, because we cannot parse these lines
82
- # in certain rpm versions verify scripts cannot be turned off
83
- lines=`$sudoprefix rpm -V --nodeps --nodigest --nosignature --nomtime --nofiles $package | wc -l`
84
- output=`echo -e "$output" | head -n-${lines}`
85
- fi
86
-
87
- if [ -n "$output" ]; then
88
- if [ $scope == "changed-managed-files" ]; then
89
- echo -e "$package:\\n$output";
90
- else
91
- echo -e "$output"
92
- fi
93
- fi
94
- }
95
-
96
- if [ $scope == "changed-managed-files" ]; then
97
- for package in `rpm -qa --queryformat "%{NAME}-%{VERSION}\\n"`; do
98
- inspect_package $package
99
- done
100
- fi
101
-
102
- if [ $scope == "config-files" ]; then
103
- inspect_package $package
104
- fi
105
-
46
+ $sudoprefix rpm -Va --nodeps --nodigest --nosignature --nomtime $noscripts || true
data/lib/autoyast.rb CHANGED
@@ -43,10 +43,10 @@ class Autoyast < Exporter
43
43
  output_dir
44
44
  )
45
45
  FileUtils.chmod(0600, File.join(output_dir, "unmanaged_files_#{@name}_excludes"))
46
- FileUtils.cp(
47
- File.join(Machinery::ROOT, "export_helpers/autoyast_export_readme.md"),
48
- File.join(output_dir, "README.md")
49
- )
46
+ readme = File.read(File.join(Machinery::ROOT, "export_helpers/autoyast_export_readme.md"))
47
+ readme.gsub!("<ip>", outgoing_ip)
48
+ readme.gsub!("<path>", output_dir)
49
+ File.write(File.join(output_dir, "README.md"), readme)
50
50
  Dir["#{@system_description.description_path}/*"].each do |content|
51
51
  FileUtils.cp_r(content, output_dir, preserve: true)
52
52
  end
@@ -101,6 +101,11 @@ class Autoyast < Exporter
101
101
  builder.to_xml
102
102
  end
103
103
 
104
+ def outgoing_ip
105
+ output = Cheetah.run("ip", "route", "get", "8.8.8.8", stdout: :capture)
106
+ output[/ src ([\d\.:]+)\s*$/, 1] || "<ip>"
107
+ end
108
+
104
109
  private
105
110
 
106
111
  def apply_software_settings(xml)
data/lib/cli.rb CHANGED
@@ -154,6 +154,16 @@ class Cli
154
154
  true
155
155
  end
156
156
 
157
+ def self.check_container_name!(image, name)
158
+ if image.include?("/") && name.include?("/")
159
+ raise Machinery::Errors::InvalidCommandLine.new(
160
+ "Error: System description name '#{name}' is invalid. By default Machinery" \
161
+ " uses the image name as description name if the parameter `--name` is not" \
162
+ " provided.\nIf the image name consist a slash the `--name=NAME` parameter" \
163
+ " is mandatory. Valid characters are 'a-zA-Z0-9_:.-'."
164
+ )
165
+ end
166
+ end
157
167
 
158
168
  on_error do |e|
159
169
  Cli.handle_error(e)
@@ -177,7 +187,8 @@ class Cli
177
187
  if scopes
178
188
  if exclude_scopes
179
189
  # scope and exclude-scope
180
- raise Machinery::Errors::InvalidCommandLine.new( "You cannot provide the --scope and --exclude-scope option at the same time.")
190
+ raise Machinery::Errors::InvalidCommandLine.new("You cannot provide the --scope and " \
191
+ "--exclude-scope option at the same time.")
181
192
  else
182
193
  # scope only
183
194
  scope_list = parse_scopes(scopes)
@@ -274,8 +285,8 @@ class Cli
274
285
  LONGDESC
275
286
  arg "NAME"
276
287
  command "analyze" do |c|
277
- c.flag [:operation, :o], type: String, required: true,
278
- desc: "The analyze operation to perform", arg_name: "OPERATION"
288
+ c.flag [:operation, :o], type: String, required: false,
289
+ desc: "The analyze operation to perform", arg_name: "OPERATION", default_value: "config-file-diffs"
279
290
 
280
291
  c.action do |global_options,options,args|
281
292
  name = shift_arg(args, "NAME")
@@ -347,10 +358,8 @@ class Cli
347
358
  desc: "Exclude specified scopes", arg_name: "SCOPE_LIST"
348
359
  c.switch "show-all", required: false, negatable: false,
349
360
  desc: "Show also common properties"
350
- if @config.experimental_features
351
- c.switch "html", required: false, negatable: false,
352
- desc: "Open comparison in HTML format in your web browser."
353
- end
361
+ c.switch "html", required: false, negatable: false,
362
+ desc: "Open comparison in HTML format in your web browser."
354
363
  c.switch "pager", required: false, default_value: true,
355
364
  desc: "Pipe output into a pager"
356
365
 
@@ -637,6 +646,8 @@ class Cli
637
646
 
638
647
  name, scope_list, inspect_options, filter = parse_inspect_command_options(image, options)
639
648
 
649
+ check_container_name!(image, name)
650
+
640
651
  begin
641
652
  system.start
642
653
  inspector_task.inspect_system(
data/lib/docker_system.rb CHANGED
@@ -124,12 +124,8 @@ class DockerSystem < System
124
124
  private
125
125
 
126
126
  def validate_image_name(image)
127
- images = LoggedCheetah.run("docker", "images", stdout: :capture).split("\n")
128
-
129
- if !images.find { |i| i.start_with?("#{image} ") || i.index(" #{image} ") }
130
- raise Machinery::Errors::InspectionFailed.new(
131
- "Unknown docker image: '#{image}'"
132
- )
133
- end
127
+ LoggedCheetah.run("docker", "inspect", image)
128
+ rescue
129
+ raise Machinery::Errors::InspectionFailed.new("Unknown docker image: '#{image}'")
134
130
  end
135
131
  end
data/lib/helper.rb CHANGED
@@ -21,24 +21,7 @@ module Machinery
21
21
  end
22
22
 
23
23
  def self.content_is_binary?(content)
24
- # Code by http://www.thecodingforums.com/threads/test-if-file-is-binary.843447/#post-4572282
25
- # Modified by SUSE Linux GmbH
26
- ascii = 0
27
- control = 0
28
- binary = 0
29
-
30
- content.each_byte do |byte|
31
- case byte
32
- when 0...32
33
- control += 1
34
- when 32...128
35
- ascii += 1
36
- else
37
- binary += 1
38
- end
39
- end
40
-
41
- control.to_f / ascii > 0.1 || binary.to_f / ascii > 0.05
24
+ !Cheetah.run("file", "-b", "-", stdout: :capture, stdin: content).include?(" text")
42
25
  end
43
26
 
44
27
  # Implementation of String#scrub for Ruby < 2.1. Assumes the string is in
data/lib/html.rb CHANGED
@@ -51,7 +51,7 @@ EOF
51
51
  rescue Errno::EADDRINUSE
52
52
  servefailed_error = <<-EOF.chomp
53
53
  Port #{Server.settings.port} is already in use.
54
- Stop the already running server on port #{Server.settings.port} or specify a new port by using --port option.
54
+ You have to stop the already running server on port #{Server.settings.port} first or if you're serving a description with the `serve` command, you can also use the `--port` option.
55
55
  EOF
56
56
  raise Machinery::Errors::ServeFailed, servefailed_error
57
57
  rescue SocketError => e
data/lib/inspector.rb CHANGED
@@ -93,30 +93,4 @@ class Inspector
93
93
  def scope
94
94
  self.class.scope
95
95
  end
96
-
97
- # Runs the given script on the inspected machine asynchronously and calls the callback method
98
- # periodically with new output when it occurs.
99
- #
100
- # Example:
101
- #
102
- # count = 0
103
- # raw_list = run_script_with_progress("changed_managed_files.sh") do |chunk|
104
- # count += chunk.lines.count
105
- # Machinery::Ui.progress("Found #{count} changed files...")
106
- # end
107
- def run_script_with_progress(*script, &callback)
108
- output = ""
109
- write_io = StringIO.new(output, "a")
110
- read_io = StringIO.new(output, "r")
111
-
112
- inspect_thread = Thread.new { @system.run_script(*script, stdout: write_io) }
113
-
114
- while inspect_thread.alive?
115
- sleep 0.1
116
- chunk = read_io.read
117
- callback.call(chunk)
118
- end
119
-
120
- output
121
- end
122
96
  end
data/lib/machinery.rb CHANGED
@@ -68,7 +68,6 @@ require_relative "list_task"
68
68
  require_relative "system_description_store"
69
69
  require_relative "logged_cheetah"
70
70
  require_relative "renderer_helper"
71
- require_relative "changed_rpm_files_helper"
72
71
  require_relative "export_task"
73
72
  require_relative "helper"
74
73
  require_relative "deploy_task"
@@ -110,6 +109,7 @@ require_relative "workload_mapper_dsl"
110
109
  require_relative "containerized_app"
111
110
  require_relative "move_task"
112
111
  require_relative "docker_system"
112
+ require_relative "rpm_database"
113
113
 
114
114
  Dir[File.join(Machinery::ROOT, "plugins", "**", "*.rb")].each { |f| require(f) }
115
115
 
@@ -15,7 +15,60 @@
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
- module ChangedRpmFilesHelper
18
+ class RpmDatabase
19
+ class ChangedFile < Machinery::Object
20
+ attr_accessor :type
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
+
39
+ out = @system.run_script_with_progress("changed_files.sh", &block)
40
+ result = out.each_line.map do |line|
41
+ line.chomp!
42
+ next unless line.match(/^[^ ]+[ ]+. \/.*$/)
43
+
44
+ file, changes, type = parse_rpm_changes_line(line)
45
+
46
+ package = @system.run_command("rpm", "-qf", file, stdout: :capture).split.first
47
+ package_name, package_version = package.scan(/(.*)-([^-]*)-[^-]/).first
48
+
49
+ ChangedFile.new(
50
+ type,
51
+ name: file,
52
+ package_name: package_name,
53
+ package_version: package_version,
54
+ status: "changed",
55
+ changes: changes
56
+ )
57
+ end.compact.uniq
58
+
59
+ paths = result.reject { |f| f.changes == Machinery::Array.new(["deleted"]) }.map(&:name)
60
+ path_data = get_path_data(paths)
61
+ result.each do |pkg|
62
+ next unless path_data[pkg.name]
63
+
64
+ path_data[pkg.name].each do |key, value|
65
+ pkg[key] = value
66
+ end
67
+ end
68
+
69
+ @changed_files = result
70
+ end
71
+
19
72
  def expected_tag?(character, position)
20
73
  if @rpm_changes[position] == character
21
74
  true
@@ -85,40 +138,40 @@ module ChangedRpmFilesHelper
85
138
 
86
139
  [path.join(":").chomp,
87
140
  {
88
- mode: mode,
89
- user: user,
141
+ mode: mode,
142
+ user: user,
90
143
  group: group,
91
- type: type
144
+ type: type
92
145
  }
93
146
  ]
94
147
  end
95
148
 
96
- def get_link_target(system, link)
97
- system.run_command(
149
+ def get_link_target(link)
150
+ @system.run_command(
98
151
  "find", link, "-prune", "-printf", "%l",
99
- stdout: :capture,
152
+ stdout: :capture,
100
153
  privileged: true
101
154
  ).strip
102
155
  end
103
156
 
104
157
  # get path data for list of files
105
158
  # cur_files is guaranteed to not exceed max command line length
106
- def get_file_properties(system, cur_files)
159
+ def get_file_properties(cur_files)
107
160
  ret = {}
108
- out = system.run_command(
161
+ out = @system.run_command(
109
162
  "stat", "--printf", "%a:%U:%G:%u:%g:%F:%n\\n",
110
163
  *cur_files,
111
164
  stdout: :capture
112
165
  )
113
166
  out.each_line do |l|
114
- path, values = parse_stat_line(l)
115
- ret[path] = values
116
- ret[path][:target] = get_link_target(system, path) if values[:type] == "link"
167
+ path, values = parse_stat_line(l)
168
+ ret[path] = values
169
+ ret[path][:target] = get_link_target(path) if values[:type] == "link"
117
170
  end
118
171
  ret
119
172
  end
120
173
 
121
- def get_path_data(system, paths)
174
+ def get_path_data(paths)
122
175
  ret = {}
123
176
  path_index = 0
124
177
  # arbitrary number for maximum command line length that should always work
@@ -131,12 +184,12 @@ module ChangedRpmFilesHelper
131
184
  cur_len += paths[path_index].size + 1
132
185
  path_index += 1
133
186
  else
134
- ret.merge!(get_file_properties(system, cur_files))
187
+ ret.merge!(get_file_properties(cur_files))
135
188
  cur_files.clear
136
189
  cur_len = 0
137
190
  end
138
191
  end
139
- ret.merge!(get_file_properties(system, cur_files)) unless cur_files.empty?
192
+ ret.merge!(get_file_properties(cur_files)) unless cur_files.empty?
140
193
  ret
141
194
  end
142
195
  end
@@ -74,6 +74,6 @@ module ScopeFileAccessArchive
74
74
  content = file_content(system_file)
75
75
  return false if content.empty?
76
76
 
77
- Machinery.content_is_binary?(content.slice(0, 1024))
77
+ Machinery.content_is_binary?(content.slice(0, 4096))
78
78
  end
79
79
  end
@@ -30,7 +30,7 @@ module ScopeFileAccessFlat
30
30
  path = system_file.scope.file_path(system_file)
31
31
  return false if File.zero?(path)
32
32
 
33
- Machinery.content_is_binary?(File.read(path))
33
+ Machinery.content_is_binary?(File.read(path, 4096))
34
34
  end
35
35
 
36
36
  def has_file?(name)
data/lib/system.rb CHANGED
@@ -102,6 +102,40 @@ class System
102
102
  run_command("bash", "-c", script, *args)
103
103
  end
104
104
 
105
+ # Runs the given script on the inspected machine asynchronously and calls the callback method
106
+ # periodically with new output when it occurs.
107
+ #
108
+ # Example:
109
+ #
110
+ # count = 0
111
+ # raw_list = run_script_with_progress("changed_managed_files.sh") do |chunk|
112
+ # count += chunk.lines.count
113
+ # Machinery::Ui.progress("Found #{count} changed files...")
114
+ # end
115
+ def run_script_with_progress(*script, &callback)
116
+ output = ""
117
+ error = ""
118
+ write_io = StringIO.new(output, "a")
119
+ error_io = StringIO.new(error, "a")
120
+ read_io = StringIO.new(output, "r")
121
+
122
+ inspect_thread = Thread.new do
123
+ run_script(*script, stdout: write_io, stderr: error_io)
124
+ end
125
+
126
+ while inspect_thread.alive?
127
+ sleep 0.1
128
+ chunk = read_io.read
129
+ callback.call(chunk) if callback
130
+ end
131
+
132
+ if error.include?("password is required")
133
+ raise Machinery::Errors::InsufficientPrivileges.new(remote_user, host)
134
+ end
135
+
136
+ output
137
+ end
138
+
105
139
  def has_command?(command)
106
140
  run_command("bash", "-c", "type -P #{command}", stdout: :capture)
107
141
  true
@@ -116,4 +150,8 @@ class System
116
150
  def locale
117
151
  @locale || "C"
118
152
  end
153
+
154
+ def rpm_database
155
+ @rpm_database ||= RpmDatabase.new(self)
156
+ end
119
157
  end
data/lib/tarball.rb CHANGED
@@ -22,7 +22,7 @@ class Tarball
22
22
  end
23
23
 
24
24
  def list
25
- output = LoggedCheetah.run("tar", "tvf", @file, stdout: :capture)
25
+ output = LoggedCheetah.run("tar", "tvf", @file, "--quoting-style=literal", stdout: :capture)
26
26
 
27
27
  output.lines.map do |line|
28
28
  mode, user_and_group, size, _date, _time, rest = line.split(" ", 6)
data/lib/version.rb CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  module Machinery
19
19
 
20
- VERSION = "1.15.0"
20
+ VERSION = "1.16.0"
21
21
 
22
22
  end
@@ -10,4 +10,4 @@ and outputs the result in the
10
10
 
11
11
  Make sure that the official Go Development environment is installed.
12
12
 
13
- To build the helper binary just run `go build`.
13
+ To build the helper binary just run `rake build`.
@@ -2,4 +2,4 @@
2
2
 
3
3
  package main
4
4
 
5
- const VERSION = "b333b1358568df9a508e7d92c61d3280395911d9"
5
+ const VERSION = "f5f2a71bd21d86dcbc1b90e30b8af0f466b335bd"
Binary file
@@ -520,7 +520,7 @@ image under the <code>/tmp/tux/</code> directory:</p>
520
520
 
521
521
  <h3 id="SYNOPSIS">SYNOPSIS</h3>
522
522
 
523
- <p><code>machinery compare</code> [-s SCOPE | --scope=SCOPE] [-e EXCLUDE-SCOPE | --exclude-scope=EXCLUDE-SCOPE] [--no-pager] [--show-all] NAME1 NAME2</p>
523
+ <p><code>machinery compare</code> [-s SCOPE | --scope=SCOPE] [-e EXCLUDE-SCOPE | --exclude-scope=EXCLUDE-SCOPE] [--no-pager] [--show-all] [--html] NAME1 NAME2</p>
524
524
 
525
525
  <p><code>machinery</code> help compare</p>
526
526
 
@@ -546,6 +546,7 @@ See the <a href="#Scopes" data-bare-link="true">Scope section</a> for more infor
546
546
  See the <a href="#Scopes" data-bare-link="true">Scope section</a> for more information.</p></dd>
547
547
  <dt><code>--no-pager</code> (optional)</dt><dd><p>Do not pipe output into a pager.</p></dd>
548
548
  <dt><code>--show-all</code> (optional)</dt><dd><p>Show also common properties of the descriptions (not only the differences).</p></dd>
549
+ <dt><code>--html</code> (optional)</dt><dd><p>Shows the comparison of two system descriptions in the web browser.</p></dd>
549
550
  </dl>
550
551
 
551
552
 
@@ -562,6 +563,9 @@ See the <a href="#Scopes" data-bare-link="true">Scope section</a> for more infor
562
563
  list:</p>
563
564
 
564
565
  <p>$ <code>machinery</code> compare earth moon --scope=changed-managed-files --show-all</p></li>
566
+ <li><p>Compares system descriptions and shows the result in HTML format in your web browser:</p>
567
+
568
+ <p> $ machinery compare --html earth moon</p></li>
565
569
  </ul>
566
570
 
567
571
 
@@ -901,7 +905,7 @@ via <code>ssh-copy-id</code> to the inspected host, e.g.: <code>ssh-copy-id root
901
905
  <li><p>When inspecting as non-root the user has to have the following command
902
906
  whitelist given in the sudoers file:</p>
903
907
 
904
- <p>machinery ALL=(ALL) NOPASSWD: /usr/bin/find,/usr/bin/cat,/bin/cat,/usr/bin/rsync,/bin/rpm -V *,/bin/tar --create *</p></li>
908
+ <p>machinery ALL=(ALL) NOPASSWD: /usr/bin/find,/usr/bin/cat,/bin/cat,/usr/bin/rsync,/bin/rpm -Va *,/bin/tar --create *</p></li>
905
909
  <li><p>To add a remote <code>machinery</code> user run as root:</p>
906
910
 
907
911
  <h1><code>useradd -m machinery -c "remote user for machinery"</code></h1>
@@ -1376,7 +1380,7 @@ manually editing it.</p>
1376
1380
 
1377
1381
  <ol class='man-decor man-foot man foot'>
1378
1382
  <li class='tl'></li>
1379
- <li class='tc'>October 2015</li>
1383
+ <li class='tc'>November 2015</li>
1380
1384
  <li class='tr'>machinery(1)</li>
1381
1385
  </ol>
1382
1386
 
@@ -16,7 +16,6 @@
16
16
  # you may find current contact information at www.suse.com
17
17
 
18
18
  class ChangedManagedFilesInspector < Inspector
19
- include ChangedRpmFilesHelper
20
19
  has_priority 90
21
20
 
22
21
  def initialize(system, description)
@@ -69,73 +68,14 @@ class ChangedManagedFilesInspector < Inspector
69
68
 
70
69
  private
71
70
 
72
- def amend_file_attributes(changed_files)
73
- existing_files = changed_files.reject { |f| f.changes.nil? || f.changes.include?("deleted") }
74
- file_attributes = get_path_data(@system, existing_files.map(&:name))
75
- changed_files.map do |changed_file|
76
- if file_attributes[changed_file.name]
77
- ChangedManagedFile.new(changed_file.attributes.merge(file_attributes[changed_file.name]))
78
- else
79
- changed_file
80
- end
81
- end
82
- end
83
-
84
71
  def changed_files
85
72
  count = 0
86
- list = run_script_with_progress("changed_files.sh", "--", "changed-managed-files") do |chunk|
73
+ files = @system.rpm_database.changed_files do |chunk|
87
74
  count += chunk.lines.reject { |l| l.chomp.end_with?(":") || l.split(" ")[1] == "c" }.count
88
75
  Machinery::Ui.progress(" -> Found #{count} changed #{Machinery::pluralize(count, "file")}...")
89
76
  end
90
-
91
- # The raw list lists each package followed by the changed files, e.g.
92
- #
93
- # libpulse0-4.0.git.270.g9490a:
94
- # S.5...... c /etc/pulse/client.conf
95
- # ntp-4.2.6p5:
96
- # S.5...... c /etc/ntp.conf
97
- #
98
- # We map this to an array of files like this:
99
- #
100
- # [
101
- # {
102
- # name: "/etc/pulse/client.conf",
103
- # package_name: "libpulse0",
104
- # package_version: "4.0.git.270.g9490a"
105
- # },
106
- # ...
107
- # ]
108
- file_list = list.split("\n").slice_before(/(.*):\z/).flat_map do |package, *files|
109
- package_name, package_version = package.scan(/(.*)-([^-]*):/).first
110
- files.map do |changed_file|
111
- if changed_file =~ /\A(\/\S+) (.*)/
112
- ChangedManagedFile.new(
113
- name: $1,
114
- package_name: package_name,
115
- package_version: package_version,
116
- status: "error",
117
- error_message: $2
118
- )
119
- else
120
- file, changes, flag = parse_rpm_changes_line(changed_file)
121
-
122
- # Config files (flagged as 'c') are handled by the ConfigFilesInspector
123
- next if flag == "c"
124
-
125
- ChangedManagedFile.new(
126
- name: file,
127
- package_name: package_name,
128
- package_version: package_version,
129
- status: "changed",
130
- changes: changes
131
- )
132
- end
133
- # Since errors are also recognized for config-files we have
134
- # to filter them
135
- end.compact.select { |item| item.changes }
136
- end.uniq
137
-
138
- amend_file_attributes(file_list)
77
+ files.reject(&:config_file?).map do |file|
78
+ ChangedManagedFile.new(file.attributes)
79
+ end
139
80
  end
140
-
141
81
  end
@@ -16,8 +16,6 @@
16
16
  # you may find current contact information at www.suse.com
17
17
 
18
18
  class ConfigFilesInspector < Inspector
19
- include ChangedRpmFilesHelper
20
-
21
19
  has_priority 80
22
20
  # checks if all required binaries are present
23
21
  def check_requirements(check_rsync)
@@ -27,47 +25,15 @@ class ConfigFilesInspector < Inspector
27
25
  @system.check_retrieve_files_dependencies if check_rsync
28
26
  end
29
27
 
30
- # returns list of packages containing configfiles
31
- def packages_with_config_files
32
- # first determine packages that have config files at all
33
- # rpm command provides lines with package names and subsequent
34
- # lines with pathes of config files for that package
35
- # e.g.
36
- # apache2
37
- # /etc/apache2/charset.conv
38
- # /etc/apache2/default-server.conf
39
- #
40
- output = @system.run_command(
41
- "rpm", "-qa", "--configfiles", "--queryformat",
42
- "%{NAME}-%{VERSION}\n",
43
- :stdout => :capture
44
- )
45
- # use leading slash to decide between lines containing package names
46
- # and lines containing config files
47
- chunks = output.split("\n").slice_before { |l| !l.start_with?("/") }
48
- chunks.reject { |_pkg, *cfiles| cfiles.empty? }.map(&:first).uniq
49
- end
50
-
51
28
  # returns a hash with entries for changed config files
52
29
  def config_file_changes(pkg)
53
- out = @system.run_script("changed_files.sh", "--", "config-files", pkg, stdout: :capture)
54
- parts = pkg.split("-")
55
- package_name = parts[0..-2].join("-")
56
- package_version = parts.last
57
-
58
- paths_and_changes = out.lines.map { |line| parse_rpm_changes_line(line) }
59
- paths_and_changes.reject! do |path, changes, type|
60
- # only consider config files and only those with changes
61
- type != "c" || changes.empty?
62
- end
63
-
64
- paths_and_changes.map do |path, changes|
30
+ @system.changed_files.select(&:config_file?).map do |file|
65
31
  ConfigFile.new(
66
- name: path,
32
+ name: file.path,
67
33
  package_name: package_name,
68
34
  package_version: package_version,
69
35
  status: "changed",
70
- changes: changes
36
+ changes: file.changes
71
37
  )
72
38
  end.uniq
73
39
  end
@@ -82,12 +48,12 @@ class ConfigFilesInspector < Inspector
82
48
  check_requirements(do_extract)
83
49
 
84
50
  count = 0
85
- result = packages_with_config_files.flat_map do |package|
86
- files = config_file_changes(package)
87
- count += files.length
51
+ files = @system.rpm_database.changed_files do |chunk|
52
+ count += chunk.lines.count { |l| !l.chomp.end_with?(":") && l.split(" ")[1] == "c" }
88
53
  Machinery::Ui.progress(" -> Found #{count} config #{Machinery::pluralize(count, "file")}...")
89
-
90
- files
54
+ end
55
+ result = files.select(&:config_file?).map do |file|
56
+ ConfigFile.new(file.attributes)
91
57
  end
92
58
 
93
59
  if filter
@@ -95,16 +61,6 @@ class ConfigFilesInspector < Inspector
95
61
  result.delete_if { |e| file_filter.matches?(e.name) } if file_filter
96
62
  end
97
63
 
98
- paths = result.reject { |f| f.changes == Machinery::Array.new(["deleted"]) }.map(&:name)
99
- path_data = get_path_data(@system, paths)
100
- key_list = [:user, :group, :mode, :type, :target]
101
- result.each do |pkg|
102
- pname = pkg.name
103
- if path_data.has_key?(pname)
104
- key_list.each { |k| pkg[k] = path_data[pname][k] if path_data[pname][k] }
105
- end
106
- end
107
-
108
64
  scope = ConfigFilesScope.new
109
65
  file_store = @description.scope_file_store("config_files")
110
66
  scope.scope_file_store = file_store
@@ -94,6 +94,11 @@ class OsInspector < Inspector
94
94
  if result["pretty_name"] =~ /^openSUSE.*Tumbleweed/
95
95
  result["pretty_name"] = "openSUSE Tumbleweed"
96
96
  end
97
+
98
+ # remove Leap version from pretty name
99
+ if result["pretty_name"] =~ /^openSUSE.*Leap/
100
+ result["pretty_name"] = "openSUSE Leap"
101
+ end
97
102
  end
98
103
  # return pretty_name as name as it contains the actual full length
99
104
  # name instead of an abbreviation
@@ -192,6 +192,20 @@ class OsOpenSuseTumbleweed < Os
192
192
  end
193
193
  end
194
194
 
195
+ class OsOpenSuseLeap < Os
196
+ def display_name
197
+ "#{name} (#{architecture})"
198
+ end
199
+
200
+ def self.canonical_name
201
+ "openSUSE Leap"
202
+ end
203
+
204
+ def self.buildable_systems
205
+ [OsOpenSuse13_2, OsOpenSuseLeap]
206
+ end
207
+ end
208
+
195
209
  class Rhel < Os
196
210
  def self.canonical_name
197
211
  "Red Hat Enterprise Linux Server"
@@ -39,6 +39,7 @@ class UsersInspector < Inspector
39
39
  private
40
40
 
41
41
  def parse_users(passwd, shadow)
42
+ passwd = Machinery.scrub(passwd)
42
43
  users = passwd.lines.map { |l| l.split(":").first }
43
44
 
44
45
  users.map do |user|
@@ -22,6 +22,7 @@ class HelperBuilder
22
22
  def initialize(helper_dir)
23
23
  @helper_dir = helper_dir
24
24
  @git_revision_file = File.join(helper_dir, "..", ".git_revision")
25
+ @go_version_file = File.join(helper_dir, "version.go")
25
26
  end
26
27
 
27
28
  def run_build
@@ -30,7 +31,7 @@ class HelperBuilder
30
31
  return false if !go_available?
31
32
 
32
33
  # handle changed branches (where go files are older than the helper)
33
- if runs_in_git? && changed_revision?
34
+ if runs_in_git? && (changed_revision? || !File.exist?(@go_version_file))
34
35
  write_go_version_file
35
36
  if build_machinery_helper
36
37
  write_git_revision_file
@@ -56,7 +57,7 @@ package main
56
57
 
57
58
  const VERSION = "#{git_revision}"
58
59
  EOF
59
- File.write(File.join(@helper_dir, "version.go"), file)
60
+ File.write(@go_version_file, file)
60
61
  end
61
62
 
62
63
  def build_machinery_helper
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.15.0
4
+ version: 1.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SUSE
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-26 00:00:00.000000000 Z
11
+ date: 2015-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cheetah
@@ -304,7 +304,6 @@ files:
304
304
  - lib/array.rb
305
305
  - lib/autoyast.rb
306
306
  - lib/build_task.rb
307
- - lib/changed_rpm_files_helper.rb
308
307
  - lib/cli.rb
309
308
  - lib/compare_task.rb
310
309
  - lib/comparison.rb
@@ -352,6 +351,7 @@ files:
352
351
  - lib/renderer.rb
353
352
  - lib/renderer_helper.rb
354
353
  - lib/rpm.rb
354
+ - lib/rpm_database.rb
355
355
  - lib/scope.rb
356
356
  - lib/scope_file_access_archive.rb
357
357
  - lib/scope_file_access_flat.rb