gd_bam 0.0.1
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.
- data/README.md +169 -0
- data/bin/bam +218 -0
- data/lib/bam/version.rb +3 -0
- data/lib/bam.rb +8 -0
- data/lib/dsl/project_dsl.rb +259 -0
- data/lib/graphs/docentize.grf +47 -0
- data/lib/graphs/dummy.grf +46 -0
- data/lib/graphs/load_history.grf +579 -0
- data/lib/graphs/process_account.grf +47 -0
- data/lib/graphs/process_activity.grf +222 -0
- data/lib/graphs/process_activity_dim.grf +88 -0
- data/lib/graphs/process_activity_owner.grf +48 -0
- data/lib/graphs/process_opportunity.grf +46 -0
- data/lib/graphs/process_opportunity_line_item.grf +179 -0
- data/lib/graphs/process_opportunity_snapshot.grf +94 -0
- data/lib/graphs/process_owner.grf +48 -0
- data/lib/graphs/process_stage.grf +51 -0
- data/lib/graphs/process_stage_history.grf +184 -0
- data/lib/graphs/process_velocity_duration.grf +140 -0
- data/lib/nodes/clover_gen.rb +1283 -0
- data/lib/nodes/dependency.rb +96 -0
- data/lib/nodes/nodes.rb +371 -0
- data/lib/repo/1_config.json +8 -0
- data/lib/repository/repo.rb +21 -0
- data/lib/runtime.rb +517 -0
- data/templates/dataset.json.erb +13 -0
- data/templates/flow.rb.erb +12 -0
- data/templates/params.json.erb +7 -0
- data/templates/project.erb +18 -0
- data/templates/source.json.erb +22 -0
- data/templates/tap.json.erb +16 -0
- data/templates/update_dataset.script.erb +4 -0
- data/templates/update_dataset_dry.script.erb +3 -0
- data/templates/workspace.prm.erb +25 -0
- metadata +412 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'rgl/adjacency'
|
2
|
+
require 'rgl/dot'
|
3
|
+
require 'rgl/topsort'
|
4
|
+
|
5
|
+
require 'repository/repo'
|
6
|
+
|
7
|
+
module GoodData
|
8
|
+
module CloverGenerator
|
9
|
+
module Dependency
|
10
|
+
|
11
|
+
|
12
|
+
class Visitor
|
13
|
+
|
14
|
+
def accept(node)
|
15
|
+
puts node
|
16
|
+
if node.type == "ldm"
|
17
|
+
puts "LDM #{node.to_s}"
|
18
|
+
else
|
19
|
+
puts "doing something on #{node.to_s}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class N
|
26
|
+
def initialize(x)
|
27
|
+
@x = x
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"#{@x[:type]}-#{@x[:name]}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def type
|
35
|
+
@x[:type]
|
36
|
+
end
|
37
|
+
|
38
|
+
def provides
|
39
|
+
@x[:provides]
|
40
|
+
end
|
41
|
+
|
42
|
+
def requires
|
43
|
+
@x[:requires]
|
44
|
+
end
|
45
|
+
|
46
|
+
def package
|
47
|
+
@x[:package]
|
48
|
+
end
|
49
|
+
|
50
|
+
def visit(v)
|
51
|
+
v.accept(self)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def resolve(repo, you)
|
58
|
+
repo << you
|
59
|
+
|
60
|
+
providers = repo.reduce({}) do |memo, mod|
|
61
|
+
package = mod.package
|
62
|
+
mod.provides.each do |providee|
|
63
|
+
memo[[package, providee].join('/')] = mod
|
64
|
+
end
|
65
|
+
memo
|
66
|
+
end
|
67
|
+
|
68
|
+
vertices = repo.reduce([]) do |memo, mod|
|
69
|
+
package = mod.package
|
70
|
+
reqs = mod.requires
|
71
|
+
len = reqs.length
|
72
|
+
req_modules = reqs.map do |m|
|
73
|
+
if providers[m].nil?
|
74
|
+
fail "Dependency not met. Looking for #{m} and could not find it"
|
75
|
+
else
|
76
|
+
providers[m]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
memo.concat([mod].cycle().take(len).zip(req_modules).flatten)
|
80
|
+
end
|
81
|
+
|
82
|
+
x = RGL::DirectedAdjacencyGraph[*vertices]
|
83
|
+
fail "Graph is cyclic" unless x.acyclic?
|
84
|
+
x
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_dependent(graph, you)
|
88
|
+
graph.bfs_search_tree_from(you)
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_dot(graph)
|
92
|
+
graph.write_to_graphic_file('jpg')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/nodes/nodes.rb
ADDED
@@ -0,0 +1,371 @@
|
|
1
|
+
module GoodData
|
2
|
+
module CloverGenerator
|
3
|
+
module Nodes
|
4
|
+
|
5
|
+
SF_CONNECTION = "SFDC"
|
6
|
+
EDGE = "EDGE"
|
7
|
+
WRITER = "DATA_WRITER"
|
8
|
+
READER = "DATA_READER"
|
9
|
+
SF_READER = "SF_READER"
|
10
|
+
REFORMAT = "REFORMAT"
|
11
|
+
PERSISTENT_LOOKUP = "persistentLookup"
|
12
|
+
GD_LOOKUP = "gdLookup"
|
13
|
+
GD_ESTORE_WRITER = "GD_ESTORE_WRITER"
|
14
|
+
GD_ESTORE_READER = "GD_ESTORE_READER"
|
15
|
+
ENABLED = "ENABLED"
|
16
|
+
DEFAULT_HEIGHT = "77"
|
17
|
+
DEFAULT_WIDTH = "128"
|
18
|
+
GD_DATASET_WRITER = "GD_DATASET_WRITER"
|
19
|
+
GD_ESTORE_TRUNCATE = "GD_ESTORE_TRUNCATE"
|
20
|
+
DATA_GENERATOR = "DATA_GENERATOR"
|
21
|
+
SIMPLE_GATHER = "SIMPLE_GATHER"
|
22
|
+
SIMPLE_COPY = "SIMPLE_COPY"
|
23
|
+
CHECK_FOREIGN_KEY = "CHECK_FOREIGN_KEY"
|
24
|
+
RUN_GRAPH = "RUN_GRAPH"
|
25
|
+
TRASH = "TRASH"
|
26
|
+
LOOKUP_TABLE_READER_WRITER = "LOOKUP_TABLE_READER_WRITER"
|
27
|
+
FILE_COPY_MOVE = "FILE_COPY_MOVE"
|
28
|
+
FILE_DELETE = "FILE_DELETE"
|
29
|
+
FILE_LIST = "FILE_LIST"
|
30
|
+
EXT_SORT = "EXT_SORT"
|
31
|
+
EXT_HASH_JOIN = "EXT_HASH_JOIN"
|
32
|
+
NORMALIZER = "NORMALIZER"
|
33
|
+
|
34
|
+
|
35
|
+
DEFAULT_NODE_PARAMS = {
|
36
|
+
:enabled => ENABLED,
|
37
|
+
:guiHeight => DEFAULT_HEIGHT,
|
38
|
+
:guiWidth => DEFAULT_WIDTH
|
39
|
+
}
|
40
|
+
|
41
|
+
def self.node(data, options={})
|
42
|
+
defaults = options[:defaults] || {}
|
43
|
+
required = options[:required] || []
|
44
|
+
allowed = options[:allowed] || []
|
45
|
+
output_data = defaults.merge(data)
|
46
|
+
required.each do |key|
|
47
|
+
unless output_data.has_key?(key)
|
48
|
+
fail "#{key} is required but not provided"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
output_data
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.base_node(data, options={})
|
55
|
+
defaults = DEFAULT_NODE_PARAMS.merge(options[:defaults] || {})
|
56
|
+
required = (options[:required] || []).concat([:type, :id])
|
57
|
+
allowed = options[:allowed] || []
|
58
|
+
output_data = defaults.merge(data)
|
59
|
+
|
60
|
+
node(output_data, {
|
61
|
+
:allowed => [:enabled, :guiName, :id, :type, :guiHeight, :guiWidth, :name].concat(allowed),
|
62
|
+
:required => required,
|
63
|
+
:defaults => defaults
|
64
|
+
})
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.gd_loader2(data, options={})
|
68
|
+
local_defaults = {
|
69
|
+
:type => GD_DATASET_WRITER,
|
70
|
+
:projectId => "${GDC_PROJECT_ID}",
|
71
|
+
}
|
72
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
73
|
+
base_node(defaults.merge(data), {
|
74
|
+
:allowed => [:enabled, :guiName, :id, :type, :guiHeight, :guiWidth, :name, :projectId, :dataset, :datasetFieldMappings],
|
75
|
+
:defaults => defaults,
|
76
|
+
:required => []
|
77
|
+
})
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.writer2(data, options={})
|
81
|
+
local_defaults = {
|
82
|
+
:type => WRITER,
|
83
|
+
:quoteCharacter => "\"",
|
84
|
+
:charset => "UTF-8",
|
85
|
+
:quotedStrings => "true",
|
86
|
+
:append => "false",
|
87
|
+
:outputFieldNames => "false"
|
88
|
+
}
|
89
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
90
|
+
|
91
|
+
base_node(defaults.merge(data), {
|
92
|
+
:allowed => [:fileURL, :quotedStrings, :quoteCharacter, :charset, :outputFieldNames, :append],
|
93
|
+
:defaults => defaults,
|
94
|
+
:required => [:fileURL]
|
95
|
+
})
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.reader2(data, options={})
|
99
|
+
local_defaults = {
|
100
|
+
:type => READER,
|
101
|
+
:quoteCharacter => "\"",
|
102
|
+
:charset => "UTF-8",
|
103
|
+
:quotedStrings => "true",
|
104
|
+
:skipRows => 1
|
105
|
+
}
|
106
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
107
|
+
|
108
|
+
base_node(defaults.merge(data), {
|
109
|
+
:allowed => [:fileURL, :quotedStrings, :quoteCharacter, :charset, :skipRows],
|
110
|
+
:defaults => defaults,
|
111
|
+
:required => [:fileURL]
|
112
|
+
})
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.sfdc_reader2(data, options={})
|
116
|
+
local_defaults = {
|
117
|
+
:type => SF_READER,
|
118
|
+
}
|
119
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
120
|
+
|
121
|
+
base_node(defaults.merge(data), {
|
122
|
+
:allowed => [:soql, :sfdcConnection, :mandatoryFields],
|
123
|
+
:defaults => defaults,
|
124
|
+
:required => [:soql, :sfdcConnection]
|
125
|
+
})
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.run_graph2(data, options={})
|
130
|
+
local_defaults = {
|
131
|
+
:type => RUN_GRAPH,
|
132
|
+
:paramsToPass => "GDC_WEBDAV_ROOT;GDC_PROJECT_ID;GDC_USERNAME;GDC_PASSWORD;GDC_SST"
|
133
|
+
}
|
134
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
135
|
+
|
136
|
+
base_node(defaults.merge(data), {
|
137
|
+
:allowed => [:paramsToPass, :type, :name, :clientId, :loginHostname, :name, :username, :password, :passwordEncrypted, :token, :id],
|
138
|
+
:defaults => defaults,
|
139
|
+
:required => [:graphName]
|
140
|
+
})
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.edge2(data, options={})
|
144
|
+
local_defaults = {
|
145
|
+
:type => EDGE,
|
146
|
+
:guiBendpoints => "",
|
147
|
+
:guiRouter => "Manhattan",
|
148
|
+
:inPort => "Port 0 (in)",
|
149
|
+
:outPort => "Port 0 (output)"
|
150
|
+
}
|
151
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
152
|
+
base_node(defaults.merge(data), {
|
153
|
+
:allowed => [],
|
154
|
+
:defaults => defaults,
|
155
|
+
:required => []
|
156
|
+
})
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.metadata2(data)
|
160
|
+
data
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.reformat2(data, options={})
|
164
|
+
local_defaults = {
|
165
|
+
:type => REFORMAT,
|
166
|
+
}
|
167
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
168
|
+
base_node(defaults.merge(data), {
|
169
|
+
:allowed => [],
|
170
|
+
:defaults => defaults,
|
171
|
+
:required => []
|
172
|
+
})
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.normalizer2(data, options={})
|
176
|
+
local_defaults = {
|
177
|
+
:type => NORMALIZER,
|
178
|
+
}
|
179
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
180
|
+
base_node(defaults.merge(data), {
|
181
|
+
:allowed => [],
|
182
|
+
:defaults => defaults,
|
183
|
+
:required => []
|
184
|
+
})
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def self.lookup_reader_writer2(data, options={})
|
189
|
+
local_defaults = {
|
190
|
+
:type => LOOKUP_TABLE_READER_WRITER,
|
191
|
+
}
|
192
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
193
|
+
base_node(defaults.merge(data), {
|
194
|
+
:allowed => [],
|
195
|
+
:defaults => defaults,
|
196
|
+
:required => []
|
197
|
+
})
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.lookup2(data, options={})
|
201
|
+
local_defaults = {
|
202
|
+
:type => PERSISTENT_LOOKUP,
|
203
|
+
:cacheSize => "1000",
|
204
|
+
:commitInterval => "100",
|
205
|
+
:pageSize => "16"
|
206
|
+
}
|
207
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
208
|
+
base_node(defaults.merge(data), {
|
209
|
+
:allowed => [],
|
210
|
+
:defaults => defaults,
|
211
|
+
:required => [:metadata]
|
212
|
+
})
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.trash2(data, options={})
|
216
|
+
local_defaults = {
|
217
|
+
:type => TRASH,
|
218
|
+
}
|
219
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
220
|
+
base_node(defaults.merge(data), {
|
221
|
+
:allowed => [],
|
222
|
+
:defaults => defaults,
|
223
|
+
:required => []
|
224
|
+
})
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.data_generator2(data, options={})
|
228
|
+
local_defaults = {
|
229
|
+
:type => DATA_GENERATOR,
|
230
|
+
:recordsNumber => 1
|
231
|
+
}
|
232
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
233
|
+
base_node(defaults.merge(data), {
|
234
|
+
:allowed => [],
|
235
|
+
:defaults => defaults,
|
236
|
+
:required => []
|
237
|
+
})
|
238
|
+
end
|
239
|
+
|
240
|
+
# <Node baseURL="${DATA}/1_in.csv" enabled="enabled" guiHeight="65" guiName="File List" guiWidth="128" guiX="147" guiY="213" id="FILE_LIST0" outputMapping="//#CTL2 // Transforms input record into output record. function integer transform() { 	$out.0.field1 = $in.0.fileName; 	return ALL; } // Called during component initialization. // function boolean init() {} // Called during each graph run before the transform is executed. May be used to allocate and initialize resources // required by the transform. All resources allocated within this method should be released // by the postExecute() method. // function void preExecute() {} // Called only if transform() throws an exception. // function integer transformOnError(string errorMessage, string stackTrace) {} // Called during each graph run after the entire transform was executed. Should be used to free any resources // allocated within the preExecute() method. // function void postExecute() {} // Called to return a user-defined error message when an error occurs. // function string getMessage() {} " type="FILE_LIST"/>
|
241
|
+
def self.file_list2(data, options={})
|
242
|
+
local_defaults = {
|
243
|
+
:type => FILE_LIST,
|
244
|
+
}
|
245
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
246
|
+
base_node(defaults.merge(data), {
|
247
|
+
:allowed => [],
|
248
|
+
:defaults => defaults,
|
249
|
+
:required => []
|
250
|
+
})
|
251
|
+
end
|
252
|
+
|
253
|
+
def self.hash_join2(data, options={})
|
254
|
+
local_defaults = {
|
255
|
+
:type => EXT_HASH_JOIN,
|
256
|
+
}
|
257
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
258
|
+
base_node(defaults.merge(data), {
|
259
|
+
:allowed => [],
|
260
|
+
:defaults => defaults,
|
261
|
+
:required => []
|
262
|
+
})
|
263
|
+
end
|
264
|
+
|
265
|
+
def self.sort2(data, options={})
|
266
|
+
local_defaults = {
|
267
|
+
:type => EXT_SORT,
|
268
|
+
}
|
269
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
270
|
+
base_node(defaults.merge(data), {
|
271
|
+
:allowed => [],
|
272
|
+
:defaults => defaults,
|
273
|
+
:required => []
|
274
|
+
})
|
275
|
+
end
|
276
|
+
|
277
|
+
def self.es_truncate2(data, options={})
|
278
|
+
local_defaults = {
|
279
|
+
:type => GD_ESTORE_TRUNCATE,
|
280
|
+
}
|
281
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
282
|
+
base_node(defaults.merge(data), {
|
283
|
+
:allowed => [],
|
284
|
+
:defaults => defaults,
|
285
|
+
:required => []
|
286
|
+
})
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
def self.es_reader2(data, options={})
|
291
|
+
local_defaults = {
|
292
|
+
:type => GD_ESTORE_READER,
|
293
|
+
}
|
294
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
295
|
+
base_node(defaults.merge(data), {
|
296
|
+
:allowed => [],
|
297
|
+
:defaults => defaults,
|
298
|
+
:required => []
|
299
|
+
})
|
300
|
+
end
|
301
|
+
|
302
|
+
def self.es_writer2(data, options={})
|
303
|
+
local_defaults = {
|
304
|
+
:type => GD_ESTORE_WRITER,
|
305
|
+
}
|
306
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
307
|
+
base_node(defaults.merge(data), {
|
308
|
+
:allowed => [],
|
309
|
+
:defaults => defaults,
|
310
|
+
:required => []
|
311
|
+
})
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
def self.file_delete2(data, options={})
|
316
|
+
local_defaults = {
|
317
|
+
:type => FILE_DELETE
|
318
|
+
}
|
319
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
320
|
+
base_node(defaults.merge(data), {
|
321
|
+
:allowed => [],
|
322
|
+
:defaults => defaults,
|
323
|
+
:required => []
|
324
|
+
})
|
325
|
+
end
|
326
|
+
|
327
|
+
def self.file_copy2(data, options={})
|
328
|
+
local_defaults = {
|
329
|
+
:type => FILE_COPY_MOVE,
|
330
|
+
:operation => "COPY",
|
331
|
+
:baseURL => "${PROJECT}"
|
332
|
+
}
|
333
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
334
|
+
base_node(defaults.merge(data), {
|
335
|
+
:allowed => [],
|
336
|
+
:defaults => defaults,
|
337
|
+
:required => []
|
338
|
+
})
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
def self.copy2(data, options={})
|
343
|
+
local_defaults = {
|
344
|
+
:type => SIMPLE_COPY,
|
345
|
+
}
|
346
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
347
|
+
base_node(defaults.merge(data), {
|
348
|
+
:allowed => [],
|
349
|
+
:defaults => defaults,
|
350
|
+
:required => []
|
351
|
+
})
|
352
|
+
end
|
353
|
+
|
354
|
+
def self.connection2(data, options={})
|
355
|
+
local_defaults = {
|
356
|
+
:type => SF_CONNECTION,
|
357
|
+
:passwordEncrypted => "false",
|
358
|
+
:loginHostname => "login.salesforce.com",
|
359
|
+
:clientId => "gooddata/gooddata/",
|
360
|
+
:name => "Salesforce connection"
|
361
|
+
}
|
362
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
363
|
+
node(defaults.merge(data), {
|
364
|
+
:allowed => [:type, :name, :clientId, :loginHostname, :name, :username, :password, :passwordEncrypted, :token, :id],
|
365
|
+
:defaults => defaults,
|
366
|
+
:required => [:password, :username, :token, :loginHostname, :id, :clientId, :name]
|
367
|
+
})
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module GoodData
|
2
|
+
module CloverGenerator
|
3
|
+
module Repo
|
4
|
+
|
5
|
+
def self.parse(json_definition)
|
6
|
+
JSON.parse(json_definition, :symbolize_names => true)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.load(path)
|
10
|
+
definitions = nil
|
11
|
+
FileUtils.cd(path) do
|
12
|
+
definitions = Dir.glob('*.json').map do |f|
|
13
|
+
parse(File.read(f))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
definitions
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|