machinery-tool 1.4.0 → 1.5.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.
- checksums.yaml +4 -4
- data/NEWS +7 -0
- data/bin/machinery +3 -1
- data/helpers/default_filters.json +24 -0
- data/helpers/yum_repositories.py +8 -2
- data/lib/autoyast.rb +8 -3
- data/lib/changed_rpm_files_helper.rb +34 -7
- data/lib/cli.rb +149 -101
- data/lib/element_filter.rb +45 -0
- data/lib/exceptions.rb +3 -2
- data/lib/filter.rb +121 -0
- data/lib/inspect_task.rb +25 -4
- data/lib/kiwi_config.rb +11 -0
- data/lib/list_task.rb +53 -26
- data/lib/local_system.rb +1 -1
- data/lib/machinery.rb +2 -0
- data/lib/manifest.rb +3 -2
- data/lib/migration.rb +2 -2
- data/lib/system_description.rb +33 -4
- data/lib/tarball.rb +5 -5
- data/lib/version.rb +1 -1
- data/lib/zypper.rb +12 -17
- data/man/generated/machinery.1.gz +0 -0
- data/man/generated/machinery.1.html +21 -4
- data/plugins/docs/changed_managed_files.md +3 -1
- data/plugins/docs/config_files.md +3 -2
- data/plugins/inspect/changed_managed_files_inspector.rb +8 -2
- data/plugins/inspect/config_files_inspector.rb +1 -1
- data/plugins/inspect/groups_inspector.rb +3 -1
- data/plugins/inspect/os_inspector.rb +2 -2
- data/plugins/inspect/packages_inspector.rb +1 -1
- data/plugins/inspect/patterns_inspector.rb +1 -1
- data/plugins/inspect/repositories_inspector.rb +1 -1
- data/plugins/inspect/services_inspector.rb +1 -1
- data/plugins/inspect/unmanaged_files_inspector.rb +17 -42
- data/plugins/inspect/users_inspector.rb +1 -1
- data/plugins/schema/v3/system-description-changed-managed-files.schema.json +1 -1
- data/plugins/schema/v3/system-description-config-files.schema.json +1 -1
- data/plugins/schema/v3/system-description-repositories.schema.json +1 -1
- data/schema/v3/system-description-global.schema.json +12 -0
- metadata +5 -2
@@ -0,0 +1,45 @@
|
|
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 ElementFilter
|
19
|
+
attr_accessor :path, :matchers
|
20
|
+
|
21
|
+
def initialize(path, matchers = nil)
|
22
|
+
@path = path
|
23
|
+
@matchers = []
|
24
|
+
|
25
|
+
raise("Wrong type") if ![NilClass, String, Array].include?(matchers.class)
|
26
|
+
|
27
|
+
add_matchers(matchers) if matchers
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_matchers(matchers)
|
31
|
+
@matchers += Array(matchers)
|
32
|
+
end
|
33
|
+
|
34
|
+
def matches?(value)
|
35
|
+
@matchers.each do |matcher|
|
36
|
+
if matcher.end_with?("*")
|
37
|
+
return true if value.start_with?(matcher[0..-2])
|
38
|
+
else
|
39
|
+
return true if value == matcher
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
data/lib/exceptions.rb
CHANGED
@@ -38,10 +38,11 @@ module Machinery
|
|
38
38
|
class SystemDescriptionNotFound < SystemDescriptionError; end
|
39
39
|
|
40
40
|
class SystemDescriptionIncompatible < SystemDescriptionError
|
41
|
-
attr_reader :name
|
41
|
+
attr_reader :name, :format_version
|
42
42
|
|
43
|
-
def initialize(name)
|
43
|
+
def initialize(name, format_version)
|
44
44
|
@name = name
|
45
|
+
@format_version = format_version
|
45
46
|
end
|
46
47
|
|
47
48
|
def to_s
|
data/lib/filter.rb
ADDED
@@ -0,0 +1,121 @@
|
|
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
|
+
# The Filter class is used to hold the information about the filter conditions
|
19
|
+
# that should be applied during certain Machinery commands.
|
20
|
+
#
|
21
|
+
# Filters are usually created by passing a filter definition string to the
|
22
|
+
# constructor, e.g.
|
23
|
+
#
|
24
|
+
# filter = Filter.new("/unmanaged_files/files/name=/opt")
|
25
|
+
#
|
26
|
+
# Existing filters can be extended by amending the definition:
|
27
|
+
#
|
28
|
+
# filter.add_element_filter_from_definition("/unmanaged_files/files/name=/srv")
|
29
|
+
#
|
30
|
+
# or by adding ElementFilters directly:
|
31
|
+
#
|
32
|
+
# element_filter = ElementFilter.new("/unmanaged_files/files/name", ["/opt", "/srv"])
|
33
|
+
# filter.add_element_filter(element_filter)
|
34
|
+
#
|
35
|
+
#
|
36
|
+
# The actual filtering can be done by passing values to Filter#matches?
|
37
|
+
#
|
38
|
+
# filter = Filter.new("/unmanaged_files/files/name=/opt*")
|
39
|
+
# filter.matches?("/unmanaged_files/files/name", "/opt/foo")
|
40
|
+
# => true
|
41
|
+
# filter.matches?("/unmanaged_files/files/name", "/srv/bar")
|
42
|
+
# => false
|
43
|
+
#
|
44
|
+
# More details about how the filter work can be found at
|
45
|
+
# https://github.com/SUSE/machinery/blob/master/docs/Filtering-Design.md
|
46
|
+
class Filter
|
47
|
+
attr_accessor :element_filters
|
48
|
+
|
49
|
+
def self.parse_filter_definitions(filter_definitions)
|
50
|
+
element_filters = {}
|
51
|
+
Array(filter_definitions).each do |definition|
|
52
|
+
path, matcher_definition = definition.split("=", 2)
|
53
|
+
|
54
|
+
element_filters[path] ||= ElementFilter.new(path)
|
55
|
+
if matcher_definition.index(",")
|
56
|
+
matchers = matcher_definition.split(/(?<!\\),/)
|
57
|
+
matchers.map! { |matcher| matcher.gsub("\\,", ",") } # Unescape escaped commas
|
58
|
+
|
59
|
+
element_filters[path].add_matchers([matchers])
|
60
|
+
else
|
61
|
+
element_filters[path].add_matchers(matcher_definition)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
element_filters
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.from_default_definition(command)
|
69
|
+
filter = Filter.new
|
70
|
+
|
71
|
+
default_filters_file = File.join(Machinery::ROOT, "helpers/default_filters.json")
|
72
|
+
if File.exists?(default_filters_file)
|
73
|
+
default_filters = JSON.parse(File.read(default_filters_file))
|
74
|
+
if default_filters[command]
|
75
|
+
default_filters[command].each do |definition|
|
76
|
+
filter.add_element_filter_from_definition(definition)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
filter
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize(definitions = [])
|
85
|
+
@element_filters = Filter.parse_filter_definitions(definitions)
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_element_filter_from_definition(filter_definition)
|
89
|
+
new_element_filters = Filter.parse_filter_definitions(filter_definition)
|
90
|
+
|
91
|
+
new_element_filters.each do |path, element_filter|
|
92
|
+
@element_filters[path] ||= ElementFilter.new(path)
|
93
|
+
@element_filters[path].add_matchers(element_filter.matchers)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_element_filter(element_filter)
|
98
|
+
path = element_filter.path
|
99
|
+
@element_filters[path] ||= ElementFilter.new(path)
|
100
|
+
@element_filters[path].add_matchers(element_filter.matchers)
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_array
|
104
|
+
@element_filters.flat_map do |path, element_filter|
|
105
|
+
element_filter.matchers.map do |matcher|
|
106
|
+
"#{path}=#{Array(matcher).join(",")}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def matches?(path, value)
|
112
|
+
filter = element_filter_for(path)
|
113
|
+
return false if !filter
|
114
|
+
|
115
|
+
filter.matches?(value)
|
116
|
+
end
|
117
|
+
|
118
|
+
def element_filter_for(path)
|
119
|
+
element_filters[path]
|
120
|
+
end
|
121
|
+
end
|
data/lib/inspect_task.rb
CHANGED
@@ -16,11 +16,12 @@
|
|
16
16
|
# you may find current contact information at www.suse.com
|
17
17
|
|
18
18
|
class InspectTask
|
19
|
-
def inspect_system(store, host, name, current_user, scopes, options = {})
|
19
|
+
def inspect_system(store, host, name, current_user, scopes, filter, options = {})
|
20
20
|
system = System.for(host)
|
21
21
|
check_root(system, current_user)
|
22
22
|
|
23
|
-
description, failed_inspections = build_description(store, name, system,
|
23
|
+
description, failed_inspections = build_description(store, name, system,
|
24
|
+
scopes, filter, options)
|
24
25
|
|
25
26
|
if !description.attributes.empty?
|
26
27
|
print_description(description, scopes) if options[:show]
|
@@ -57,7 +58,17 @@ class InspectTask
|
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
60
|
-
def
|
61
|
+
def adapt_filter_in_metadata(filter_in_metadata, scope, filter)
|
62
|
+
filter_in_metadata.element_filters.
|
63
|
+
reject! { |path, _filter| path.start_with?("/#{scope}") }
|
64
|
+
filter.element_filters.
|
65
|
+
select { |path, _filter| path.start_with?("/#{scope}") }.
|
66
|
+
each do |_path, element_filter|
|
67
|
+
filter_in_metadata.add_element_filter(element_filter)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_description(store, name, system, scopes, filter, options)
|
61
72
|
begin
|
62
73
|
description = SystemDescription.load(name, store)
|
63
74
|
rescue Machinery::Errors::SystemDescriptionNotFound
|
@@ -72,17 +83,27 @@ class InspectTask
|
|
72
83
|
|
73
84
|
failed_inspections = {}
|
74
85
|
|
86
|
+
if description.filters["inspect"]
|
87
|
+
filter_in_metadata = description.filters["inspect"]
|
88
|
+
else
|
89
|
+
filter_in_metadata = Filter.new
|
90
|
+
end
|
91
|
+
|
75
92
|
scopes.map { |s| Inspector.for(s) }.each do |inspector|
|
76
93
|
Machinery::Ui.puts "Inspecting #{Machinery::Ui.internal_scope_list_to_string(inspector.scope)}..."
|
77
94
|
begin
|
78
|
-
summary = inspector.inspect(system, description, options)
|
95
|
+
summary = inspector.inspect(system, description, filter, options)
|
79
96
|
rescue Machinery::Errors::MachineryError => e
|
80
97
|
Machinery::Ui.puts " -> Inspection failed!"
|
81
98
|
failed_inspections[inspector.scope] = e
|
82
99
|
next
|
83
100
|
end
|
84
101
|
description[inspector.scope].set_metadata(timestring, host)
|
102
|
+
|
103
|
+
adapt_filter_in_metadata(filter_in_metadata, inspector.scope, filter)
|
104
|
+
|
85
105
|
if !description.attributes.empty?
|
106
|
+
description.set_filter("inspect", filter_in_metadata)
|
86
107
|
description.save
|
87
108
|
end
|
88
109
|
Machinery::Ui.puts " -> " + summary
|
data/lib/kiwi_config.rb
CHANGED
@@ -221,6 +221,7 @@ EOF
|
|
221
221
|
|
222
222
|
def apply_repositories(xml)
|
223
223
|
if @system_description.repositories
|
224
|
+
usable_repositories = false
|
224
225
|
@system_description.repositories.each do |repo|
|
225
226
|
# workaround kiwi issue by replacing spaces
|
226
227
|
# the final image is not affected because the repositories are added by the config.sh
|
@@ -231,6 +232,7 @@ EOF
|
|
231
232
|
end
|
232
233
|
# only use accessible repositories as source for kiwi build
|
233
234
|
if repo.enabled && !repo.type.nil? && !repo.external_medium?
|
235
|
+
usable_repositories = true
|
234
236
|
xml.repository(parameters) do
|
235
237
|
xml.source(path: repo.url)
|
236
238
|
end
|
@@ -244,6 +246,15 @@ EOF
|
|
244
246
|
@sh << "zypper -n mr --priority=#{repo.priority} '#{repo.name}'\n"
|
245
247
|
end
|
246
248
|
end
|
249
|
+
if !usable_repositories
|
250
|
+
raise(
|
251
|
+
Machinery::Errors::MissingRequirement.new(
|
252
|
+
"The system description doesn't contain any enabled or network reachable repository." \
|
253
|
+
" Please make sure that there is at least one accessible repository with all the" \
|
254
|
+
" required packages."
|
255
|
+
)
|
256
|
+
)
|
257
|
+
end
|
247
258
|
end
|
248
259
|
end
|
249
260
|
|
data/lib/list_task.rb
CHANGED
@@ -20,45 +20,72 @@ class ListTask
|
|
20
20
|
descriptions = store.list.sort
|
21
21
|
|
22
22
|
descriptions.each do |name|
|
23
|
-
name = File.basename(name)
|
24
23
|
begin
|
25
24
|
description = SystemDescription.load(name, store, skip_validation: true)
|
25
|
+
rescue Machinery::Errors::SystemDescriptionIncompatible => e
|
26
|
+
if !e.format_version
|
27
|
+
show_error("#{name}: incompatible format version. Can not be upgraded.\n", options)
|
28
|
+
elsif e.format_version < SystemDescription::CURRENT_FORMAT_VERSION
|
29
|
+
show_error("#{name}: format version #{e.format_version}, " \
|
30
|
+
"needs to be upgraded.\n", options)
|
31
|
+
else
|
32
|
+
show_error("#{name}: format version #{e.format_version}. " \
|
33
|
+
"Please upgrade Machinery to the latest version.\n", options)
|
34
|
+
end
|
35
|
+
next
|
36
|
+
rescue Machinery::Errors::SystemDescriptionValidationFailed
|
37
|
+
show_error("#{name}: This description is broken. Use " \
|
38
|
+
"`#{$0} validate #{name}` to see the error message.\n", options)
|
39
|
+
next
|
26
40
|
rescue Machinery::Errors::SystemDescriptionError
|
27
|
-
|
28
|
-
Machinery::Ui.puts " This description has an incompatible data format or is broken.\n" \
|
29
|
-
" Use `#{$0} validate #{name}` to see the error message.\n\n"
|
41
|
+
show_error("#{name}: This description is broken.\n", options)
|
30
42
|
next
|
31
43
|
end
|
32
|
-
scopes = []
|
33
44
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
45
|
+
if options[:short]
|
46
|
+
Machinery::Ui.puts name
|
47
|
+
else
|
48
|
+
scopes = []
|
49
|
+
|
50
|
+
description.scopes.each do |scope|
|
51
|
+
entry = Machinery::Ui.internal_scope_list_to_string(scope)
|
52
|
+
if SystemDescription::EXTRACTABLE_SCOPES.include?(scope)
|
53
|
+
if description.scope_extracted?(scope)
|
54
|
+
entry += " (extracted)"
|
55
|
+
else
|
56
|
+
entry += " (not extracted)"
|
57
|
+
end
|
41
58
|
end
|
42
|
-
end
|
43
59
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
60
|
+
if options[:verbose]
|
61
|
+
meta = description[scope].meta
|
62
|
+
if meta
|
63
|
+
time = Time.parse(meta.modified).getlocal
|
64
|
+
date = time.strftime "%Y-%m-%d %H:%M:%S"
|
65
|
+
hostname = meta.hostname
|
66
|
+
else
|
67
|
+
date = "unknown"
|
68
|
+
hostname = "Unknown hostname"
|
69
|
+
end
|
70
|
+
entry += "\n Host: [#{hostname}]"
|
71
|
+
entry += "\n Date: (#{date})"
|
53
72
|
end
|
54
|
-
|
55
|
-
|
73
|
+
|
74
|
+
scopes << entry
|
56
75
|
end
|
57
76
|
|
58
|
-
scopes
|
77
|
+
Machinery::Ui.puts " #{name}:\n * " + scopes .join("\n * ") + "\n\n"
|
59
78
|
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
60
83
|
|
61
|
-
|
84
|
+
def show_error(error_message, options)
|
85
|
+
if options[:short]
|
86
|
+
Machinery::Ui.puts(error_message)
|
87
|
+
else
|
88
|
+
Machinery::Ui.puts(" " + error_message + "\n")
|
62
89
|
end
|
63
90
|
end
|
64
91
|
end
|
data/lib/local_system.rb
CHANGED
@@ -24,7 +24,7 @@ class LocalSystem < System
|
|
24
24
|
description = SystemDescription.new("localhost",
|
25
25
|
SystemDescriptionMemoryStore.new)
|
26
26
|
inspector = OsInspector.new
|
27
|
-
inspector.inspect(System.for("localhost"), description)
|
27
|
+
inspector.inspect(System.for("localhost"), description, nil)
|
28
28
|
@@os = description.os
|
29
29
|
end
|
30
30
|
@@os
|
data/lib/machinery.rb
CHANGED
@@ -87,6 +87,8 @@ require_relative "scope_file_store"
|
|
87
87
|
require_relative "json_validator"
|
88
88
|
require_relative "json_validation_error_cleaner"
|
89
89
|
require_relative "file_validator"
|
90
|
+
require_relative "element_filter"
|
91
|
+
require_relative "filter"
|
90
92
|
|
91
93
|
Dir[File.join(Machinery::ROOT, "plugins", "**", "*.rb")].each { |f| require(f) }
|
92
94
|
|
data/lib/manifest.rb
CHANGED
@@ -55,7 +55,7 @@ class Manifest
|
|
55
55
|
|
56
56
|
errors = JsonValidator.new(@hash).validate
|
57
57
|
if !errors.empty?
|
58
|
-
raise Machinery::Errors::
|
58
|
+
raise Machinery::Errors::SystemDescriptionValidationFailed.new(errors)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -74,7 +74,6 @@ class Manifest
|
|
74
74
|
|
75
75
|
# remove needless json error information
|
76
76
|
lines[0].gsub!(/^\d+: (.*)$/, "\\1")
|
77
|
-
json_error = lines[0..block_end].join("\n")
|
78
77
|
|
79
78
|
if error_pos == 1
|
80
79
|
json_error = "An opening bracket, a comma or quotation is missing " \
|
@@ -84,6 +83,8 @@ class Manifest
|
|
84
83
|
error_pos = nil
|
85
84
|
end
|
86
85
|
|
86
|
+
json_error ||= lines[0..block_end].join("\n")
|
87
|
+
|
87
88
|
error = "The JSON data of the system description '#{name}' " \
|
88
89
|
"couldn't be parsed. The following error occured"
|
89
90
|
error += " around line #{error_pos}" if error_pos
|
data/lib/migration.rb
CHANGED
@@ -75,13 +75,13 @@ class Migration
|
|
75
75
|
Machinery::Ui.warn("Warning: System Description validation errors:")
|
76
76
|
Machinery::Ui.warn(errors)
|
77
77
|
else
|
78
|
-
raise Machinery::Errors::
|
78
|
+
raise Machinery::Errors::SystemDescriptionValidationFailed.new(errors)
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
82
|
current_version = hash["meta"]["format_version"]
|
83
83
|
if !current_version
|
84
|
-
raise Machinery::Errors::
|
84
|
+
raise Machinery::Errors::SystemDescriptionIncompatible.new(
|
85
85
|
"The system description '#{description_name}' was generated by an old " \
|
86
86
|
"version of machinery that is not supported by the upgrade mechanism."
|
87
87
|
)
|
data/lib/system_description.rb
CHANGED
@@ -36,6 +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
40
|
|
40
41
|
class << self
|
41
42
|
# Load the system description with the given name
|
@@ -89,14 +90,27 @@ class SystemDescription < Machinery::Object
|
|
89
90
|
|
90
91
|
def from_hash(name, store, hash)
|
91
92
|
begin
|
93
|
+
json_format_version = hash["meta"]["format_version"] if hash["meta"]
|
92
94
|
description = SystemDescription.new(name, store, create_scopes(hash))
|
93
|
-
rescue NameError
|
94
|
-
|
95
|
+
rescue NameError, TypeError
|
96
|
+
if json_format_version && json_format_version != SystemDescription::CURRENT_FORMAT_VERSION
|
97
|
+
raise Machinery::Errors::SystemDescriptionIncompatible.new(name, json_format_version)
|
98
|
+
else
|
99
|
+
raise Machinery::Errors::SystemDescriptionError.new
|
100
|
+
end
|
95
101
|
end
|
96
102
|
|
97
|
-
json_format_version = hash["meta"]["format_version"] if hash["meta"]
|
98
103
|
description.format_version = json_format_version
|
99
104
|
|
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
|
112
|
+
end
|
113
|
+
|
100
114
|
description
|
101
115
|
end
|
102
116
|
|
@@ -125,6 +139,7 @@ class SystemDescription < Machinery::Object
|
|
125
139
|
@name = name
|
126
140
|
@store = store
|
127
141
|
@format_version = CURRENT_FORMAT_VERSION
|
142
|
+
@filters = {}
|
128
143
|
|
129
144
|
super(hash)
|
130
145
|
end
|
@@ -136,7 +151,7 @@ class SystemDescription < Machinery::Object
|
|
136
151
|
|
137
152
|
def validate_format_compatibility
|
138
153
|
if !compatible?
|
139
|
-
raise Machinery::Errors::SystemDescriptionIncompatible.new(
|
154
|
+
raise Machinery::Errors::SystemDescriptionIncompatible.new(name, format_version)
|
140
155
|
end
|
141
156
|
end
|
142
157
|
|
@@ -161,6 +176,10 @@ class SystemDescription < Machinery::Object
|
|
161
176
|
attributes.keys.each do |key|
|
162
177
|
meta[key] = self[key].meta.as_json if self[key].meta
|
163
178
|
end
|
179
|
+
@filters.each do |command, filter|
|
180
|
+
meta["filters"] ||= {}
|
181
|
+
meta["filters"][command] = filter.to_array
|
182
|
+
end
|
164
183
|
|
165
184
|
hash = as_json
|
166
185
|
hash["meta"] = meta unless meta.empty?
|
@@ -180,6 +199,16 @@ class SystemDescription < Machinery::Object
|
|
180
199
|
File.chmod(0600, path) if created
|
181
200
|
end
|
182
201
|
|
202
|
+
def set_filter(command, filter)
|
203
|
+
if !["inspect"].include?(command)
|
204
|
+
raise Machinery::Errors::MachineryError.new(
|
205
|
+
"Storing the filter for command '#{command}' is not supported."
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
@filters[command] = filter
|
210
|
+
end
|
211
|
+
|
183
212
|
def scopes
|
184
213
|
attributes.keys.map(&:to_s).sort
|
185
214
|
end
|