machinery-tool 1.5.0 → 1.6.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS +18 -0
  3. data/html/assets/machinery.css +20 -1
  4. data/html/assets/machinery.js +53 -26
  5. data/html/index.html.haml +69 -46
  6. data/lib/analyze_config_file_diffs_task.rb +1 -1
  7. data/lib/array.rb +36 -14
  8. data/lib/cli.rb +45 -50
  9. data/lib/compare_task.rb +1 -1
  10. data/lib/config.rb +8 -2
  11. data/lib/config_base.rb +14 -1
  12. data/lib/element_filter.rb +48 -11
  13. data/lib/exceptions.rb +5 -0
  14. data/lib/filter.rb +63 -14
  15. data/lib/filter_option_parser.rb +83 -0
  16. data/lib/generate_html_task.rb +3 -1
  17. data/lib/hint.rb +36 -18
  18. data/lib/html.rb +1 -0
  19. data/lib/inspect_task.rb +12 -21
  20. data/lib/inspector.rb +13 -6
  21. data/lib/kiwi_config.rb +17 -14
  22. data/lib/list_task.rb +5 -1
  23. data/lib/local_system.rb +3 -4
  24. data/lib/logged_cheetah.rb +3 -1
  25. data/lib/machinery.rb +1 -0
  26. data/lib/object.rb +24 -19
  27. data/lib/scope_file_store.rb +3 -1
  28. data/lib/show_task.rb +5 -7
  29. data/lib/system_description.rb +11 -12
  30. data/lib/system_description_store.rb +1 -1
  31. data/lib/ui.rb +44 -36
  32. data/lib/upgrade_format_task.rb +4 -1
  33. data/lib/version.rb +1 -1
  34. data/man/generated/machinery.1.gz +0 -0
  35. data/man/generated/machinery.1.html +7 -2
  36. data/plugins/inspect/changed_managed_files_inspector.rb +13 -6
  37. data/plugins/inspect/config_files_inspector.rb +27 -20
  38. data/plugins/inspect/groups_inspector.rb +12 -4
  39. data/plugins/inspect/os_inspector.rb +29 -22
  40. data/plugins/inspect/packages_inspector.rb +13 -5
  41. data/plugins/inspect/patterns_inspector.rb +24 -10
  42. data/plugins/inspect/repositories_inspector.rb +19 -15
  43. data/plugins/inspect/services_inspector.rb +28 -22
  44. data/plugins/inspect/unmanaged_files_inspector.rb +42 -33
  45. data/plugins/inspect/users_inspector.rb +13 -5
  46. data/plugins/model/os_model.rb +1 -1
  47. metadata +3 -2
@@ -51,7 +51,9 @@ class ScopeFileStore
51
51
  end
52
52
 
53
53
  def list_content
54
- files = Dir.glob(File.join(path, "**/{*,.*}"))
54
+ files = Dir.
55
+ glob(File.join(path, "**/*"), File::FNM_DOTMATCH).
56
+ reject { |path| [".", ".."].include?(File.basename(path)) }
55
57
  # filter parent directories because they should not be listed separately
56
58
  files.reject { |f| files.index { |e| e =~ /^#{f}\/.+/ } }
57
59
  end
data/lib/show_task.rb CHANGED
@@ -16,10 +16,11 @@
16
16
  # you may find current contact information at www.suse.com
17
17
 
18
18
  class ShowTask
19
- def show(description, scopes, options = {})
19
+ def show(description, scopes, filter, options = {})
20
20
  if options[:show_html]
21
21
  show_html(description)
22
22
  else
23
+ filter.apply!(description)
23
24
  show_console(description, scopes, options )
24
25
  end
25
26
  end
@@ -42,24 +43,21 @@ class ShowTask
42
43
 
43
44
  def show_console(description, scopes, options)
44
45
  missing_scopes = []
45
- output = ""
46
46
 
47
47
  scopes.map { |s| Renderer.for(s) }.each do |renderer|
48
48
  section = renderer.render(description, options)
49
49
  unless section.empty?
50
- output += section
50
+ Machinery::Ui.puts section
51
51
  else
52
52
  missing_scopes << renderer.scope
53
53
  end
54
54
  end
55
55
 
56
56
  if missing_scopes.length > 0
57
- output += "# The following requested scopes were not inspected\n\n"
57
+ Machinery::Ui.puts "# The following requested scopes were not inspected\n\n"
58
58
  missing_scopes.each do |scope|
59
- output += " * #{Machinery::Ui.internal_scope_list_to_string(scope)}\n"
59
+ Machinery::Ui.puts " * #{Machinery::Ui.internal_scope_list_to_string(scope)}\n"
60
60
  end
61
61
  end
62
-
63
- Machinery::Ui.print_output(output, :no_pager => options[:no_pager])
64
62
  end
65
63
  end
@@ -36,7 +36,7 @@ class SystemDescription < Machinery::Object
36
36
  attr_accessor :name
37
37
  attr_accessor :store
38
38
  attr_accessor :format_version
39
- attr_accessor :filters
39
+ attr_accessor :filter_definitions
40
40
 
41
41
  class << self
42
42
  # Load the system description with the given name
@@ -103,12 +103,7 @@ class SystemDescription < Machinery::Object
103
103
  description.format_version = json_format_version
104
104
 
105
105
  if hash["meta"] && hash["meta"]["filters"]
106
- hash["meta"]["filters"].each do |command, filter_definitions|
107
- description.filters[command] = Filter.new
108
- filter_definitions.each do |definition|
109
- description.filters[command].add_element_filter_from_definition(definition)
110
- end
111
- end
106
+ description.filter_definitions = hash["meta"]["filters"]
112
107
  end
113
108
 
114
109
  description
@@ -139,7 +134,7 @@ class SystemDescription < Machinery::Object
139
134
  @name = name
140
135
  @store = store
141
136
  @format_version = CURRENT_FORMAT_VERSION
142
- @filters = {}
137
+ @filter_definitions = {}
143
138
 
144
139
  super(hash)
145
140
  end
@@ -176,9 +171,9 @@ class SystemDescription < Machinery::Object
176
171
  attributes.keys.each do |key|
177
172
  meta[key] = self[key].meta.as_json if self[key].meta
178
173
  end
179
- @filters.each do |command, filter|
174
+ @filter_definitions.each do |command, filter|
180
175
  meta["filters"] ||= {}
181
- meta["filters"][command] = filter.to_array
176
+ meta["filters"][command] = filter
182
177
  end
183
178
 
184
179
  hash = as_json
@@ -199,14 +194,18 @@ class SystemDescription < Machinery::Object
199
194
  File.chmod(0600, path) if created
200
195
  end
201
196
 
202
- def set_filter(command, filter)
197
+ def filter_definitions(command)
198
+ @filter_definitions[command] || []
199
+ end
200
+
201
+ def set_filter_definitions(command, filter)
203
202
  if !["inspect"].include?(command)
204
203
  raise Machinery::Errors::MachineryError.new(
205
204
  "Storing the filter for command '#{command}' is not supported."
206
205
  )
207
206
  end
208
207
 
209
- @filters[command] = filter
208
+ @filter_definitions[command] = filter
210
209
  end
211
210
 
212
211
  def scopes
@@ -52,7 +52,7 @@ class SystemDescriptionStore
52
52
  def list
53
53
  Dir["#{@base_path}/*"].
54
54
  select { |item| File.exists?(manifest_path(File.basename(item)))}.
55
- map { |item| File.basename(item) }
55
+ map { |item| File.basename(item) }.sort
56
56
  end
57
57
 
58
58
  def remove(name)
data/lib/ui.rb CHANGED
@@ -17,58 +17,66 @@
17
17
 
18
18
  module Machinery
19
19
  class Ui
20
- def self.internal_scope_list_to_string(scopes)
21
- list = Array(scopes)
22
- list.map { |e| e.tr("_", "-") }.join(", ")
23
- end
20
+ class <<self
21
+ attr_accessor :use_pager
22
+
23
+ def internal_scope_list_to_string(scopes)
24
+ list = Array(scopes)
25
+ list.map { |e| e.tr("_", "-") }.join(", ")
26
+ end
27
+
28
+ def write_output_to_pager(output)
29
+ @pager ||= IO.popen("$PAGER", "w")
24
30
 
25
- def self.write_output_to_pager(output)
26
- IO.popen("$PAGER", "w") do |f|
27
31
  begin
28
- f.puts output
32
+ @pager.puts output
29
33
  rescue Errno::EPIPE
30
34
  # We just ignore broken pipes.
31
35
  end
32
36
  end
33
- end
34
37
 
35
- def self.print_output(output, options = {})
36
- if options[:no_pager] || !$stdout.tty?
37
- Machinery::Ui.puts output
38
- else
39
- if !ENV['PAGER'] || ENV['PAGER'] == ''
40
- ENV['PAGER'] = 'less'
41
- ENV['LESS'] = 'FSRX'
38
+ def close_pager
39
+ @pager.close if @pager
40
+ end
41
+
42
+ def puts(output)
43
+ if !use_pager || !$stdout.tty?
42
44
  begin
43
- LocalSystem.validate_existence_of_package("less")
44
- write_output_to_pager(output)
45
- rescue Machinery::Errors::MissingRequirement
46
- Machinery::Ui.puts output
45
+ STDOUT.puts output
46
+ rescue Errno::EPIPE
47
+ # We just ignore broken pipes.
47
48
  end
48
49
  else
49
- IO.popen("$PAGER &>/dev/null", "w") { |f| f.close }
50
- if $?.success?
51
- write_output_to_pager(output)
50
+ if !ENV['PAGER'] || ENV['PAGER'] == ''
51
+ ENV['PAGER'] = 'less'
52
+ ENV['LESS'] = 'FSRX'
53
+ begin
54
+ LocalSystem.validate_existence_of_package("less")
55
+ write_output_to_pager(output)
56
+ rescue Machinery::Errors::MissingRequirement
57
+ STDOUT.puts output
58
+ end
52
59
  else
53
- raise(Machinery::Errors::InvalidPager.new("'#{ENV['PAGER']}' could not " \
54
- "be executed. Use the --no-pager option or modify your $PAGER " \
55
- "bash environment variable to display output.")
56
- )
60
+ IO.popen("$PAGER &>/dev/null", "w") { |f| f.close }
61
+ if $?.success?
62
+ write_output_to_pager(output)
63
+ else
64
+ raise(Machinery::Errors::InvalidPager.new("'#{ENV['PAGER']}' could not " \
65
+ "be executed. Use the --no-pager option or modify your $PAGER " \
66
+ "bash environment variable to display output.")
67
+ )
68
+ end
57
69
  end
58
70
  end
59
71
  end
60
- end
61
-
62
- def self.puts(s)
63
- STDOUT.puts s
64
- end
65
72
 
66
- def self.warn(s)
67
- STDERR.puts s
68
- end
73
+ def warn(s)
74
+ STDERR.puts s
75
+ end
69
76
 
70
- def self.error(s)
71
- STDERR.puts s
77
+ def error(s)
78
+ STDERR.puts s
79
+ end
72
80
  end
73
81
  end
74
82
  end
@@ -35,6 +35,7 @@ class UpgradeFormatTask
35
35
  descriptions.each do |description|
36
36
  begin
37
37
  Machinery.logger.info "Upgrading description \"#{description}\""
38
+ Machinery::Ui.puts "Upgrading description \"#{description}\""
38
39
  migrated = Migration.migrate_description(store, description, force: options[:force])
39
40
  migrations_done += 1 if migrated
40
41
  rescue StandardError => e
@@ -44,7 +45,9 @@ class UpgradeFormatTask
44
45
 
45
46
  if !errors.empty?
46
47
  Machinery.logger.error errors.join("\n")
47
- raise Machinery::Errors::UpgradeFailed.new(errors.join("\n"))
48
+ exception = Machinery::Errors::UpgradeFailed.new(errors.join("\n") +
49
+ Hint.to_string(:upgrade_format_force, name: name || "--all"))
50
+ raise exception
48
51
  end
49
52
 
50
53
  if options[:all]
data/lib/version.rb CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  module Machinery
19
19
 
20
- VERSION = "1.5.0"
20
+ VERSION = "1.6.0"
21
21
 
22
22
  end
Binary file
@@ -865,7 +865,11 @@ by adding an '@' before the path, e.g.</p>
865
865
 
866
866
  <p>If a filename contains a comma it needs to be escaped, e.g.</p>
867
867
 
868
- <p> $ <code>machinery</code> inspect --skip-files=/file\,with_comma myhost</p></dd>
868
+ <p> $ <code>machinery</code> inspect --skip-files=/file\,with_comma myhost</p>
869
+
870
+ <p><strong>Note</strong>: File or directory names are not expanded, e.g. '../path' is taken
871
+ literally and not expanded.</p></dd>
872
+ <dt><code>--verbose</code> (optional)</dt><dd><p>Display the filters which are used during inspection.</p></dd>
869
873
  </dl>
870
874
 
871
875
 
@@ -1027,6 +1031,7 @@ See the <a href="#Scopes" data-bare-link="true">Scope section</a> for more infor
1027
1031
  <dt><code>--show-diffs</code> (optional)</dt><dd><p>Include the generated diffs in the output if available (see <code>machinery help analyze</code>
1028
1032
  for more information).</p></dd>
1029
1033
  <dt><code>--html</code> (optional)</dt><dd><p>Open the system description in HTML format in your web browser using the <code>xdg-open</code> command.</p></dd>
1034
+ <dt><code>--verbose</code> (optional)</dt><dd><p>Display the filters which were applied before showing the system description.</p></dd>
1030
1035
  </dl>
1031
1036
 
1032
1037
 
@@ -1162,7 +1167,7 @@ manually editing it.</p>
1162
1167
 
1163
1168
  <ol class='man-decor man-foot man foot'>
1164
1169
  <li class='tl'></li>
1165
- <li class='tc'>March 2015</li>
1170
+ <li class='tc'>April 2015</li>
1166
1171
  <li class='tr'>machinery(1)</li>
1167
1172
  </ol>
1168
1173
 
@@ -18,11 +18,16 @@
18
18
  class ChangedManagedFilesInspector < Inspector
19
19
  include ChangedRpmFilesHelper
20
20
 
21
- def inspect(system, description, _filter, options = {})
21
+ def initialize(system, description)
22
+ @system = system
23
+ @description = description
24
+ end
25
+
26
+ def inspect(_filter, options = {})
22
27
  system.check_requirement("rsync", "--version") if options[:extract_changed_managed_files]
23
28
 
24
29
  @system = system
25
- file_store = description.scope_file_store("changed_managed_files")
30
+ file_store = @description.scope_file_store("changed_managed_files")
26
31
 
27
32
  result = changed_files
28
33
 
@@ -39,13 +44,15 @@ class ChangedManagedFilesInspector < Inspector
39
44
  system.retrieve_files(existing_files.map(&:name), file_store.path)
40
45
  end
41
46
 
42
- summary = "#{options[:extract_changed_managed_files] ? "Extracted" : "Found"} #{result.count} changed files."
43
-
44
- description["changed_managed_files"] = ChangedManagedFilesScope.new(
47
+ @description["changed_managed_files"] = ChangedManagedFilesScope.new(
45
48
  extracted: !!options[:extract_changed_managed_files],
46
49
  files: ChangedManagedFileList.new(result.sort_by(&:name))
47
50
  )
48
- summary
51
+ end
52
+
53
+ def summary
54
+ "#{@description.changed_managed_files.extracted ? "Extracted" : "Found"} " +
55
+ "#{@description.changed_managed_files.files.count} changed files."
49
56
  end
50
57
 
51
58
  private
@@ -19,14 +19,14 @@ class ConfigFilesInspector < Inspector
19
19
  include ChangedRpmFilesHelper
20
20
 
21
21
  # checks if all required binaries are present
22
- def check_requirements(system, check_rsync)
23
- system.check_requirement("rpm", "--version")
24
- system.check_requirement("stat", "--version")
25
- system.check_requirement("rsync", "--version") if check_rsync
22
+ def check_requirements(check_rsync)
23
+ @system.check_requirement("rpm", "--version")
24
+ @system.check_requirement("stat", "--version")
25
+ @system.check_requirement("rsync", "--version") if check_rsync
26
26
  end
27
27
 
28
28
  # returns list of packages containing configfiles
29
- def packages_with_config_files(system)
29
+ def packages_with_config_files
30
30
  # first determine packages that have config files at all
31
31
  # rpm command provides lines with package names and subsequent
32
32
  # lines with pathes of config files for that package
@@ -35,7 +35,7 @@ class ConfigFilesInspector < Inspector
35
35
  # /etc/apache2/charset.conv
36
36
  # /etc/apache2/default-server.conf
37
37
  #
38
- output = system.run_command(
38
+ output = @system.run_command(
39
39
  "rpm", "-qa", "--configfiles", "--queryformat",
40
40
  "%{NAME}-%{VERSION}\n",
41
41
  :stdout => :capture
@@ -47,9 +47,9 @@ class ConfigFilesInspector < Inspector
47
47
  end
48
48
 
49
49
  # returns a hash with entries for changed config files
50
- def config_file_changes(system, pkg)
50
+ def config_file_changes(pkg)
51
51
  begin
52
- out = system.run_command(
52
+ out = @system.run_command(
53
53
  "rpm", "-V",
54
54
  "--nodeps", "--nodigest", "--nosignature", "--nomtime", "--nolinkto",
55
55
  pkg,
@@ -82,16 +82,21 @@ class ConfigFilesInspector < Inspector
82
82
  end
83
83
  end
84
84
 
85
- def inspect(system, description, _filter, options = {})
85
+ def initialize(system, description)
86
+ @system = system
87
+ @description = description
88
+ end
89
+
90
+ def inspect(_filter, options = {})
86
91
  do_extract = options[:extract_changed_config_files]
87
- check_requirements(system, do_extract)
92
+ check_requirements(do_extract)
88
93
 
89
- result = packages_with_config_files(system).flat_map do |package|
90
- config_file_changes(system, package)
94
+ result = packages_with_config_files.flat_map do |package|
95
+ config_file_changes(package)
91
96
  end
92
97
 
93
- paths = result.reject { |f| f.changes == ["deleted"] }.map(&:name)
94
- path_data = get_path_data(system, paths)
98
+ paths = result.reject { |f| f.changes == Machinery::Array.new(["deleted"]) }.map(&:name)
99
+ path_data = get_path_data(@system, paths)
95
100
  key_list = [ :user, :group, :mode ]
96
101
  result.each do |pkg|
97
102
  pname = pkg.name
@@ -100,19 +105,21 @@ class ConfigFilesInspector < Inspector
100
105
  end
101
106
  end
102
107
 
103
- file_store = description.scope_file_store("config_files")
108
+ file_store = @description.scope_file_store("config_files")
104
109
  file_store.remove
105
110
  if do_extract
106
111
  file_store.create
107
- system.retrieve_files(paths, file_store.path)
112
+ @system.retrieve_files(paths, file_store.path)
108
113
  end
109
114
 
110
- summary = "#{do_extract ? "Extracted" : "Found"} #{result.count} changed configuration files."
111
-
112
- description["config_files"] = ConfigFilesScope.new(
115
+ @description["config_files"] = ConfigFilesScope.new(
113
116
  extracted: !!do_extract,
114
117
  files: ConfigFileList.new(result.sort_by(&:name))
115
118
  )
116
- summary
119
+ end
120
+
121
+ def summary
122
+ "#{@description.config_files.extracted ? "Extracted" : "Found"} " +
123
+ "#{@description.config_files.files.count} changed configuration files."
117
124
  end
118
125
  end
@@ -16,13 +16,21 @@
16
16
  # you may find current contact information at www.suse.com
17
17
 
18
18
  class GroupsInspector < Inspector
19
- def inspect(system, description, _filter, _options = {})
20
- group_content = system.read_file("/etc/group")
19
+ def initialize(system, description)
20
+ @system = system
21
+ @description = description
22
+ end
23
+
24
+ def inspect(_filter, _options = {})
25
+ group_content = @system.read_file("/etc/group")
21
26
 
22
27
  groups = group_content ? parse_groups(group_content) : []
23
28
 
24
- description.groups = GroupsScope.new(groups.sort_by(&:name))
25
- "Found #{groups.size} groups."
29
+ @description.groups = GroupsScope.new(groups.sort_by(&:name))
30
+ end
31
+
32
+ def summary
33
+ "Found #{@description.groups.size} groups."
26
34
  end
27
35
 
28
36
  private