machinery-tool 1.8.2 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS +13 -0
  3. data/helpers/changed_files.sh +105 -0
  4. data/helpers/filter-packages-for-build.yaml +2 -0
  5. data/lib/array.rb +8 -0
  6. data/lib/autoyast.rb +28 -26
  7. data/lib/build_task.rb +11 -2
  8. data/lib/changed_rpm_files_helper.rb +26 -7
  9. data/lib/cli.rb +12 -2
  10. data/lib/compare_task.rb +9 -2
  11. data/lib/config.rb +4 -0
  12. data/lib/element_filter.rb +4 -0
  13. data/lib/exceptions.rb +1 -0
  14. data/lib/exporter.rb +4 -0
  15. data/lib/file_validator.rb +3 -3
  16. data/lib/helper.rb +10 -4
  17. data/lib/inspector.rb +26 -0
  18. data/lib/kiwi_config.rb +36 -35
  19. data/lib/local_system.rb +19 -9
  20. data/lib/machinery.rb +2 -0
  21. data/lib/manifest.rb +1 -1
  22. data/lib/object.rb +8 -0
  23. data/lib/scope.rb +7 -1
  24. data/lib/scope_file_access.rb +67 -0
  25. data/lib/system.rb +2 -2
  26. data/lib/system_description.rb +26 -21
  27. data/lib/system_description_store.rb +1 -1
  28. data/lib/system_file.rb +44 -0
  29. data/lib/tarball.rb +1 -1
  30. data/lib/ui.rb +27 -0
  31. data/lib/upgrade_format_task.rb +1 -1
  32. data/lib/version.rb +1 -1
  33. data/lib/zypper.rb +1 -1
  34. data/man/generated/machinery.1.gz +0 -0
  35. data/man/generated/machinery.1.html +1 -1
  36. data/plugins/changed_managed_files/changed_managed_files_inspector.rb +27 -11
  37. data/plugins/changed_managed_files/changed_managed_files_model.rb +2 -1
  38. data/plugins/changed_managed_files/schema/system-description-changed-managed-files.schema-v4.json +126 -0
  39. data/plugins/config_files/config_files_inspector.rb +28 -23
  40. data/plugins/config_files/config_files_model.rb +2 -1
  41. data/plugins/config_files/schema/system-description-config-files.schema-v4.json +126 -0
  42. data/plugins/groups/schema/system-description-groups.schema-v4.json +30 -0
  43. data/plugins/os/os_inspector.rb +2 -2
  44. data/plugins/os/schema/system-description-os.schema-v4.json +21 -0
  45. data/plugins/packages/schema/system-description-packages.schema-v4.json +34 -0
  46. data/plugins/patterns/schema/system-description-patterns.schema-v4.json +24 -0
  47. data/plugins/repositories/schema/system-description-repositories.schema-v4.json +45 -0
  48. data/plugins/services/schema/system-description-services.schema-v4.json +30 -0
  49. data/plugins/unmanaged_files/schema/system-description-unmanaged-files.schema-v4.json +144 -0
  50. data/plugins/unmanaged_files/unmanaged_files_inspector.rb +34 -26
  51. data/plugins/unmanaged_files/unmanaged_files_model.rb +2 -1
  52. data/plugins/users/schema/system-description-users.schema-v4.json +61 -0
  53. data/schema/migrations/migrate3to4.rb +52 -0
  54. data/schema/system-description-global.schema-v4.json +43 -0
  55. metadata +17 -3
  56. data/helpers/changed_managed_files.sh +0 -46
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a9dfaf00e73b823dc8164aa283469baefd8e9ea4
4
- data.tar.gz: ccaf2f58602a73a1cac8a396c2134fc520ba48b6
3
+ metadata.gz: 7fa664c89d067292bb4703e9b8bba47651981831
4
+ data.tar.gz: 45c13a6f27432d9fc09ab306cdad7c07680df73f
5
5
  SHA512:
6
- metadata.gz: 493bf1127ae653467d41ea5c4c3ab20ac28b546cd10e1018b8de2c881faf57ca5c1c2e488cdd32679477452ed7a748ff2013a0e655a001cf9eb7ec8c842c78d3
7
- data.tar.gz: 397f7be936594a0b1b0eabadc988a360e4b561407787b4e809c8b16842e5e7d05f814d5548a0e9baaca98cbc2af870973d0037049067fe8a2fe7b86b6a481e3e
6
+ metadata.gz: f31cd802cb1ce442b18bb0dd374f9308371bf7376e168d97608d5a0ff94e10164d11c6cc0ed58c40aaad230338430c966f5013f3a8c49c940ab1ed45f810ca32
7
+ data.tar.gz: b1d69fc9f41836dab29ff51e449861517527b9b205ad5e6ccc6ef981199b40386518a93c02a98d3454b25bf842914c8da9f106a15179aa71e11c2e8b8b924908
data/NEWS CHANGED
@@ -1,6 +1,19 @@
1
1
  # Machinery Release Notes
2
2
 
3
3
 
4
+ ## Version 1.9.0 - Wed Jun 17 09:57:07 CEST 2015 - thardeck@suse.de
5
+
6
+ * Support links in changed managed files scope
7
+ * Support links in config files scope
8
+ * Introduce system description format version 4 (see https://github.com/SUSE/machinery/wiki/System-Description-Format#version-4)
9
+ * Show progress during inspection of scopes
10
+ * Show message when compared scopes are identical (gh#SUSE/machinery#631)
11
+ * Check number of parameters in all commands (gh#SUSE/machinery#898)
12
+ * Do not abort when Machinery is run on unsupported platforms, but just show a warning
13
+ * Apply all filters on file extraction (gh#SUSE/machinery#887)
14
+ * Consistent output of filters with --verbose option (gh#SUSE/machinery#797)
15
+ * Fix export of changed managed files with quotes in file name (gh#SUSE/machinery#913)
16
+
4
17
  ## Version 1.8.2 - Wed May 27 16:56:44 CEST 2015 - thardeck@suse.de
5
18
 
6
19
  * Fixed repository inspection using a non-root user
@@ -0,0 +1,105 @@
1
+ #!/bin/bash
2
+ # Copyright (c) 2013-2015 SUSE LLC
3
+ #
4
+ # This program is free software; you can redistribute it and/or
5
+ # modify it under the terms of version 3 of the GNU General Public License as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, contact SUSE LLC.
15
+ #
16
+ # To contact SUSE about this file by physical or electronic mail,
17
+ # you may find current contact information at www.suse.com
18
+
19
+ # Print a list of each package with changed managed files followed by a list of
20
+ # the changed files, e.g.
21
+ #
22
+ # libpulse0-4.0.git.270.g9490a:
23
+ # S.5...... c /etc/pulse/client.conf
24
+ # ntp-4.2.6p5:
25
+ # S.5...... c /etc/ntp.conf
26
+
27
+ # Exit immediately if a command exits with a non-zero status.
28
+ set -e
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
+ if [ $UID -ne "0" ]; then
49
+ sudoprefix="sudo -n"
50
+ fi
51
+
52
+ rpm_supports_noscripts_option () {
53
+ rpm -V --noscripts rpm > /dev/null
54
+ }
55
+
56
+ if rpm_supports_noscripts_option; then
57
+ noscripts="--noscripts"
58
+ fi
59
+
60
+ package_contains_verify_script () {
61
+ rpm --scripts -q $1 | grep "verify scriptlet" > /dev/null
62
+ }
63
+
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
+
@@ -1,4 +1,6 @@
1
1
  # check lib/os.rb for the distribution names
2
+ "openSUSE 13.2 (Harlequin)":
3
+ - openSUSE-release-dvd
2
4
  "openSUSE 13.1 (Bottle)":
3
5
  - openSUSE-release-dvd
4
6
  "SUSE Linux Enterprise Server 12":
@@ -49,11 +49,19 @@ module Machinery
49
49
  end
50
50
 
51
51
  attr_reader :elements
52
+ attr_accessor :scope
52
53
 
53
54
  def initialize(elements = [])
54
55
  @elements = self.class.convert_raw_array(elements)
55
56
  end
56
57
 
58
+ def scope=(scope)
59
+ @scope = scope
60
+ @elements.each do |child|
61
+ child.scope = @scope if child.respond_to?(:scope=)
62
+ end
63
+ end
64
+
57
65
  def ==(other)
58
66
  self.class == other.class && @elements == other.elements
59
67
  end
@@ -82,8 +82,8 @@ class Autoyast < Exporter
82
82
  apply_groups(xml)
83
83
  apply_services(xml)
84
84
 
85
- apply_extracted_files("config_files")
86
- apply_extracted_files("changed_managed_files")
85
+ apply_changed_files("config_files")
86
+ apply_changed_files("changed_managed_files")
87
87
  apply_unmanaged_files
88
88
  xml.scripts do
89
89
  apply_url_extraction(xml)
@@ -262,33 +262,37 @@ class Autoyast < Exporter
262
262
  end
263
263
  end
264
264
 
265
- def apply_extracted_files(scope)
266
- return if !@system_description[scope] || !@system_description[scope].extracted
267
-
268
- base = Pathname(@system_description.scope_file_store(scope).path)
269
- Dir["#{base}/**/*"].sort.each do |path|
270
- next if File.directory?(path)
271
-
272
- relative_path = Pathname(path).relative_path_from(base).to_s
273
- url = "`cat /tmp/description_url`/#{URI.escape(File.join(scope, relative_path))}"
274
-
275
- @chroot_scripts << "mkdir -p '#{File.join("/mnt", File.dirname(relative_path))}'"
276
- @chroot_scripts << "curl -o '#{File.join("/mnt", relative_path)}' \"#{url}\""
277
- end
278
-
279
- @system_description[scope].files.map do |file|
280
- if file.user
281
- @chroot_scripts << "chown #{file.user}:#{file.group} '#{File.join("/mnt", file.name)}'"
282
- end
283
- if file.mode
284
- @chroot_scripts << "chmod #{file.mode} '#{File.join("/mnt", file.name)}'"
265
+ def apply_changed_files(scope)
266
+ return if !@system_description.scope_extracted?(scope)
267
+
268
+ @system_description[scope].files.each do |file|
269
+ if file.deleted?
270
+ @chroot_scripts << "rm -rf '#{quote(file.name)}'"
271
+ elsif file.directory?
272
+ @chroot_scripts << <<EOF.strip
273
+ chmod #{file.mode} '#{File.join("/mnt", quote(file.name))}'
274
+ chown #{file.user}:#{file.group} '#{File.join("/mnt", quote(file.name))}'
275
+ EOF
276
+ elsif file.file?
277
+ url = "`cat /tmp/description_url`/#{URI.escape(File.join(scope, quote(file.name)))}"
278
+ @chroot_scripts << <<EOF.strip
279
+ mkdir -p '#{File.join("/mnt", File.dirname(quote(file.name)))}'
280
+ curl -o '#{File.join("/mnt", quote(file.name))}' \"#{url}\"
281
+ chmod #{file.mode} '#{File.join("/mnt", quote(file.name))}'
282
+ chown #{file.user}:#{file.group} '#{File.join("/mnt", quote(file.name))}'
283
+ EOF
284
+ elsif file.link?
285
+ @chroot_scripts << <<EOF.strip
286
+ rm -rf '#{File.join("/mnt", quote(file.name))}'
287
+ ln -s '#{quote(file.target)}' '#{File.join("/mnt", quote(file.name))}'
288
+ chown --no-dereference #{file.user}:#{file.group} '#{File.join("/mnt", quote(file.name))}'
289
+ EOF
285
290
  end
286
291
  end
287
292
  end
288
293
 
289
294
  def apply_unmanaged_files
290
- return if !@system_description.unmanaged_files ||
291
- !@system_description.unmanaged_files.extracted
295
+ return if !@system_description.scope_extracted?("unmanaged_files")
292
296
 
293
297
  base = Pathname(@system_description.scope_file_store("unmanaged_files").path)
294
298
  @chroot_scripts << <<-EOF.chomp.gsub(/^\s+/, "")
@@ -296,8 +300,6 @@ class Autoyast < Exporter
296
300
  EOF
297
301
 
298
302
  Dir["#{base}/**/*.tgz"].sort.each do |path|
299
- next if !path.end_with?(".tgz")
300
-
301
303
  relative_path = Pathname(path).relative_path_from(base).to_s
302
304
  tarball_name = File.basename(path)
303
305
  url = "`cat /tmp/description_url`#{URI.escape(File.join("/unmanaged_files", relative_path))}"
@@ -35,8 +35,12 @@ class BuildTask
35
35
  output_path, img_extension)
36
36
 
37
37
  begin
38
- LoggedCheetah.run("sudo", tmp_script.path, :stdout => $stdout,
39
- :stderr => $stderr)
38
+ LoggedCheetah.run(
39
+ "sudo",
40
+ tmp_script.path,
41
+ stdout: $stdout,
42
+ stderr: $stderr
43
+ )
40
44
  rescue SignalException => e
41
45
  # Handle SIGHUP(1), SIGINT(2) and SIGTERM(15) gracefully
42
46
  if [1, 2, 15].include?(e.signo)
@@ -62,6 +66,11 @@ class BuildTask
62
66
  end
63
67
  end
64
68
  raise
69
+ rescue Cheetah::ExecutionFailed
70
+ raise(
71
+ Machinery::Errors::BuildFailed,
72
+ "The execution of the build script failed."
73
+ )
65
74
  ensure
66
75
  tmp_script.delete
67
76
  end
@@ -69,32 +69,51 @@ module ChangedRpmFilesHelper
69
69
  end
70
70
 
71
71
  def parse_stat_line(line)
72
- mode, user, group, uid, gid, *path = line.split(":")
72
+ mode, user, group, uid, gid, type, *path = line.split(":")
73
73
 
74
74
  user = uid if user == "UNKNOWN"
75
75
  group = gid if group == "UNKNOWN"
76
76
 
77
+ type = case type
78
+ when "directory"
79
+ "dir"
80
+ when "symbolic link"
81
+ "link"
82
+ when "regular file"
83
+ "file"
84
+ end
85
+
77
86
  [path.join(":").chomp,
78
87
  {
79
- :mode => mode,
80
- :user => user,
81
- :group => group
88
+ mode: mode,
89
+ user: user,
90
+ group: group,
91
+ type: type
82
92
  }
83
93
  ]
84
94
  end
85
95
 
96
+ def get_link_target(system, link)
97
+ system.run_command(
98
+ "find", link, "-prune", "-printf", "%l",
99
+ stdout: :capture,
100
+ privileged: true
101
+ ).strip
102
+ end
103
+
86
104
  # get path data for list of files
87
105
  # cur_files is guaranteed to not exceed max command line length
88
106
  def get_file_properties(system, cur_files)
89
107
  ret = {}
90
108
  out = system.run_command(
91
- "stat", "--printf", "%a:%U:%G:%u:%g:%n\\n",
92
- *cur_files,
93
- :stdout => :capture
109
+ "stat", "--printf", "%a:%U:%G:%u:%g:%F:%n\\n",
110
+ *cur_files,
111
+ stdout: :capture
94
112
  )
95
113
  out.each_line do |l|
96
114
  path, values = parse_stat_line(l)
97
115
  ret[path] = values
116
+ ret[path][:target] = get_link_target(system, path) if values[:type] == "link"
98
117
  end
99
118
  ret
100
119
  end
data/lib/cli.rb CHANGED
@@ -37,6 +37,7 @@ class Cli
37
37
  else
38
38
  Machinery.logger.level = Logger::INFO
39
39
  end
40
+ check_exceeding_arguments(command.arguments, args)
40
41
  end
41
42
 
42
43
  post do |global_options,command,options,args|
@@ -56,6 +57,14 @@ class Cli
56
57
 
57
58
  GLI::Commands::Help.skips_post = false
58
59
 
60
+ def self.check_exceeding_arguments(defined, parsed)
61
+ if parsed.size > defined.size
62
+ message = "The given arguments don't match the command's specified arguments."
63
+ raise GLI::BadCommandLine.new(message)
64
+ end
65
+ true
66
+ end
67
+
59
68
  def self.buildable_distributions
60
69
  distribution_string = ""
61
70
  Os.supported_host_systems.each do |distribution|
@@ -74,7 +83,7 @@ class Cli
74
83
  GLI::UnknownCommand, GLI::BadCommandLine, OptionParser::MissingArgument
75
84
  Machinery::Ui.error e.to_s + "\n\n"
76
85
  command = ARGV & @commands.keys.map(&:to_s)
77
- run(command << "--help")
86
+ Machinery::Ui.error "Run '#{$0} #{command.first} --help' for more information."
78
87
  exit 1
79
88
  when Machinery::Errors::MachineryError
80
89
  Machinery.logger.error(e.message)
@@ -331,7 +340,8 @@ class Cli
331
340
 
332
341
  The system description is copied and stored under the provided name.
333
342
  LONGDESC
334
- arg_name "FROM_NAME TO_NAME"
343
+ arg "FROM_NAME"
344
+ arg "TO_NAME"
335
345
  command :copy do |c|
336
346
  c.action do |global_options,options,args|
337
347
  from = shift_arg(args, "FROM_NAME")
@@ -41,7 +41,7 @@ class CompareTask
41
41
  end
42
42
  end
43
43
 
44
- target = "/tmp/machinery-html-comparison"
44
+ target = File.join(Machinery::DEFAULT_CONFIG_DIR, "html-comparison")
45
45
  FileUtils.rm_r(target) if Dir.exists?(target)
46
46
  FileUtils.mkdir_p(target)
47
47
 
@@ -52,6 +52,7 @@ class CompareTask
52
52
  def render_comparison(description1, description2, scopes, options = {})
53
53
  output = ""
54
54
  identical = true
55
+ identical_scopes = []
55
56
  common_scopes = false
56
57
  store = description1.store
57
58
  scopes.each do |scope|
@@ -85,6 +86,8 @@ class CompareTask
85
86
 
86
87
  if partial_description1[scope] || partial_description2[scope]
87
88
  identical = false
89
+ else
90
+ identical_scopes << scope
88
91
  end
89
92
  common_scopes = true
90
93
  else
@@ -94,9 +97,13 @@ class CompareTask
94
97
  identical = false if description1[scope] || description2[scope]
95
98
  end
96
99
  end
97
-
98
100
  output = "Compared descriptions are identical.\n" + output if identical && common_scopes
99
101
 
102
+ if !identical_scopes.empty?
103
+ phrase = Machinery::pluralize(identical_scopes.count, "scope is", "scopes are")
104
+ output += "Following #{phrase} identical in both descriptions: " + identical_scopes.join(",")
105
+ end
106
+
100
107
  output
101
108
  end
102
109
  end
@@ -38,6 +38,10 @@ module Machinery
38
38
  description: "Enable experimental features. See " \
39
39
  "https://github.com/SUSE/machinery/wiki/Experimental-Features for more details"
40
40
  )
41
+ entry("perform_support_check",
42
+ default: true,
43
+ description: "Check whether the current platform is supported by Machinery"
44
+ )
41
45
  end
42
46
  end
43
47
  end
@@ -29,6 +29,10 @@ class ElementFilter
29
29
  add_matchers(operator, matchers) if operator && matchers
30
30
  end
31
31
 
32
+ def initialize_copy(other)
33
+ @matchers = other.matchers.dup
34
+ end
35
+
32
36
  def add_matchers(operator, matchers)
33
37
  if ![Filter::OPERATOR_EQUALS, Filter::OPERATOR_EQUALS_NOT].include?(operator)
34
38
  raise Machinery::Errors::InvalidFilter.new("Wrong filter operator '#{operator}'")
@@ -118,6 +118,7 @@ module Machinery
118
118
  class ElementFilterTypeMismatch < MachineryError
119
119
  attr_accessor :failed_matcher
120
120
  end
121
+ class FileUtilsError < MachineryError; end
121
122
 
122
123
  class BuildFailed < MachineryError; end
123
124
  class DeployFailed < MachineryError; end
@@ -21,4 +21,8 @@ class Exporter
21
21
 
22
22
  abstract_method :write
23
23
  abstract_method :export_name
24
+
25
+ def quote(name)
26
+ name.gsub("'", "'\\\\''")
27
+ end
24
28
  end