masamune 0.11.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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +54 -0
- data/Rakefile +15 -0
- data/bin/masamune-elastic-mapreduce +4 -0
- data/bin/masamune-hive +4 -0
- data/bin/masamune-psql +4 -0
- data/bin/masamune-shell +4 -0
- data/lib/masamune.rb +56 -0
- data/lib/masamune/accumulate.rb +60 -0
- data/lib/masamune/actions.rb +38 -0
- data/lib/masamune/actions/data_flow.rb +131 -0
- data/lib/masamune/actions/date_parse.rb +75 -0
- data/lib/masamune/actions/elastic_mapreduce.rb +68 -0
- data/lib/masamune/actions/execute.rb +52 -0
- data/lib/masamune/actions/filesystem.rb +37 -0
- data/lib/masamune/actions/hadoop_filesystem.rb +40 -0
- data/lib/masamune/actions/hadoop_streaming.rb +41 -0
- data/lib/masamune/actions/hive.rb +74 -0
- data/lib/masamune/actions/postgres.rb +76 -0
- data/lib/masamune/actions/postgres_admin.rb +34 -0
- data/lib/masamune/actions/s3cmd.rb +44 -0
- data/lib/masamune/actions/transform.rb +89 -0
- data/lib/masamune/after_initialize_callbacks.rb +55 -0
- data/lib/masamune/cached_filesystem.rb +110 -0
- data/lib/masamune/commands.rb +37 -0
- data/lib/masamune/commands/elastic_mapreduce.rb +119 -0
- data/lib/masamune/commands/hadoop_filesystem.rb +57 -0
- data/lib/masamune/commands/hadoop_streaming.rb +116 -0
- data/lib/masamune/commands/hive.rb +178 -0
- data/lib/masamune/commands/interactive.rb +37 -0
- data/lib/masamune/commands/postgres.rb +128 -0
- data/lib/masamune/commands/postgres_admin.rb +72 -0
- data/lib/masamune/commands/postgres_common.rb +33 -0
- data/lib/masamune/commands/retry_with_backoff.rb +60 -0
- data/lib/masamune/commands/s3cmd.rb +70 -0
- data/lib/masamune/commands/shell.rb +202 -0
- data/lib/masamune/configuration.rb +195 -0
- data/lib/masamune/data_plan.rb +31 -0
- data/lib/masamune/data_plan/builder.rb +66 -0
- data/lib/masamune/data_plan/elem.rb +190 -0
- data/lib/masamune/data_plan/engine.rb +162 -0
- data/lib/masamune/data_plan/rule.rb +292 -0
- data/lib/masamune/data_plan/set.rb +176 -0
- data/lib/masamune/environment.rb +164 -0
- data/lib/masamune/filesystem.rb +567 -0
- data/lib/masamune/has_environment.rb +40 -0
- data/lib/masamune/helpers.rb +27 -0
- data/lib/masamune/helpers/postgres.rb +84 -0
- data/lib/masamune/io.rb +33 -0
- data/lib/masamune/last_element.rb +53 -0
- data/lib/masamune/method_logger.rb +41 -0
- data/lib/masamune/multi_io.rb +39 -0
- data/lib/masamune/schema.rb +36 -0
- data/lib/masamune/schema/catalog.rb +233 -0
- data/lib/masamune/schema/column.rb +527 -0
- data/lib/masamune/schema/dimension.rb +133 -0
- data/lib/masamune/schema/event.rb +121 -0
- data/lib/masamune/schema/fact.rb +133 -0
- data/lib/masamune/schema/map.rb +265 -0
- data/lib/masamune/schema/row.rb +133 -0
- data/lib/masamune/schema/store.rb +115 -0
- data/lib/masamune/schema/table.rb +308 -0
- data/lib/masamune/schema/table_reference.rb +76 -0
- data/lib/masamune/spec_helper.rb +23 -0
- data/lib/masamune/string_format.rb +34 -0
- data/lib/masamune/tasks/elastic_mapreduce_thor.rb +60 -0
- data/lib/masamune/tasks/hive_thor.rb +55 -0
- data/lib/masamune/tasks/postgres_thor.rb +47 -0
- data/lib/masamune/tasks/shell_thor.rb +63 -0
- data/lib/masamune/template.rb +77 -0
- data/lib/masamune/thor.rb +186 -0
- data/lib/masamune/thor_loader.rb +38 -0
- data/lib/masamune/topological_hash.rb +34 -0
- data/lib/masamune/transform.rb +47 -0
- data/lib/masamune/transform/bulk_upsert.psql.erb +64 -0
- data/lib/masamune/transform/bulk_upsert.rb +52 -0
- data/lib/masamune/transform/consolidate_dimension.rb +54 -0
- data/lib/masamune/transform/deduplicate_dimension.psql.erb +52 -0
- data/lib/masamune/transform/deduplicate_dimension.rb +53 -0
- data/lib/masamune/transform/define_event_view.hql.erb +51 -0
- data/lib/masamune/transform/define_event_view.rb +60 -0
- data/lib/masamune/transform/define_index.psql.erb +34 -0
- data/lib/masamune/transform/define_schema.hql.erb +23 -0
- data/lib/masamune/transform/define_schema.psql.erb +79 -0
- data/lib/masamune/transform/define_schema.rb +56 -0
- data/lib/masamune/transform/define_table.hql.erb +34 -0
- data/lib/masamune/transform/define_table.psql.erb +95 -0
- data/lib/masamune/transform/define_table.rb +40 -0
- data/lib/masamune/transform/define_unique.psql.erb +30 -0
- data/lib/masamune/transform/insert_reference_values.psql.erb +43 -0
- data/lib/masamune/transform/insert_reference_values.rb +64 -0
- data/lib/masamune/transform/load_dimension.rb +47 -0
- data/lib/masamune/transform/load_fact.rb +45 -0
- data/lib/masamune/transform/operator.rb +96 -0
- data/lib/masamune/transform/relabel_dimension.psql.erb +76 -0
- data/lib/masamune/transform/relabel_dimension.rb +39 -0
- data/lib/masamune/transform/rollup_fact.psql.erb +79 -0
- data/lib/masamune/transform/rollup_fact.rb +149 -0
- data/lib/masamune/transform/snapshot_dimension.psql.erb +75 -0
- data/lib/masamune/transform/snapshot_dimension.rb +74 -0
- data/lib/masamune/transform/stage_dimension.psql.erb +39 -0
- data/lib/masamune/transform/stage_dimension.rb +83 -0
- data/lib/masamune/transform/stage_fact.psql.erb +80 -0
- data/lib/masamune/transform/stage_fact.rb +111 -0
- data/lib/masamune/version.rb +25 -0
- data/spec/fixtures/aggregate.sql.erb +25 -0
- data/spec/fixtures/comment.sql.erb +27 -0
- data/spec/fixtures/invalid.sql.erb +23 -0
- data/spec/fixtures/relative.sql.erb +23 -0
- data/spec/fixtures/simple.sql.erb +28 -0
- data/spec/fixtures/whitespace.sql.erb +30 -0
- data/spec/masamune/actions/elastic_mapreduce_spec.rb +108 -0
- data/spec/masamune/actions/execute_spec.rb +50 -0
- data/spec/masamune/actions/hadoop_filesystem_spec.rb +44 -0
- data/spec/masamune/actions/hadoop_streaming_spec.rb +74 -0
- data/spec/masamune/actions/hive_spec.rb +117 -0
- data/spec/masamune/actions/postgres_admin_spec.rb +58 -0
- data/spec/masamune/actions/postgres_spec.rb +134 -0
- data/spec/masamune/actions/s3cmd_spec.rb +44 -0
- data/spec/masamune/actions/transform_spec.rb +144 -0
- data/spec/masamune/after_initialization_callbacks_spec.rb +61 -0
- data/spec/masamune/cached_filesystem_spec.rb +167 -0
- data/spec/masamune/commands/hadoop_filesystem_spec.rb +50 -0
- data/spec/masamune/commands/hadoop_streaming_spec.rb +106 -0
- data/spec/masamune/commands/hive_spec.rb +117 -0
- data/spec/masamune/commands/postgres_admin_spec.rb +69 -0
- data/spec/masamune/commands/postgres_spec.rb +100 -0
- data/spec/masamune/commands/retry_with_backoff_spec.rb +116 -0
- data/spec/masamune/commands/s3cmd_spec.rb +50 -0
- data/spec/masamune/commands/shell_spec.rb +101 -0
- data/spec/masamune/configuration_spec.rb +102 -0
- data/spec/masamune/data_plan/builder_spec.rb +91 -0
- data/spec/masamune/data_plan/elem_spec.rb +102 -0
- data/spec/masamune/data_plan/engine_spec.rb +356 -0
- data/spec/masamune/data_plan/rule_spec.rb +407 -0
- data/spec/masamune/data_plan/set_spec.rb +517 -0
- data/spec/masamune/environment_spec.rb +65 -0
- data/spec/masamune/filesystem_spec.rb +1421 -0
- data/spec/masamune/helpers/postgres_spec.rb +95 -0
- data/spec/masamune/schema/catalog_spec.rb +613 -0
- data/spec/masamune/schema/column_spec.rb +696 -0
- data/spec/masamune/schema/dimension_spec.rb +137 -0
- data/spec/masamune/schema/event_spec.rb +75 -0
- data/spec/masamune/schema/fact_spec.rb +117 -0
- data/spec/masamune/schema/map_spec.rb +593 -0
- data/spec/masamune/schema/row_spec.rb +28 -0
- data/spec/masamune/schema/store_spec.rb +49 -0
- data/spec/masamune/schema/table_spec.rb +395 -0
- data/spec/masamune/string_format_spec.rb +60 -0
- data/spec/masamune/tasks/elastic_mapreduce_thor_spec.rb +57 -0
- data/spec/masamune/tasks/hive_thor_spec.rb +75 -0
- data/spec/masamune/tasks/postgres_thor_spec.rb +42 -0
- data/spec/masamune/tasks/shell_thor_spec.rb +51 -0
- data/spec/masamune/template_spec.rb +77 -0
- data/spec/masamune/thor_spec.rb +238 -0
- data/spec/masamune/transform/bulk_upsert.dimension_spec.rb +200 -0
- data/spec/masamune/transform/consolidate_dimension_spec.rb +62 -0
- data/spec/masamune/transform/deduplicate_dimension_spec.rb +84 -0
- data/spec/masamune/transform/define_event_view_spec.rb +84 -0
- data/spec/masamune/transform/define_schema_spec.rb +83 -0
- data/spec/masamune/transform/define_table.dimension_spec.rb +306 -0
- data/spec/masamune/transform/define_table.fact_spec.rb +291 -0
- data/spec/masamune/transform/define_table.table_spec.rb +525 -0
- data/spec/masamune/transform/insert_reference_values.dimension_spec.rb +111 -0
- data/spec/masamune/transform/insert_reference_values.fact_spec.rb +149 -0
- data/spec/masamune/transform/load_dimension_spec.rb +76 -0
- data/spec/masamune/transform/load_fact_spec.rb +89 -0
- data/spec/masamune/transform/relabel_dimension_spec.rb +102 -0
- data/spec/masamune/transform/rollup_fact_spec.rb +333 -0
- data/spec/masamune/transform/snapshot_dimension_spec.rb +103 -0
- data/spec/masamune/transform/stage_dimension_spec.rb +115 -0
- data/spec/masamune/transform/stage_fact_spec.rb +204 -0
- data/spec/masamune_spec.rb +32 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/masamune/example_group.rb +36 -0
- data/spec/support/masamune/mock_command.rb +99 -0
- data/spec/support/masamune/mock_delegate.rb +51 -0
- data/spec/support/masamune/mock_filesystem.rb +96 -0
- data/spec/support/masamune/thor_mute.rb +35 -0
- data/spec/support/rspec/example/action_example_group.rb +34 -0
- data/spec/support/rspec/example/task_example_group.rb +80 -0
- data/spec/support/rspec/example/transform_example_group.rb +36 -0
- data/spec/support/shared_examples/postgres_common_examples.rb +53 -0
- metadata +462 -0
@@ -0,0 +1,292 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
#
|
3
|
+
# Copyright (c) 2014-2015, VMware, Inc. All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'active_support'
|
24
|
+
require 'active_support/duration'
|
25
|
+
require 'active_support/values/time_zone'
|
26
|
+
require 'active_support/core_ext/time/calculations'
|
27
|
+
require 'active_support/core_ext/date/calculations'
|
28
|
+
require 'active_support/core_ext/date_time/calculations'
|
29
|
+
require 'date'
|
30
|
+
|
31
|
+
class Masamune::DataPlan::Rule
|
32
|
+
TERMINAL = nil
|
33
|
+
|
34
|
+
include Masamune::Accumulate
|
35
|
+
|
36
|
+
attr_reader :engine, :name, :type, :options
|
37
|
+
|
38
|
+
def initialize(engine, name, type, options = {})
|
39
|
+
@engine = engine
|
40
|
+
@name = name
|
41
|
+
@type = type
|
42
|
+
@options = options
|
43
|
+
end
|
44
|
+
|
45
|
+
def for_targets?
|
46
|
+
@type == :target
|
47
|
+
end
|
48
|
+
|
49
|
+
def for_sources?
|
50
|
+
@type == :source
|
51
|
+
end
|
52
|
+
|
53
|
+
def for_path?
|
54
|
+
@options.key?(:path)
|
55
|
+
end
|
56
|
+
|
57
|
+
def for_table?
|
58
|
+
@options.key?(:table)
|
59
|
+
end
|
60
|
+
|
61
|
+
def for_table_with_partition?
|
62
|
+
@options.key?(:table) && @options.key?(:partition)
|
63
|
+
end
|
64
|
+
|
65
|
+
def path
|
66
|
+
@options[:path]
|
67
|
+
end
|
68
|
+
|
69
|
+
def table
|
70
|
+
@options[:table]
|
71
|
+
end
|
72
|
+
|
73
|
+
def partition
|
74
|
+
@options[:partition]
|
75
|
+
end
|
76
|
+
|
77
|
+
def ==(other)
|
78
|
+
engine == other.engine &&
|
79
|
+
name == other.name &&
|
80
|
+
type == other.type &&
|
81
|
+
pattern == other.pattern &&
|
82
|
+
options == other.options
|
83
|
+
end
|
84
|
+
|
85
|
+
def eql?(other)
|
86
|
+
self == other
|
87
|
+
end
|
88
|
+
|
89
|
+
def hash
|
90
|
+
[engine, name, type, pattern, options].hash
|
91
|
+
end
|
92
|
+
|
93
|
+
def pattern
|
94
|
+
@pattern ||= begin
|
95
|
+
if for_path?
|
96
|
+
path.respond_to?(:call) ? path.call(engine.filesystem) : path
|
97
|
+
elsif for_table_with_partition?
|
98
|
+
[table , partition].join('_')
|
99
|
+
elsif for_table?
|
100
|
+
table
|
101
|
+
end.to_s
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def primary?
|
106
|
+
@options.fetch(:primary, true)
|
107
|
+
end
|
108
|
+
|
109
|
+
def matches?(input)
|
110
|
+
matched_pattern = match_data_hash(matcher.match(input))
|
111
|
+
matched_pattern.present? && matched_pattern[:rest].blank?
|
112
|
+
end
|
113
|
+
|
114
|
+
def bind_date(input_date)
|
115
|
+
output_date = tz.utc_to_local(input_date)
|
116
|
+
Masamune::DataPlan::Elem.new(self, output_date, options_for_elem)
|
117
|
+
end
|
118
|
+
|
119
|
+
def bind_input(input)
|
120
|
+
return input if input.is_a?(Masamune::DataPlan::Elem)
|
121
|
+
matched_pattern = match_data_hash(matcher.match(input))
|
122
|
+
raise "Cannot bind_input #{input} to #{pattern}" unless matched_pattern
|
123
|
+
output_date = matched_date(matched_pattern)
|
124
|
+
Masamune::DataPlan::Elem.new(self, output_date, options_for_elem.merge(matched_extra(matched_pattern)))
|
125
|
+
end
|
126
|
+
|
127
|
+
def unify(elem, rule)
|
128
|
+
rule.bind_date(elem.start_time)
|
129
|
+
end
|
130
|
+
|
131
|
+
def generate(start_time, stop_time, &block)
|
132
|
+
instance = bind_date(start_time)
|
133
|
+
|
134
|
+
begin
|
135
|
+
yield instance
|
136
|
+
instance = instance.next
|
137
|
+
end while instance.start_time <= stop_time
|
138
|
+
end
|
139
|
+
method_accumulate :generate
|
140
|
+
|
141
|
+
def generate_via_unify(elem, rule, &block)
|
142
|
+
instance = unify(elem, rule)
|
143
|
+
|
144
|
+
stop_time = instance.start_time.advance(time_step => 1)
|
145
|
+
begin
|
146
|
+
yield instance
|
147
|
+
instance = instance.next
|
148
|
+
end while instance.start_time < stop_time
|
149
|
+
end
|
150
|
+
method_accumulate :generate_via_unify
|
151
|
+
|
152
|
+
def tz
|
153
|
+
ActiveSupport::TimeZone[@options.fetch(:tz, 'UTC')]
|
154
|
+
end
|
155
|
+
|
156
|
+
def time_step
|
157
|
+
@time_step ||=
|
158
|
+
case pattern
|
159
|
+
when /%s/
|
160
|
+
:hours
|
161
|
+
when /%H-s/
|
162
|
+
:hours
|
163
|
+
when /%d-s/
|
164
|
+
:days
|
165
|
+
when /%m-s/
|
166
|
+
:months
|
167
|
+
when /%Y-s/
|
168
|
+
:years
|
169
|
+
when /%-?k/, /%-?H/
|
170
|
+
:hours
|
171
|
+
when /%-?d/
|
172
|
+
:days
|
173
|
+
when /%-?m/
|
174
|
+
:months
|
175
|
+
when /%-?Y/
|
176
|
+
:years
|
177
|
+
else
|
178
|
+
:hours
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def time_round(time)
|
183
|
+
case time_step
|
184
|
+
when :hours
|
185
|
+
DateTime.civil(time.year, time.month, time.day, time.hour)
|
186
|
+
when :days
|
187
|
+
DateTime.civil(time.year, time.month, time.day)
|
188
|
+
when :months
|
189
|
+
DateTime.civil(time.year, time.month)
|
190
|
+
when :years
|
191
|
+
DateTime.civil(time.year)
|
192
|
+
else
|
193
|
+
time
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def window
|
198
|
+
@options[:window] || 0
|
199
|
+
end
|
200
|
+
|
201
|
+
def adjacent_matches(instance)
|
202
|
+
(-window .. -1).each do |i|
|
203
|
+
yield instance.prev(i.abs)
|
204
|
+
end
|
205
|
+
yield instance
|
206
|
+
(1 .. window).each do |i|
|
207
|
+
yield instance.next(i)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
method_accumulate :adjacent_matches
|
211
|
+
|
212
|
+
def inspect
|
213
|
+
{type: type, pattern: pattern, options: options}.to_s
|
214
|
+
end
|
215
|
+
|
216
|
+
def strftime_format
|
217
|
+
@strftime_format ||=
|
218
|
+
pattern.dup.tap do |format|
|
219
|
+
format.gsub!('%H-s', '%s')
|
220
|
+
format.gsub!('%d-s', '%s')
|
221
|
+
format.gsub!('%m-s', '%s')
|
222
|
+
format.gsub!('%Y-s', '%s')
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def round(grain)
|
227
|
+
pattern_parts = pattern.split('/')
|
228
|
+
part_index = pattern_parts.find_index { |part| part =~ time_step_to_format(grain) }
|
229
|
+
raise "cannot round to :#{grain} for #{pattern}" unless part_index
|
230
|
+
new_pattern = pattern_parts[0..part_index].join('/')
|
231
|
+
self.class.new(engine, name, type, options.merge(path: new_pattern))
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def time_step_to_format(step)
|
237
|
+
case step
|
238
|
+
when :hour, :hours
|
239
|
+
/%-?[H|k]/
|
240
|
+
when :day, :days
|
241
|
+
/%-?d/
|
242
|
+
when :month, :months
|
243
|
+
/%-?m/
|
244
|
+
when :year, :years
|
245
|
+
/%Y/
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def matcher
|
250
|
+
@matcher ||= begin
|
251
|
+
regexp = pattern.dup
|
252
|
+
regexp.gsub!(/%([YmdH]-)?s/, '(?<timestamp>\d{10})')
|
253
|
+
regexp.gsub!('%Y', '(?<year>\d{4})')
|
254
|
+
regexp.gsub!('%m', '(?<month>\d{2})')
|
255
|
+
regexp.gsub!('%-m', '(?<month>\d{1,2})')
|
256
|
+
regexp.gsub!('%d', '(?<day>\d{2})')
|
257
|
+
regexp.gsub!('%-d', '(?<day>\d{1,2})')
|
258
|
+
regexp.gsub!('%H', '(?<hour>\d{2})')
|
259
|
+
regexp.gsub!('%k', '(?<hour>\d{2})')
|
260
|
+
regexp.gsub!('%-k', '(?<hour>\d{1,2})')
|
261
|
+
regexp.gsub!('*', '(?<glob>.*?)')
|
262
|
+
regexp.gsub!(/$/, '(?<rest>.*?)\z')
|
263
|
+
Regexp.compile(regexp)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def match_data_hash(match_data = nil)
|
268
|
+
return unless match_data.present?
|
269
|
+
Hash.new.tap do |hash|
|
270
|
+
match_data.names.map(&:to_sym).each do |key|
|
271
|
+
hash[key] = match_data[key.to_sym]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def matched_date(matched_data)
|
277
|
+
if timestamp = matched_data[:timestamp]
|
278
|
+
Time.at(timestamp.to_i).to_datetime
|
279
|
+
else
|
280
|
+
DateTime.new(*matched_data.values_at(:year, :month, :day, :hour).compact.map(&:to_i))
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def matched_extra(matched_data)
|
285
|
+
return {} unless matched_data.has_key?(:glob)
|
286
|
+
{glob: matched_data[:glob]}.reject { |_,v| v == '*' }
|
287
|
+
end
|
288
|
+
|
289
|
+
def options_for_elem
|
290
|
+
@options.reject { |k,_| [:path, :table].include?(k) }
|
291
|
+
end
|
292
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
#
|
3
|
+
# Copyright (c) 2014-2015, VMware, Inc. All Rights Reserved.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'set'
|
24
|
+
|
25
|
+
class Masamune::DataPlan::Set < Set
|
26
|
+
EMPTY = self.new
|
27
|
+
|
28
|
+
include Masamune::Accumulate
|
29
|
+
|
30
|
+
attr_reader :rule
|
31
|
+
|
32
|
+
def initialize(rule, enum = nil)
|
33
|
+
@rule = rule
|
34
|
+
super convert_enum(enum)
|
35
|
+
end
|
36
|
+
|
37
|
+
def union(enum = nil)
|
38
|
+
super(convert_enum(enum) || EMPTY)
|
39
|
+
end
|
40
|
+
|
41
|
+
def add(elem = nil)
|
42
|
+
super convert_elem(elem)
|
43
|
+
end
|
44
|
+
|
45
|
+
def include?(elem = nil)
|
46
|
+
super convert_elem(elem)
|
47
|
+
end
|
48
|
+
|
49
|
+
def missing(&block)
|
50
|
+
self.each do |elem|
|
51
|
+
yield elem if elem.explode.empty?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
method_accumulate :missing, lambda { |set| set.class.new(set.rule) }
|
55
|
+
|
56
|
+
def existing(&block)
|
57
|
+
self.each do |elem|
|
58
|
+
elem.explode do |new_elem|
|
59
|
+
yield new_elem
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
method_accumulate :existing, lambda { |set| set.class.new(set.rule) }
|
64
|
+
|
65
|
+
def adjacent(&block)
|
66
|
+
self.each do |elem|
|
67
|
+
@rule.adjacent_matches(elem) do |adj_elem|
|
68
|
+
yield adj_elem
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
method_accumulate :adjacent, lambda { |set| set.class.new(set.rule) }
|
73
|
+
|
74
|
+
def stale(&block)
|
75
|
+
return Masamune::DataPlan::Set::EMPTY if empty? || @rule.for_sources?
|
76
|
+
self.each do |target|
|
77
|
+
yield target if target.sources.existing.any? { |source| target_stale?(source, target) }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
method_accumulate :stale, lambda { |set| set.class.new(set.rule) }
|
81
|
+
|
82
|
+
def incomplete(&block)
|
83
|
+
return Masamune::DataPlan::Set::EMPTY if empty? || @rule.for_sources?
|
84
|
+
set = Set.new
|
85
|
+
self.each do |target|
|
86
|
+
yield target if set.add?(target) unless target.complete?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
method_accumulate :incomplete, lambda { |set| set.class.new(set.rule) }
|
90
|
+
|
91
|
+
def actionable(&block)
|
92
|
+
return Masamune::DataPlan::Set::EMPTY if empty? || @rule.for_sources?
|
93
|
+
set = Set.new
|
94
|
+
missing.each do |target|
|
95
|
+
yield target if set.add?(target)
|
96
|
+
end
|
97
|
+
incomplete.each do |target|
|
98
|
+
yield target if set.add?(target)
|
99
|
+
end
|
100
|
+
stale.each do |target|
|
101
|
+
yield target if set.add?(target)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
method_accumulate :actionable, lambda { |set| set.class.new(set.rule) }
|
105
|
+
|
106
|
+
def updateable(&block)
|
107
|
+
return Masamune::DataPlan::Set::EMPTY if empty? || @rule.for_sources?
|
108
|
+
set = Set.new
|
109
|
+
actionable.each do |target|
|
110
|
+
yield target if set.add?(target) && target.sources.existing.any?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
method_accumulate :updateable, lambda { |set| set.class.new(set.rule) }
|
114
|
+
|
115
|
+
# TODO detect & warn or correct if coarser grain set is incomplete
|
116
|
+
def with_grain(grain, &block)
|
117
|
+
seen = Set.new
|
118
|
+
self.each do |elem|
|
119
|
+
granular_elem = elem.round(grain)
|
120
|
+
yield granular_elem if seen.add?(granular_elem)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
method_accumulate :with_grain, lambda { |set, grain| set.class.new(set.rule.round(grain)) }
|
124
|
+
|
125
|
+
def targets
|
126
|
+
return Masamune::DataPlan::Set::EMPTY if empty? || @rule.for_targets?
|
127
|
+
self.class.new(self.first.targets.rule).tap do |set|
|
128
|
+
self.each do |elem|
|
129
|
+
set.merge elem.targets
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def sources
|
135
|
+
return Masamune::DataPlan::Set::EMPTY if empty? || @rule.for_sources?
|
136
|
+
self.class.new(self.first.sources.rule).tap do |set|
|
137
|
+
self.each do |elem|
|
138
|
+
set.merge elem.sources
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def convert_elem(elem)
|
146
|
+
case elem
|
147
|
+
when nil
|
148
|
+
when Masamune::DataPlan::Elem
|
149
|
+
elem
|
150
|
+
when String
|
151
|
+
@rule.bind_input(elem)
|
152
|
+
else
|
153
|
+
raise "Unhandled elem class #{elem.class}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def convert_enum(enum)
|
158
|
+
case enum
|
159
|
+
when nil
|
160
|
+
when Array
|
161
|
+
enum.flatten.uniq
|
162
|
+
when Set, self.class
|
163
|
+
enum
|
164
|
+
when String
|
165
|
+
[enum]
|
166
|
+
else
|
167
|
+
raise "Unhandled enum class #{enum.class}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def target_stale?(source, target)
|
172
|
+
target.last_modified_at != Masamune::DataPlan::Elem::MISSING_MODIFIED_AT &&
|
173
|
+
source.last_modified_at != Masamune::DataPlan::Elem::MISSING_MODIFIED_AT &&
|
174
|
+
source.last_modified_at >= target.last_modified_at
|
175
|
+
end
|
176
|
+
end
|