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.
- checksums.yaml +4 -4
- data/NEWS +18 -0
- data/html/assets/machinery.css +20 -1
- data/html/assets/machinery.js +53 -26
- data/html/index.html.haml +69 -46
- data/lib/analyze_config_file_diffs_task.rb +1 -1
- data/lib/array.rb +36 -14
- data/lib/cli.rb +45 -50
- data/lib/compare_task.rb +1 -1
- data/lib/config.rb +8 -2
- data/lib/config_base.rb +14 -1
- data/lib/element_filter.rb +48 -11
- data/lib/exceptions.rb +5 -0
- data/lib/filter.rb +63 -14
- data/lib/filter_option_parser.rb +83 -0
- data/lib/generate_html_task.rb +3 -1
- data/lib/hint.rb +36 -18
- data/lib/html.rb +1 -0
- data/lib/inspect_task.rb +12 -21
- data/lib/inspector.rb +13 -6
- data/lib/kiwi_config.rb +17 -14
- data/lib/list_task.rb +5 -1
- data/lib/local_system.rb +3 -4
- data/lib/logged_cheetah.rb +3 -1
- data/lib/machinery.rb +1 -0
- data/lib/object.rb +24 -19
- data/lib/scope_file_store.rb +3 -1
- data/lib/show_task.rb +5 -7
- data/lib/system_description.rb +11 -12
- data/lib/system_description_store.rb +1 -1
- data/lib/ui.rb +44 -36
- data/lib/upgrade_format_task.rb +4 -1
- data/lib/version.rb +1 -1
- data/man/generated/machinery.1.gz +0 -0
- data/man/generated/machinery.1.html +7 -2
- data/plugins/inspect/changed_managed_files_inspector.rb +13 -6
- data/plugins/inspect/config_files_inspector.rb +27 -20
- data/plugins/inspect/groups_inspector.rb +12 -4
- data/plugins/inspect/os_inspector.rb +29 -22
- data/plugins/inspect/packages_inspector.rb +13 -5
- data/plugins/inspect/patterns_inspector.rb +24 -10
- data/plugins/inspect/repositories_inspector.rb +19 -15
- data/plugins/inspect/services_inspector.rb +28 -22
- data/plugins/inspect/unmanaged_files_inspector.rb +42 -33
- data/plugins/inspect/users_inspector.rb +13 -5
- data/plugins/model/os_model.rb +1 -1
- metadata +3 -2
data/lib/array.rb
CHANGED
@@ -22,30 +22,36 @@ module Machinery
|
|
22
22
|
@element_class = options[:class]
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
def convert_element(element)
|
26
|
+
if @element_class
|
27
|
+
element.is_a?(@element_class) ? element : @element_class.from_json(element)
|
28
|
+
else
|
29
|
+
case element
|
30
|
+
when ::Array
|
31
|
+
Machinery::Array.from_json(element)
|
32
|
+
when Hash
|
33
|
+
Machinery::Object.from_json(element)
|
29
34
|
else
|
30
|
-
|
31
|
-
when ::Array
|
32
|
-
Machinery::Array.from_json(element)
|
33
|
-
when Hash
|
34
|
-
Machinery::Object.from_json(element)
|
35
|
-
else
|
36
|
-
element
|
37
|
-
end
|
35
|
+
element
|
38
36
|
end
|
39
37
|
end
|
38
|
+
end
|
40
39
|
|
41
|
-
|
40
|
+
def convert_raw_array(array)
|
41
|
+
array.map do |element|
|
42
|
+
convert_element(element)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def from_json(json_object)
|
47
|
+
new(json_object)
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
45
51
|
attr_reader :elements
|
46
52
|
|
47
53
|
def initialize(elements = [])
|
48
|
-
@elements = elements
|
54
|
+
@elements = self.class.convert_raw_array(elements)
|
49
55
|
end
|
50
56
|
|
51
57
|
def ==(other)
|
@@ -69,6 +75,22 @@ module Machinery
|
|
69
75
|
self.class.new(@elements & other.elements)
|
70
76
|
end
|
71
77
|
|
78
|
+
def push(element)
|
79
|
+
@elements.push(self.class.convert_element(element))
|
80
|
+
end
|
81
|
+
|
82
|
+
def <<(element)
|
83
|
+
@elements << self.class.convert_element(element)
|
84
|
+
end
|
85
|
+
|
86
|
+
def +(array)
|
87
|
+
self.class.new(@elements + self.class.new(array).elements)
|
88
|
+
end
|
89
|
+
|
90
|
+
def insert(index, *elements)
|
91
|
+
@elements.insert(index, *self.class.new(elements).elements)
|
92
|
+
end
|
93
|
+
|
72
94
|
def as_json
|
73
95
|
@elements.map do |element|
|
74
96
|
if element.is_a?(Machinery::Array) || element.is_a?(Machinery::Object)
|
data/lib/cli.rb
CHANGED
@@ -22,9 +22,13 @@ class Cli
|
|
22
22
|
preserve_argv(true)
|
23
23
|
@version = Machinery::VERSION + " (system description format version " +
|
24
24
|
"#{SystemDescription::CURRENT_FORMAT_VERSION})"
|
25
|
+
@config = Machinery::Config.new
|
25
26
|
switch :version, negatable: false, desc: "Show version"
|
26
27
|
switch :debug, negatable: false, desc: "Enable debug mode"
|
27
28
|
switch [:help, :h], negatable: false, desc: "Show help"
|
29
|
+
if @config.experimental_features
|
30
|
+
flag :exclude, negatable: false, desc: "Exclude elements matching the filter criteria"
|
31
|
+
end
|
28
32
|
|
29
33
|
sort_help :manually
|
30
34
|
pre do |global_options,command,options,args|
|
@@ -39,14 +43,15 @@ class Cli
|
|
39
43
|
if command.is_a?(GLI::Commands::Help) && !global_options[:version]
|
40
44
|
|
41
45
|
Machinery::Ui.puts "\nMachinery can show hints which guide through a typical workflow."
|
42
|
-
if
|
46
|
+
if @config.hints
|
43
47
|
Machinery::Ui.puts "These hints can be switched off by '#{$0} config hints off'."
|
44
48
|
else
|
45
49
|
Machinery::Ui.puts "These hints can be switched on by '#{$0} config hints on'."
|
46
50
|
end
|
47
51
|
|
48
|
-
Hint.get_started
|
52
|
+
Hint.print(:get_started)
|
49
53
|
end
|
54
|
+
Machinery::Ui.close_pager
|
50
55
|
end
|
51
56
|
|
52
57
|
GLI::Commands::Help.skips_post = false
|
@@ -68,9 +73,12 @@ class Cli
|
|
68
73
|
when SignalException
|
69
74
|
Machinery.logger.info "Machinery was aborted with signal #{e.signo}."
|
70
75
|
exit 1
|
76
|
+
when Errno::ENOSPC
|
77
|
+
Machinery::Ui.error("Error: " + e.message)
|
78
|
+
exit 1
|
71
79
|
else
|
72
80
|
Machinery::Ui.error "Machinery experienced an unexpected error. Please file a " \
|
73
|
-
"bug report at https://github.com/SUSE/machinery/issues/new
|
81
|
+
"bug report at: https://github.com/SUSE/machinery/issues/new\n"
|
74
82
|
if e.is_a?(Cheetah::ExecutionFailed)
|
75
83
|
result = ""
|
76
84
|
result << "#{e.message}\n"
|
@@ -208,7 +216,7 @@ class Cli
|
|
208
216
|
when "config-file-diffs"
|
209
217
|
task = AnalyzeConfigFileDiffsTask.new
|
210
218
|
task.analyze(description)
|
211
|
-
Hint.show_analyze_data
|
219
|
+
Hint.print(:show_analyze_data, name: name)
|
212
220
|
else
|
213
221
|
raise Machinery::Errors::InvalidCommandLine.new(
|
214
222
|
"The operation '#{options[:operation]}' is not supported. " \
|
@@ -270,6 +278,8 @@ class Cli
|
|
270
278
|
desc: "Pipe output into a pager"
|
271
279
|
|
272
280
|
c.action do |global_options,options,args|
|
281
|
+
Machinery::Ui.use_pager = options[:pager]
|
282
|
+
|
273
283
|
name1 = shift_arg(args, "NAME1")
|
274
284
|
name2 = shift_arg(args, "NAME2")
|
275
285
|
store = system_description_store
|
@@ -279,8 +289,7 @@ class Cli
|
|
279
289
|
|
280
290
|
task = CompareTask.new
|
281
291
|
opts = {
|
282
|
-
|
283
|
-
no_pager: !options["pager"]
|
292
|
+
show_all: options["show-all"]
|
284
293
|
}
|
285
294
|
task.compare(description1, description2, scope_list, opts)
|
286
295
|
end
|
@@ -428,6 +437,8 @@ class Cli
|
|
428
437
|
desc: "Extract changed managed files from inspected system"
|
429
438
|
c.switch :show, required: false, negatable: false,
|
430
439
|
desc: "Print inspection result"
|
440
|
+
c.switch :verbose, required: false, negatable: false,
|
441
|
+
desc: "Display the filters which are used during inspection"
|
431
442
|
|
432
443
|
c.action do |global_options,options,args|
|
433
444
|
host = shift_arg(args, "HOSTNAME")
|
@@ -455,12 +466,12 @@ class Cli
|
|
455
466
|
inspect_options[:extract_unmanaged_files] = true
|
456
467
|
end
|
457
468
|
|
458
|
-
|
459
|
-
Machinery::Ui.warn("Warning: The --skip-files option is currently only supported for the " \
|
460
|
-
"\"unmanaged-files\" scope")
|
461
|
-
end
|
469
|
+
filter = FilterOptionParser.parse("inspect", options, global_options)
|
462
470
|
|
463
|
-
|
471
|
+
if options["verbose"] && !filter.empty?
|
472
|
+
Machinery::Ui.puts "\nThe following filters are applied during inspection:"
|
473
|
+
Machinery::Ui.puts filter.to_array.join("\n") + "\n\n"
|
474
|
+
end
|
464
475
|
|
465
476
|
inspector_task.inspect_system(
|
466
477
|
system_description_store,
|
@@ -472,10 +483,10 @@ class Cli
|
|
472
483
|
inspect_options
|
473
484
|
)
|
474
485
|
|
475
|
-
Hint.show_data
|
486
|
+
Hint.print(:show_data, name: name)
|
476
487
|
|
477
488
|
if !options["extract-files"] || Inspector.all_scopes.count != scope_list.count
|
478
|
-
Hint.do_complete_inspection
|
489
|
+
Hint.print(:do_complete_inspection, name: name, host: host)
|
479
490
|
end
|
480
491
|
end
|
481
492
|
end
|
@@ -545,8 +556,12 @@ class Cli
|
|
545
556
|
desc: "Show diffs of configuration files changes."
|
546
557
|
c.switch "html", required: false, negatable: false,
|
547
558
|
desc: "Open system description in HTML format in your web browser."
|
559
|
+
c.switch "verbose", required: false, negatable: false,
|
560
|
+
desc: "Show the filters that were applied before showing the description."
|
548
561
|
|
549
562
|
c.action do |global_options,options,args|
|
563
|
+
Machinery::Ui.use_pager = options["pager"]
|
564
|
+
|
550
565
|
name = shift_arg(args, "NAME")
|
551
566
|
if name == "localhost" && !CurrentUser.new.is_root?
|
552
567
|
Machinery::Ui.puts "You need root rights to access the system description of your locally inspected system."
|
@@ -554,14 +569,28 @@ class Cli
|
|
554
569
|
description = SystemDescription.load(name, system_description_store)
|
555
570
|
scope_list = process_scope_option(options[:scope], options["exclude-scope"])
|
556
571
|
|
572
|
+
filter = FilterOptionParser.parse("show", options, global_options)
|
573
|
+
|
574
|
+
inspected_filters = description.filter_definitions("inspect")
|
575
|
+
|
576
|
+
if options["verbose"]
|
577
|
+
if !inspected_filters.empty?
|
578
|
+
Machinery::Ui.puts "\nThe following filters were applied during inspection:"
|
579
|
+
Machinery::Ui.puts inspected_filters.join("\n") + "\n\n"
|
580
|
+
end
|
581
|
+
|
582
|
+
if !filter.empty?
|
583
|
+
Machinery::Ui.puts "\nThe following filters were applied before showing the description:"
|
584
|
+
Machinery::Ui.puts filter.to_array.join("\n") + "\n\n"
|
585
|
+
end
|
586
|
+
end
|
557
587
|
|
558
588
|
task = ShowTask.new
|
559
589
|
opts = {
|
560
|
-
no_pager: !options["pager"],
|
561
590
|
show_diffs: options["show-diffs"],
|
562
591
|
show_html: options["html"]
|
563
592
|
}
|
564
|
-
task.show(description, scope_list, opts)
|
593
|
+
task.show(description, scope_list, filter, opts)
|
565
594
|
end
|
566
595
|
end
|
567
596
|
|
@@ -639,7 +668,7 @@ class Cli
|
|
639
668
|
task = ConfigTask.new
|
640
669
|
task.config(key, value)
|
641
670
|
|
642
|
-
if key == "hints" &&
|
671
|
+
if key == "hints" && !@config.hints
|
643
672
|
Machinery::Ui.puts "Hints can be switched on again by '#{$0} config hints on'."
|
644
673
|
end
|
645
674
|
end
|
@@ -652,38 +681,4 @@ class Cli
|
|
652
681
|
SystemDescriptionStore.new
|
653
682
|
end
|
654
683
|
end
|
655
|
-
|
656
|
-
|
657
|
-
def self.prepare_filter(command, options)
|
658
|
-
filter = Filter.from_default_definition(command)
|
659
|
-
|
660
|
-
skip_files = options.delete("skip-files")
|
661
|
-
if skip_files
|
662
|
-
files = skip_files.split(/(?<!\\),/) # Do not split on escaped commas
|
663
|
-
files = files.flat_map do |file|
|
664
|
-
if file.start_with?("@")
|
665
|
-
filename = File.expand_path(file[1..-1])
|
666
|
-
|
667
|
-
if !File.exists?(filename)
|
668
|
-
raise Machinery::Errors::MachineryError.new(
|
669
|
-
"The filter file '#{filename}' does not exist."
|
670
|
-
)
|
671
|
-
end
|
672
|
-
File.read(filename).lines.map(&:strip)
|
673
|
-
else
|
674
|
-
file
|
675
|
-
end
|
676
|
-
end
|
677
|
-
|
678
|
-
files.reject!(&:empty?) # Ignore empty filters
|
679
|
-
files.map! { |file| file.gsub("\\@", "@") } # Unescape escaped @s
|
680
|
-
files.map! { |file| file.chomp("/") } # List directories without the trailing /, in order to
|
681
|
-
# not confuse the unmanaged files inspector
|
682
|
-
files.each do |file|
|
683
|
-
filter.add_element_filter_from_definition("/unmanaged_files/files/name=#{file}")
|
684
|
-
end
|
685
|
-
end
|
686
|
-
|
687
|
-
filter
|
688
|
-
end
|
689
684
|
end
|
data/lib/compare_task.rb
CHANGED
@@ -19,7 +19,7 @@ class CompareTask
|
|
19
19
|
def compare(description1, description2, scopes, options = {})
|
20
20
|
output = render_comparison(description1, description2, scopes, options)
|
21
21
|
|
22
|
-
Machinery::Ui.
|
22
|
+
Machinery::Ui.puts output
|
23
23
|
end
|
24
24
|
|
25
25
|
def render_comparison(description1, description2, scopes, options = {})
|
data/lib/config.rb
CHANGED
@@ -25,8 +25,14 @@ module Machinery
|
|
25
25
|
default_config_file(Machinery::DEFAULT_CONFIG_FILE)
|
26
26
|
|
27
27
|
entry("hints",
|
28
|
-
default:
|
29
|
-
description: "Show hints about usage of Machinery in the context of the commands ran by
|
28
|
+
default: true,
|
29
|
+
description: "Show hints about usage of Machinery in the context of the commands ran by" \
|
30
|
+
" the user"
|
31
|
+
)
|
32
|
+
entry("experimental-features",
|
33
|
+
default: false,
|
34
|
+
description: "Enable experimental features. See " \
|
35
|
+
"https://github.com/SUSE/machinery/wiki/Experimental-Features for more details."
|
30
36
|
)
|
31
37
|
end
|
32
38
|
end
|
data/lib/config_base.rb
CHANGED
@@ -32,6 +32,8 @@ class ConfigBase
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def entry(key, parameters = {})
|
35
|
+
key = normalize_key(key)
|
36
|
+
|
35
37
|
@entries[key] = { value: parameters[:default], description: parameters[:description] }
|
36
38
|
create_method(key.to_sym) { get(key) }
|
37
39
|
create_method("#{key}=".to_sym) { |value| set(key, value) }
|
@@ -42,15 +44,18 @@ class ConfigBase
|
|
42
44
|
end
|
43
45
|
|
44
46
|
def each(&block)
|
45
|
-
@entries.each(&block)
|
47
|
+
@entries.map { |key, value| [unnormalize_key(key), value] }.each(&block)
|
46
48
|
end
|
47
49
|
|
48
50
|
def get(key)
|
51
|
+
key = normalize_key(key)
|
52
|
+
|
49
53
|
ensure_config_exists(key)
|
50
54
|
@entries[key][:value]
|
51
55
|
end
|
52
56
|
|
53
57
|
def set(key, value, options = {auto_save: true} )
|
58
|
+
key = normalize_key(key)
|
54
59
|
ensure_config_exists(key)
|
55
60
|
|
56
61
|
# Check if data type is correct. true and false are not of the same type which makes the check complex
|
@@ -114,4 +119,12 @@ class ConfigBase
|
|
114
119
|
def create_method(name, &block)
|
115
120
|
self.class.send(:define_method, name, &block)
|
116
121
|
end
|
122
|
+
|
123
|
+
def normalize_key(key)
|
124
|
+
key.gsub("-", "_")
|
125
|
+
end
|
126
|
+
|
127
|
+
def unnormalize_key(key)
|
128
|
+
key.gsub("_", "-")
|
129
|
+
end
|
117
130
|
end
|
data/lib/element_filter.rb
CHANGED
@@ -18,28 +18,65 @@
|
|
18
18
|
class ElementFilter
|
19
19
|
attr_accessor :path, :matchers
|
20
20
|
|
21
|
-
def initialize(path, matchers = nil)
|
21
|
+
def initialize(path, operator = nil, matchers = nil)
|
22
22
|
@path = path
|
23
|
-
@matchers =
|
23
|
+
@matchers = {}
|
24
24
|
|
25
|
-
|
25
|
+
if ![NilClass, String, Array].include?(matchers.class)
|
26
|
+
raise Machinery::Errors::InvalidFilter.new("Wrong filter type")
|
27
|
+
end
|
26
28
|
|
27
|
-
add_matchers(matchers) if matchers
|
29
|
+
add_matchers(operator, matchers) if operator && matchers
|
28
30
|
end
|
29
31
|
|
30
|
-
def add_matchers(matchers)
|
31
|
-
|
32
|
+
def add_matchers(operator, matchers)
|
33
|
+
if ![Filter::OPERATOR_EQUALS, Filter::OPERATOR_EQUALS_NOT].include?(operator)
|
34
|
+
raise Machinery::Errors::InvalidFilter.new("Wrong filter operator '#{operator}'")
|
35
|
+
end
|
36
|
+
|
37
|
+
@matchers[operator] ||= []
|
38
|
+
@matchers[operator] += Array(matchers)
|
32
39
|
end
|
33
40
|
|
34
41
|
def matches?(value)
|
35
|
-
@matchers.each do |
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
42
|
+
@matchers.each do |operator, matchers|
|
43
|
+
matchers.each do |matcher|
|
44
|
+
values_equal = case value
|
45
|
+
when Machinery::Array
|
46
|
+
value_array = value.elements
|
47
|
+
|
48
|
+
(value_array - Array(matcher)).empty? && (Array(matcher) - value_array).empty?
|
49
|
+
when String
|
50
|
+
if matcher.is_a?(Array)
|
51
|
+
exception = Machinery::Errors::ElementFilterTypeMismatch.new
|
52
|
+
exception.failed_matcher =
|
53
|
+
"#{path}#{operator}#{matcher.join(",")}"
|
54
|
+
raise exception
|
55
|
+
end
|
56
|
+
|
57
|
+
if matcher.end_with?("*")
|
58
|
+
value.start_with?(matcher[0..-2])
|
59
|
+
else
|
60
|
+
value == matcher
|
61
|
+
end
|
62
|
+
end
|
63
|
+
if operator == Filter::OPERATOR_EQUALS
|
64
|
+
return true if values_equal
|
65
|
+
elsif operator == Filter::OPERATOR_EQUALS_NOT
|
66
|
+
return true if !values_equal
|
67
|
+
end
|
40
68
|
end
|
41
69
|
end
|
42
70
|
|
43
71
|
false
|
44
72
|
end
|
73
|
+
|
74
|
+
def filters_scope?(scope)
|
75
|
+
(path =~ /\/#{scope}(\/|$)/) ? true : false
|
76
|
+
end
|
77
|
+
|
78
|
+
def ==(other)
|
79
|
+
path == other.path &&
|
80
|
+
matchers == other.matchers
|
81
|
+
end
|
45
82
|
end
|
data/lib/exceptions.rb
CHANGED
@@ -101,6 +101,11 @@ module Machinery
|
|
101
101
|
|
102
102
|
class MigrationError < MachineryError; end
|
103
103
|
|
104
|
+
class InvalidFilter < MachineryError; end
|
105
|
+
class ElementFilterTypeMismatch < MachineryError
|
106
|
+
attr_accessor :failed_matcher
|
107
|
+
end
|
108
|
+
|
104
109
|
class BuildFailed < MachineryError; end
|
105
110
|
class DeployFailed < MachineryError; end
|
106
111
|
class InspectionFailed < MachineryError; end
|
data/lib/filter.rb
CHANGED
@@ -46,19 +46,22 @@
|
|
46
46
|
class Filter
|
47
47
|
attr_accessor :element_filters
|
48
48
|
|
49
|
+
OPERATOR_EQUALS = "="
|
50
|
+
OPERATOR_EQUALS_NOT = "!="
|
51
|
+
|
49
52
|
def self.parse_filter_definitions(filter_definitions)
|
50
53
|
element_filters = {}
|
51
54
|
Array(filter_definitions).each do |definition|
|
52
|
-
path, matcher_definition = definition.
|
55
|
+
path, operator, matcher_definition = definition.scan(/([a-zA-Z_\/]+)(.*=)(.*)/)[0]
|
53
56
|
|
54
57
|
element_filters[path] ||= ElementFilter.new(path)
|
55
58
|
if matcher_definition.index(",")
|
56
59
|
matchers = matcher_definition.split(/(?<!\\),/)
|
57
60
|
matchers.map! { |matcher| matcher.gsub("\\,", ",") } # Unescape escaped commas
|
58
61
|
|
59
|
-
element_filters[path].add_matchers([matchers])
|
62
|
+
element_filters[path].add_matchers(operator, [matchers])
|
60
63
|
else
|
61
|
-
element_filters[path].add_matchers(matcher_definition)
|
64
|
+
element_filters[path].add_matchers(operator, matcher_definition)
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
@@ -86,24 +89,44 @@ class Filter
|
|
86
89
|
end
|
87
90
|
|
88
91
|
def add_element_filter_from_definition(filter_definition)
|
89
|
-
|
92
|
+
add_element_filters(Filter.parse_filter_definitions(filter_definition).values)
|
93
|
+
end
|
90
94
|
|
91
|
-
|
95
|
+
def add_element_filters(element_filters)
|
96
|
+
Array(element_filters).each do |element_filter|
|
97
|
+
path = element_filter.path
|
92
98
|
@element_filters[path] ||= ElementFilter.new(path)
|
93
|
-
|
99
|
+
|
100
|
+
element_filter.matchers.each do |operator, matchers|
|
101
|
+
@element_filters[path].add_matchers(operator, matchers)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def element_filter_for(path)
|
107
|
+
element_filters[path]
|
108
|
+
end
|
109
|
+
|
110
|
+
def element_filters_for_scope(scope)
|
111
|
+
@element_filters.values.select do |element_filter|
|
112
|
+
element_filter.filters_scope?(scope)
|
94
113
|
end
|
95
114
|
end
|
96
115
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
|
116
|
+
def set_element_filters_for_scope(scope, element_filters)
|
117
|
+
@element_filters.reject! do |_path, element_filter|
|
118
|
+
element_filter.filters_scope?(scope)
|
119
|
+
end
|
120
|
+
|
121
|
+
add_element_filters(element_filters)
|
101
122
|
end
|
102
123
|
|
103
124
|
def to_array
|
104
125
|
@element_filters.flat_map do |path, element_filter|
|
105
|
-
element_filter.matchers.
|
106
|
-
|
126
|
+
element_filter.matchers.flat_map do |operator, matchers|
|
127
|
+
matchers.map do |matcher|
|
128
|
+
"#{path}#{operator}#{Array(matcher).join(",")}"
|
129
|
+
end
|
107
130
|
end
|
108
131
|
end
|
109
132
|
end
|
@@ -115,7 +138,33 @@ class Filter
|
|
115
138
|
filter.matches?(value)
|
116
139
|
end
|
117
140
|
|
118
|
-
def
|
119
|
-
element_filters
|
141
|
+
def apply!(system_description)
|
142
|
+
element_filters.each do |path, element_filter|
|
143
|
+
steps = path.split("/").reject(&:empty?)
|
144
|
+
target = steps.pop
|
145
|
+
|
146
|
+
pointer = system_description
|
147
|
+
container = nil
|
148
|
+
steps.each do |step|
|
149
|
+
break if !pointer
|
150
|
+
pointer = pointer[step]
|
151
|
+
container ||= pointer if pointer.is_a?(Machinery::Array)
|
152
|
+
end
|
153
|
+
|
154
|
+
next if !pointer
|
155
|
+
|
156
|
+
begin
|
157
|
+
pointer.delete_if do |element|
|
158
|
+
element_filter.matches?(element[target])
|
159
|
+
end
|
160
|
+
rescue Machinery::Errors::ElementFilterTypeMismatch => e
|
161
|
+
Machinery::Ui.warn("Warning: Filter '#{e.failed_matcher}' tries to match an array, " \
|
162
|
+
"but the according element is not an array.")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def empty?
|
168
|
+
element_filters.empty?
|
120
169
|
end
|
121
170
|
end
|