zillabyte-cli 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/zillabyte-cli/version.rb +1 -1
- data/lib/zillabyte-cli/version.rb~ +5 -0
- data/lib/zillabyte/api/data.rb +19 -3
- data/lib/zillabyte/api/flows.rb +38 -1
- data/lib/zillabyte/cli/flows.rb +208 -9
- data/lib/zillabyte/cli/relations.rb +151 -24
- data/lib/zillabyte/cli/templates/js/simple_function.js +2 -2
- data/lib/zillabyte/cli/templates/python/simple_function.py +2 -2
- data/lib/zillabyte/cli/templates/ruby/Gemfile.lock +37 -0
- data/lib/zillabyte/cli/templates/ruby/simple_function.rb +4 -4
- data/zillabyte-cli.gemspec +1 -0
- metadata +20 -3
- data/lib/zillabyte/cli/logs.rb +0 -117
data/lib/zillabyte/api/data.rb
CHANGED
@@ -4,19 +4,35 @@ class Zillabyte::API::Data < Zillabyte::API::Base
|
|
4
4
|
|
5
5
|
# GET /datasets/1
|
6
6
|
def get(id, options = {})
|
7
|
-
|
8
7
|
res = @api.request(
|
9
8
|
:expects => 200,
|
10
9
|
:method => :get,
|
11
10
|
:path => "/relations/#{id}",
|
12
11
|
:body => options.to_json
|
13
12
|
)
|
14
|
-
|
15
13
|
res.body
|
16
|
-
|
17
14
|
end
|
18
15
|
|
16
|
+
def pull(id, options = {})
|
17
|
+
res = @api.request(
|
18
|
+
:expects => 200,
|
19
|
+
:method => :post,
|
20
|
+
:path => "/relations/#{id}/pull",
|
21
|
+
:body => options.to_json
|
22
|
+
)
|
23
|
+
res.body
|
24
|
+
end
|
19
25
|
|
26
|
+
def pull_to_s3(id, options)
|
27
|
+
res = @api.request(
|
28
|
+
:expects => 200,
|
29
|
+
:method => :post,
|
30
|
+
:path => "/relations/#{id}/pull_to_s3",
|
31
|
+
:body => options.to_json
|
32
|
+
)
|
33
|
+
res.body
|
34
|
+
end
|
35
|
+
|
20
36
|
# POST /datasets
|
21
37
|
def create(name, options = {})
|
22
38
|
|
data/lib/zillabyte/api/flows.rb
CHANGED
@@ -63,9 +63,46 @@ class Zillabyte::API::Flows < Zillabyte::API::Base
|
|
63
63
|
|
64
64
|
end
|
65
65
|
|
66
|
+
def delete(id, options ={})
|
67
|
+
res = @api.request(
|
68
|
+
:expects => 200,
|
69
|
+
:method => :delete,
|
70
|
+
:path => "/flows/#{id}",
|
71
|
+
:body => options.to_json
|
72
|
+
)
|
73
|
+
res.body
|
74
|
+
end
|
75
|
+
|
76
|
+
def list_cycles(id, options={})
|
77
|
+
res = @api.request(
|
78
|
+
:expects => 200,
|
79
|
+
:method => :get,
|
80
|
+
:path => "/flows/#{id}/cycles",
|
81
|
+
:body => options.to_json
|
82
|
+
)
|
83
|
+
res.body
|
84
|
+
|
85
|
+
end
|
66
86
|
|
87
|
+
def create_cycle(id, options ={})
|
88
|
+
res = @api.request(
|
89
|
+
:expects => 200,
|
90
|
+
:method => :post,
|
91
|
+
:path => "/flows/#{id}/cycles",
|
92
|
+
:body => options.to_json
|
93
|
+
)
|
94
|
+
res.body
|
95
|
+
end
|
67
96
|
|
68
|
-
|
97
|
+
def run_forever(id, options ={})
|
98
|
+
res = @api.request(
|
99
|
+
:expects => 200,
|
100
|
+
:method => :post,
|
101
|
+
:path => "/flows/#{id}/cycles/run_forever",
|
102
|
+
:body => options.to_json
|
103
|
+
)
|
104
|
+
res.body
|
105
|
+
end
|
69
106
|
|
70
107
|
|
71
108
|
|
data/lib/zillabyte/cli/flows.rb
CHANGED
@@ -5,6 +5,7 @@ require "pty"
|
|
5
5
|
require 'indentation'
|
6
6
|
require 'open3'
|
7
7
|
require 'securerandom'
|
8
|
+
require 'colorize'
|
8
9
|
|
9
10
|
# manage custom flows
|
10
11
|
#
|
@@ -24,7 +25,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
|
|
24
25
|
#
|
25
26
|
def list
|
26
27
|
|
27
|
-
headings = ["id", "name", "state"]
|
28
|
+
headings = ["id", "name", "state", "cycles"]
|
28
29
|
rows = api.flow.list.map do |row|
|
29
30
|
if headings.size == 0
|
30
31
|
headings = row.keys
|
@@ -103,6 +104,33 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
|
|
103
104
|
alias_command "pull", "flows:pull"
|
104
105
|
|
105
106
|
|
107
|
+
# flows:delete ID
|
108
|
+
#
|
109
|
+
# deletes a flow. if the flow is running, this command will kill it.
|
110
|
+
#
|
111
|
+
# -f, --force # don't ask for confirmation
|
112
|
+
def delete
|
113
|
+
id = options[:id] || shift_argument
|
114
|
+
forced = options[:force]
|
115
|
+
if not forced
|
116
|
+
while true
|
117
|
+
|
118
|
+
display "This operation cannot be undone. Are you sure you want to delete this flow? (yes/no):", false
|
119
|
+
confirm = ask
|
120
|
+
break if confirm == "yes" || confirm == "no"
|
121
|
+
display "Please enter 'yes' to delete the flow or 'no' to exit"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
confirmed = forced || confirm == "yes"
|
126
|
+
|
127
|
+
if confirmed
|
128
|
+
response = api.flows.delete(id)
|
129
|
+
display response["body"]
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
106
134
|
|
107
135
|
|
108
136
|
# flows:prep [DIR]
|
@@ -171,6 +199,72 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
|
|
171
199
|
|
172
200
|
|
173
201
|
|
202
|
+
# flow:show FLOW_ID [OPERATION]
|
203
|
+
#
|
204
|
+
# streams logs from the distributed workers
|
205
|
+
#
|
206
|
+
# -t, --tail # continuously watches for new results
|
207
|
+
# -v, --verbose LEVEL # sets the verbosity (error, info, debug) (default: info)
|
208
|
+
#
|
209
|
+
def logs
|
210
|
+
|
211
|
+
flow_id = options[:flow] || shift_argument
|
212
|
+
operation_id = options[:operation] || shift_argument || '_ALL_'
|
213
|
+
tail = options[:tail]
|
214
|
+
priority = options[:verbose] || 'debug'
|
215
|
+
carry_settings = {
|
216
|
+
:priority => priority
|
217
|
+
}
|
218
|
+
api_options = {}
|
219
|
+
|
220
|
+
error "no id given" if flow_id.nil?
|
221
|
+
|
222
|
+
begin
|
223
|
+
|
224
|
+
res = self.api.logs.get(flow_id, operation_id, api_options)
|
225
|
+
|
226
|
+
carry_settings = show_log_output(res, carry_settings)
|
227
|
+
api_options[:since] = carry_settings[:since]
|
228
|
+
|
229
|
+
if (tail)
|
230
|
+
sleep(5) # HACK
|
231
|
+
end
|
232
|
+
end while(tail)
|
233
|
+
|
234
|
+
end
|
235
|
+
alias_command "logs", "flows:logs"
|
236
|
+
|
237
|
+
|
238
|
+
# flow:cycles ID [OPTIONS]
|
239
|
+
#
|
240
|
+
# operations on the flow's cycles (batches).
|
241
|
+
# with no options, the command lists the flows cycles
|
242
|
+
# -n, --next # request the flow to move to the next cycle
|
243
|
+
# -f, --forever # don't wait on cycles any more
|
244
|
+
def cycles
|
245
|
+
flow_id = options[:id] || shift_argument
|
246
|
+
trigger_next = options[:next] || false
|
247
|
+
trigger_forever = options[:forever] || false
|
248
|
+
error "id required" if flow_id.nil?
|
249
|
+
|
250
|
+
if trigger_next
|
251
|
+
# Trigger the next flow
|
252
|
+
response = api.flows.create_cycle(flow_id)
|
253
|
+
elsif trigger_forever
|
254
|
+
response = api.flows.run_forever(flow_id)
|
255
|
+
else
|
256
|
+
# List the flows
|
257
|
+
response = api.flows.list_cycles(flow_id)
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
display response
|
263
|
+
end
|
264
|
+
|
265
|
+
|
266
|
+
|
267
|
+
|
174
268
|
# flows:test [TEST_DATASET_ID]
|
175
269
|
#
|
176
270
|
# tests a local flow with sample data
|
@@ -307,15 +401,55 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
|
|
307
401
|
end
|
308
402
|
|
309
403
|
end
|
404
|
+
|
405
|
+
# An Aggregate?
|
406
|
+
elsif type == "aggregate"
|
407
|
+
if node['consumes']
|
408
|
+
input_stream = node['consumes']
|
409
|
+
else
|
410
|
+
input_stream = stream_messages.keys.first
|
411
|
+
end
|
412
|
+
messages = stream_messages[input_stream] || []
|
413
|
+
stream_messages[input_stream] = []
|
310
414
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
415
|
+
group_by = node['group_by']
|
416
|
+
group_tuples = {}
|
417
|
+
messages.each do |msg|
|
418
|
+
msg = JSON.parse(msg)
|
419
|
+
tuple = msg["tuple"].to_json
|
420
|
+
meta = msg["meta"].to_json
|
421
|
+
column_aliases = msg["column_aliases"] || {}
|
422
|
+
aliases = Hash[column_aliases.map{|h| [h["alias"],h["concrete_name"]]}]
|
423
|
+
gt = {}
|
424
|
+
group_by.each do |field|
|
425
|
+
field_name = aliases[field] || field
|
426
|
+
gt[field] = msg["tuple"][field_name]
|
427
|
+
end
|
428
|
+
|
429
|
+
msg_no_brackets = "\"tuple\": #{tuple}, \"meta\": #{meta}, \"column_aliases\": #{column_aliases.to_json}"
|
430
|
+
if group_tuples[gt]
|
431
|
+
group_tuples[gt] << msg_no_brackets
|
432
|
+
else
|
433
|
+
group_tuples[gt] = [msg_no_brackets]
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
group_tuples.each do |group_tuple, tuples|
|
438
|
+
stream_messages[input_stream] << "{\"command\": \"begin_group\", \"tuple\": #{group_tuple.to_json}, \"meta\":{}}\n"
|
439
|
+
tuples.each do |t|
|
440
|
+
stream_messages[input_stream] << "{\"command\": \"aggregate\", #{t}}\n"
|
441
|
+
end
|
442
|
+
stream_messages[input_stream] << "{\"command\": \"end_group\"}\n"
|
443
|
+
end
|
444
|
+
|
315
445
|
# A Sink?
|
316
|
-
|
446
|
+
elsif type == "sink"
|
317
447
|
|
318
|
-
if split_branches || stream_messages.size > 1
|
448
|
+
if split_branches || stream_messages.size > 1
|
449
|
+
split_branches = true
|
450
|
+
if node['consumes'].nil?
|
451
|
+
error "The node #{name} must declare which stream it 'consumes'"
|
452
|
+
end
|
319
453
|
sink_stream = node["consumes"]
|
320
454
|
messages = stream_messages[sink_stream] || []
|
321
455
|
else
|
@@ -354,7 +488,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
|
|
354
488
|
|
355
489
|
|
356
490
|
|
357
|
-
next
|
491
|
+
next
|
358
492
|
end
|
359
493
|
|
360
494
|
|
@@ -491,6 +625,11 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
|
|
491
625
|
end
|
492
626
|
rescue PTY::ChildExited
|
493
627
|
puts "The child process exited!"
|
628
|
+
ensure
|
629
|
+
# We need to check here to see if we need to turn on multistream mode.
|
630
|
+
# Note that we still need the redundant checks above, in case the user
|
631
|
+
# didn't honor the emits contract.
|
632
|
+
split_branches = true if node["emits"].size() > 1
|
494
633
|
end
|
495
634
|
end
|
496
635
|
|
@@ -517,7 +656,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
|
|
517
656
|
|
518
657
|
|
519
658
|
|
520
|
-
# flows:live_run [DIR]
|
659
|
+
# flows:live_run [OPERATION_NAME] [PIPE_NAME] [DIR]
|
521
660
|
#
|
522
661
|
# runs a local flow with live data
|
523
662
|
#
|
@@ -598,6 +737,66 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
|
|
598
737
|
|
599
738
|
private
|
600
739
|
|
740
|
+
def show_log_output(lines, settings = {})
|
741
|
+
|
742
|
+
@colors ||= [:green, :yellow, :magenta, :cyan, :light_black, :light_green, :light_yellow, :light_blue, :light_magenta, :light_cyan]
|
743
|
+
|
744
|
+
max_category_size = 0
|
745
|
+
all_lines = []
|
746
|
+
|
747
|
+
lines.each_pair do |operation, lines|
|
748
|
+
settings[operation] ||= {}
|
749
|
+
settings[operation][:color] ||= @colors.shift
|
750
|
+
lines.each do |line_h|
|
751
|
+
|
752
|
+
line = line_h['line']
|
753
|
+
priority = line_h['priority']
|
754
|
+
date = line_h['date']
|
755
|
+
|
756
|
+
all_lines << {
|
757
|
+
:line => line,
|
758
|
+
:category => operation,
|
759
|
+
:priority => priority,
|
760
|
+
:color => settings[operation][:color],
|
761
|
+
:date => date
|
762
|
+
}
|
763
|
+
max_category_size = [max_category_size, operation.size].max
|
764
|
+
|
765
|
+
if settings[:since]
|
766
|
+
settings[:since] = [date, settings[:since]].max
|
767
|
+
else
|
768
|
+
settings[:since] = date
|
769
|
+
end
|
770
|
+
|
771
|
+
end
|
772
|
+
|
773
|
+
end
|
774
|
+
|
775
|
+
all_lines.sort! do |a,b|
|
776
|
+
a[:date] <=> b[:date]
|
777
|
+
end
|
778
|
+
|
779
|
+
requested_priority = settings[:priority]
|
780
|
+
|
781
|
+
all_lines.each do |h|
|
782
|
+
color = h[:color]
|
783
|
+
|
784
|
+
case h[:priority]
|
785
|
+
when 'error'
|
786
|
+
color = :red if h[:priority] == 'error'
|
787
|
+
when 'info'
|
788
|
+
next if ['error'].member?(requested_priority)
|
789
|
+
when 'system'
|
790
|
+
when 'debug'
|
791
|
+
next if ['info', 'error'].member?(requested_priority)
|
792
|
+
end
|
793
|
+
|
794
|
+
display "#{h[:category].rjust(max_category_size)} #{h[:priority].rjust(6)} - #{h[:line]}".colorize(color)
|
795
|
+
end
|
796
|
+
|
797
|
+
settings
|
798
|
+
end
|
799
|
+
|
601
800
|
|
602
801
|
|
603
802
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require "zillabyte/cli/base"
|
2
2
|
require "csv"
|
3
|
+
require "open-uri"
|
4
|
+
require "aws-sdk"
|
3
5
|
|
4
6
|
# manage custom relations
|
5
7
|
#
|
@@ -122,23 +124,25 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
|
|
122
124
|
#
|
123
125
|
# creates a new relation
|
124
126
|
#
|
125
|
-
# --schema SCHEMA
|
126
|
-
# --public
|
127
|
-
# --file
|
128
|
-
# --type
|
127
|
+
# --schema SCHEMA # a JSON object of column types
|
128
|
+
# --public SCOPE # Make the relation public
|
129
|
+
# --file FILE # A data file
|
130
|
+
# --type FILE_TYPE # type of data file [csv (default), xlsx]
|
131
|
+
# --description DESCRIPTION # Description of relation contents
|
129
132
|
#
|
130
133
|
def create
|
131
134
|
|
132
135
|
name = options[:name] || shift_argument
|
133
|
-
file = options[:file] ||
|
136
|
+
file = options[:file] || nil
|
134
137
|
type = options[:type] || nil
|
135
138
|
|
136
139
|
error "no name given" if name.nil?
|
137
140
|
|
138
|
-
schema =
|
139
|
-
is_public = options[:public] ||
|
141
|
+
schema = options[:schema] if options[:schema]
|
142
|
+
is_public = options[:public] || nil
|
143
|
+
description = options[:description] || nil
|
140
144
|
|
141
|
-
hash = set_relation_properties(schema,is_public)
|
145
|
+
hash = set_relation_properties(schema,is_public,description)
|
142
146
|
if file
|
143
147
|
type ||= File.extname(file).gsub(".", "")
|
144
148
|
rows = sanity_check_file(file,type, {"columns" => hash[:schema]})
|
@@ -174,15 +178,96 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
|
|
174
178
|
type ||= File.extname(file).gsub(".", "")
|
175
179
|
|
176
180
|
relation = self.api.data.get(id)
|
177
|
-
|
181
|
+
columns = relation["columns"].map{|col| {col["index"] => col["type"]}}
|
182
|
+
rows = sanity_check_file(file,type,{"columns" => columns})
|
178
183
|
|
179
184
|
res = self.api.data.append(id, {:rows => rows})
|
180
|
-
display "relation
|
185
|
+
display "relation ##{id} appended #{res["size"]} rows"
|
181
186
|
|
182
187
|
end
|
183
188
|
alias_command "append", "relations:append"
|
184
189
|
alias_command "rl:append", "relations:append"
|
185
190
|
|
191
|
+
# relations:pull ID OUTPUT
|
192
|
+
#
|
193
|
+
# pulls relation data into OUTPUT
|
194
|
+
# if s3 parameters specified, pulls relation data to S3_BUCKET/OUTPUT/
|
195
|
+
#
|
196
|
+
# --type TYPE # interpret file as type [csv, xlsx]
|
197
|
+
#
|
198
|
+
def pull
|
199
|
+
|
200
|
+
id = options[:id] || shift_argument
|
201
|
+
file = options[:file] || shift_argument
|
202
|
+
error "no id given" if id.nil?
|
203
|
+
error "no output file given" if file.nil?
|
204
|
+
type = options[:type]
|
205
|
+
type ||= File.extname(file).gsub(".", "")
|
206
|
+
|
207
|
+
res = self.api.data.pull(id)
|
208
|
+
if(res["uri"])
|
209
|
+
File.open(file, "w") do |f|
|
210
|
+
f.write open(res["uri"]).read
|
211
|
+
end
|
212
|
+
elsif(res["s3_credentials"])
|
213
|
+
display "request sent...depending on the size of your file, this may take a while..."
|
214
|
+
s3 = AWS::S3.new(res["s3_credentials"])
|
215
|
+
bucket = s3.buckets[res["s3_bucket"]]
|
216
|
+
obj = bucket.objects.with_prefix("#{res["s3_file_key"]}/")
|
217
|
+
while(true)
|
218
|
+
keys = obj.collect(&:key)
|
219
|
+
if keys.length > 0 and keys.include?("#{res["s3_file_key"]}/manifest")
|
220
|
+
File.open(file, "w") do |f|
|
221
|
+
obj.each do |o|
|
222
|
+
if o.key == "#{res["s3_file_key"]}/manifest"
|
223
|
+
next
|
224
|
+
end
|
225
|
+
f.write(o.read)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
break
|
229
|
+
else
|
230
|
+
sleep(3)
|
231
|
+
obj = bucket.objects.with_prefix("#{res["s3_file_key"]}/")
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
display "pulled data from relation ##{id} to file #{file}"
|
236
|
+
|
237
|
+
end
|
238
|
+
alias_command "rl:pull", "relations:pull"
|
239
|
+
|
240
|
+
# relations:pull:s3 ID S3_KEY S3_SECRET S3_BUCKET S3_FILE_PATH
|
241
|
+
#
|
242
|
+
# pulls relation data to S3_BUCKET/FILE_PATH/
|
243
|
+
#
|
244
|
+
# --type TYPE # interpret file as type [csv, xlsx]
|
245
|
+
#
|
246
|
+
def pull_to_s3
|
247
|
+
|
248
|
+
id = options[:id] || shift_argument
|
249
|
+
error "no id given" if id.nil?
|
250
|
+
|
251
|
+
user_s3_access_key = options[:s3_access_key] || shift_argument
|
252
|
+
user_s3_secret = options[:s3_secret] || shift_argument
|
253
|
+
user_s3_bucket = options[:s3_bucket] || shift_argument
|
254
|
+
user_s3_file_path = options[:s3_file_path] || shift_argument
|
255
|
+
error "no s3 access key provided" if user_s3_access_key.nil?
|
256
|
+
error "no s3 secret provided" if user_s3_secret.nil?
|
257
|
+
error "no s3 bucket provided" if user_s3_bucket.nil?
|
258
|
+
error "no s3 file path specified" if user_s3_file_path.nil?
|
259
|
+
|
260
|
+
s3_params = {:s3_access_key => user_s3_access_key, :s3_secret => user_s3_secret,
|
261
|
+
:s3_bucket => user_s3_bucket, :s3_object_key => user_s3_file_path}
|
262
|
+
|
263
|
+
res = self.api.data.pull_to_s3(id, s3_params)
|
264
|
+
display "downloading relation data to s3://#{res["s3_bucket"]}/#{res["s3_file_key"]}/"
|
265
|
+
display "if the relation is large, this may take a while, please check your s3 account after a few minutes"
|
266
|
+
|
267
|
+
end
|
268
|
+
alias_command "relations:pull:s3", "relations:pull_to_s3"
|
269
|
+
alias_command "rl:pull:s3", "relations:pull_to_s3"
|
270
|
+
|
186
271
|
|
187
272
|
# relations:show ID
|
188
273
|
#
|
@@ -246,11 +331,16 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
|
|
246
331
|
|
247
332
|
|
248
333
|
|
249
|
-
def set_relation_properties(schema,is_public)
|
250
|
-
|
334
|
+
def set_relation_properties(schema,is_public,description)
|
335
|
+
if description.nil?
|
336
|
+
display "Enter a description for your relation (defaults to empty string)."
|
337
|
+
description = ask.strip
|
338
|
+
end
|
339
|
+
|
340
|
+
valid_types=["STRING", "INTEGER", "FLOAT"]
|
251
341
|
meta_names=["confidence", "since", "source"]
|
252
342
|
if schema.nil?
|
253
|
-
schema =
|
343
|
+
schema = ""
|
254
344
|
|
255
345
|
# Get the column types (required)
|
256
346
|
index = 1
|
@@ -261,7 +351,7 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
|
|
261
351
|
display "Column #{index} name (empty when done): ", false
|
262
352
|
cname = ask.strip
|
263
353
|
break if cname == "" || cname.nil?
|
264
|
-
if(
|
354
|
+
if(cname =~ /^v[0-9]+$/i or meta_names.member?(cname.downcase))
|
265
355
|
warn "\"v[number]\", \"confidence\", \"since\" and \"source\" are special names in Zillabyte. Please name your column name something else."
|
266
356
|
next
|
267
357
|
end
|
@@ -277,27 +367,64 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
|
|
277
367
|
next
|
278
368
|
end
|
279
369
|
index += 1
|
280
|
-
schema
|
370
|
+
schema += "#{cname}:#{ctype},"
|
281
371
|
already_aliased[cname] = 1
|
372
|
+
end
|
373
|
+
schema = schema[0...-1]
|
374
|
+
end
|
375
|
+
schema = schema.split(",").map { |x| Hash[*x.split(":")] }
|
376
|
+
display "using schema: #{schema.to_json}"
|
377
|
+
|
378
|
+
if is_public.nil?
|
379
|
+
while true
|
380
|
+
display "Would you like your relation to be public? (yes or no)"
|
381
|
+
pp = ask.strip.downcase
|
382
|
+
if(pp == "yes" or pp == "y")
|
383
|
+
is_public = "public"
|
384
|
+
break
|
385
|
+
elsif(pp == "no" or pp == "n")
|
386
|
+
is_public = "private"
|
387
|
+
break
|
388
|
+
end
|
282
389
|
end
|
283
|
-
|
284
|
-
display "using schema: #{schema.to_json}"
|
285
|
-
|
286
390
|
end
|
287
|
-
|
391
|
+
|
392
|
+
{:schema => schema, :public => is_public, :description => description}
|
288
393
|
end
|
289
394
|
|
290
395
|
def sanity_check_file(file,type,dataset)
|
291
396
|
rows = []
|
292
|
-
|
397
|
+
|
398
|
+
n_columns = dataset["columns"].size
|
399
|
+
float_cols = []
|
400
|
+
int_cols = []
|
401
|
+
(0...n_columns).each do |i|
|
402
|
+
value = dataset["columns"][i].values[0].downcase
|
403
|
+
# use integer instead of numeric to be consistent with multilang type declarations
|
404
|
+
if(value == 'integer')
|
405
|
+
int_cols << i
|
406
|
+
elsif(value == "float")
|
407
|
+
float_cols << i
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
293
411
|
case type
|
294
412
|
when "csv"
|
295
413
|
CSV.foreach(file) do |row|
|
296
|
-
if row.size !=
|
297
|
-
|
298
|
-
|
299
|
-
|
414
|
+
if row.size != n_columns
|
415
|
+
error "relation expect #{n_columns} column(s). Found a row with #{row.size}::\n #{row}"
|
416
|
+
end
|
417
|
+
float_cols.each do |i|
|
418
|
+
if(!(row[i] =~ /^[+-]?(\d+(.\d+)?)$/))
|
419
|
+
error "column #{i+1} should be a FLOAT in row::\n #{row}"
|
420
|
+
end
|
421
|
+
end
|
422
|
+
int_cols.each do |i|
|
423
|
+
if(!(row[i] =~ /^[+-]?(\d+)$/))
|
424
|
+
error "column #{i+1} should be an INTEGER in row::\n #{row}"
|
425
|
+
end
|
300
426
|
end
|
427
|
+
rows << row
|
301
428
|
end
|
302
429
|
|
303
430
|
else
|
@@ -9,8 +9,8 @@ function prep(controller) {
|
|
9
9
|
* of machines.
|
10
10
|
*/
|
11
11
|
function exec(controller, tuple) {
|
12
|
-
if(tuple
|
13
|
-
controller.emit("has_hello_world",{"url":tuple
|
12
|
+
if(tuple["html"].indexOf("hello world") !== -1) {
|
13
|
+
controller.emit("has_hello_world",{"url":tuple["url"]});
|
14
14
|
}
|
15
15
|
}
|
16
16
|
|
@@ -7,8 +7,8 @@ def prep(controller):
|
|
7
7
|
# web page. This algorithm is run in parallel on possibly hundreds
|
8
8
|
# of machines.
|
9
9
|
def execute(controller, tup):
|
10
|
-
if("hello world" in tup
|
11
|
-
controller.emit("has_hello_world",{"url":tup
|
10
|
+
if("hello world" in tup["html"]):
|
11
|
+
controller.emit("has_hello_world",{"url":tup["url"]})
|
12
12
|
return
|
13
13
|
|
14
14
|
zillabyte.simple_function(\
|
@@ -0,0 +1,37 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.2.17)
|
5
|
+
i18n (~> 0.6, >= 0.6.4)
|
6
|
+
multi_json (~> 1.0)
|
7
|
+
ascii_charts (0.9.1)
|
8
|
+
chronic (0.10.2)
|
9
|
+
colorize (0.6.0)
|
10
|
+
excon (0.31.0)
|
11
|
+
i18n (0.6.9)
|
12
|
+
indentation (0.1.1)
|
13
|
+
mime-types (2.1)
|
14
|
+
multi_json (1.8.4)
|
15
|
+
netrc (0.7.7)
|
16
|
+
rest-client (1.6.7)
|
17
|
+
mime-types (>= 1.16)
|
18
|
+
terminal-table (1.4.5)
|
19
|
+
zillabyte (0.0.9)
|
20
|
+
zillabyte-cli
|
21
|
+
zillabyte-cli (0.0.10)
|
22
|
+
activesupport (~> 3.2.11)
|
23
|
+
ascii_charts (~> 0.9.1)
|
24
|
+
bundler (~> 1.3)
|
25
|
+
chronic (~> 0.10)
|
26
|
+
colorize (~> 0.6)
|
27
|
+
excon (~> 0.31)
|
28
|
+
indentation (~> 0.1)
|
29
|
+
netrc (~> 0.7.7)
|
30
|
+
rest-client (~> 1.6.1)
|
31
|
+
terminal-table (~> 1.4)
|
32
|
+
|
33
|
+
PLATFORMS
|
34
|
+
ruby
|
35
|
+
|
36
|
+
DEPENDENCIES
|
37
|
+
zillabyte
|
@@ -19,15 +19,15 @@ Zillabyte.simple_function do |fn|
|
|
19
19
|
fn.execute do |controller, tuple|
|
20
20
|
|
21
21
|
# get the fields
|
22
|
-
url = tuple['
|
23
|
-
html = tuple['
|
22
|
+
url = tuple['url']
|
23
|
+
html = tuple['html']
|
24
24
|
|
25
25
|
# For the purpose of this test, to show results from the test set,
|
26
26
|
# we'll loosen the search to include either hello or world
|
27
27
|
# instead of
|
28
28
|
# if html.include?('hello world')
|
29
|
-
if html.include?('hello
|
30
|
-
controller.emit("URL" => url)
|
29
|
+
if html.include?('hello world')
|
30
|
+
controller.emit("has_hello_world", "URL" => url)
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
data/zillabyte-cli.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zillabyte-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-02-
|
12
|
+
date: 2014-02-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -187,6 +187,22 @@ dependencies:
|
|
187
187
|
- - ~>
|
188
188
|
- !ruby/object:Gem::Version
|
189
189
|
version: '0.1'
|
190
|
+
- !ruby/object:Gem::Dependency
|
191
|
+
name: aws-sdk
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
193
|
+
none: false
|
194
|
+
requirements:
|
195
|
+
- - ~>
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: 1.33.0
|
198
|
+
type: :runtime
|
199
|
+
prerelease: false
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ~>
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: 1.33.0
|
190
206
|
description: The Official Zillabyte CLI Gem
|
191
207
|
email:
|
192
208
|
- gem@zillabyte.com
|
@@ -217,7 +233,6 @@ files:
|
|
217
233
|
- lib/zillabyte/cli/help.rb
|
218
234
|
- lib/zillabyte/cli/helpers/data_schema_builder.rb
|
219
235
|
- lib/zillabyte/cli/host.rb
|
220
|
-
- lib/zillabyte/cli/logs.rb
|
221
236
|
- lib/zillabyte/cli/query.rb
|
222
237
|
- lib/zillabyte/cli/relations.rb
|
223
238
|
- lib/zillabyte/cli/sources.rb
|
@@ -227,6 +242,7 @@ files:
|
|
227
242
|
- lib/zillabyte/cli/templates/python/simple_function.py
|
228
243
|
- lib/zillabyte/cli/templates/python/zillabyte.conf.yaml
|
229
244
|
- lib/zillabyte/cli/templates/ruby/Gemfile
|
245
|
+
- lib/zillabyte/cli/templates/ruby/Gemfile.lock
|
230
246
|
- lib/zillabyte/cli/templates/ruby/simple_function.rb
|
231
247
|
- lib/zillabyte/cli/templates/ruby/zillabyte.conf.yaml
|
232
248
|
- lib/zillabyte/cli/version.rb
|
@@ -239,6 +255,7 @@ files:
|
|
239
255
|
- lib/zillabyte/helpers.rb
|
240
256
|
- lib/zillabyte/queries.rb
|
241
257
|
- lib/zillabyte-cli/version.rb
|
258
|
+
- lib/zillabyte-cli/version.rb~
|
242
259
|
- lib/zillabyte-cli.rb
|
243
260
|
- LICENSE
|
244
261
|
- README.md
|
data/lib/zillabyte/cli/logs.rb
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
require "zillabyte/cli/base"
|
2
|
-
require "pty"
|
3
|
-
require 'colorize'
|
4
|
-
|
5
|
-
# manage custom logs
|
6
|
-
#
|
7
|
-
class Zillabyte::Command::Logs < Zillabyte::Command::Base
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# logs:show FLOW_ID [OPERATION]
|
14
|
-
#
|
15
|
-
# shows the logs
|
16
|
-
#
|
17
|
-
# -t, --tail # continuously watches for new results
|
18
|
-
# -v, --verbose LEVEL # sets the verbosity (error, info, debug) (default: info)
|
19
|
-
#
|
20
|
-
def show
|
21
|
-
|
22
|
-
flow_id = options[:flow] || shift_argument
|
23
|
-
operation_id = options[:operation] || shift_argument || '_ALL_'
|
24
|
-
tail = options[:tail]
|
25
|
-
priority = options[:verbose] || 'debug'
|
26
|
-
carry_settings = {
|
27
|
-
:priority => priority
|
28
|
-
}
|
29
|
-
api_options = {}
|
30
|
-
|
31
|
-
error "no id given" if flow_id.nil?
|
32
|
-
|
33
|
-
begin
|
34
|
-
|
35
|
-
res = self.api.logs.get(flow_id, operation_id, api_options)
|
36
|
-
|
37
|
-
carry_settings = show_log_output(res, carry_settings)
|
38
|
-
api_options[:since] = carry_settings[:since]
|
39
|
-
|
40
|
-
if (tail)
|
41
|
-
sleep(5) # HACK
|
42
|
-
end
|
43
|
-
end while(tail)
|
44
|
-
|
45
|
-
end
|
46
|
-
alias_command "logs", "logs:show"
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def show_log_output(lines, settings = {})
|
57
|
-
|
58
|
-
@colors ||= [:green, :yellow, :magenta, :cyan, :light_black, :light_green, :light_yellow, :light_blue, :light_magenta, :light_cyan]
|
59
|
-
|
60
|
-
max_category_size = 0
|
61
|
-
all_lines = []
|
62
|
-
|
63
|
-
lines.each_pair do |operation, lines|
|
64
|
-
settings[operation] ||= {}
|
65
|
-
settings[operation][:color] ||= @colors.shift
|
66
|
-
lines.each do |line_h|
|
67
|
-
|
68
|
-
line = line_h['line']
|
69
|
-
priority = line_h['priority']
|
70
|
-
date = line_h['date']
|
71
|
-
|
72
|
-
all_lines << {
|
73
|
-
:line => line,
|
74
|
-
:category => operation,
|
75
|
-
:priority => priority,
|
76
|
-
:color => settings[operation][:color],
|
77
|
-
:date => date
|
78
|
-
}
|
79
|
-
max_category_size = [max_category_size, operation.size].max
|
80
|
-
|
81
|
-
if settings[:since]
|
82
|
-
settings[:since] = [date, settings[:since]].max
|
83
|
-
else
|
84
|
-
settings[:since] = date
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
all_lines.sort! do |a,b|
|
92
|
-
a[:date] <=> b[:date]
|
93
|
-
end
|
94
|
-
|
95
|
-
requested_priority = settings[:priority]
|
96
|
-
|
97
|
-
all_lines.each do |h|
|
98
|
-
color = h[:color]
|
99
|
-
|
100
|
-
case h[:priority]
|
101
|
-
when 'error'
|
102
|
-
color = :red if h[:priority] == 'error'
|
103
|
-
when 'info'
|
104
|
-
next if ['error'].member?(requested_priority)
|
105
|
-
when 'system'
|
106
|
-
when 'debug'
|
107
|
-
next if ['info', 'error'].member?(requested_priority)
|
108
|
-
end
|
109
|
-
|
110
|
-
display "#{h[:category].rjust(max_category_size)} #{h[:priority].rjust(6)} - #{h[:line]}".colorize(color)
|
111
|
-
end
|
112
|
-
|
113
|
-
settings
|
114
|
-
end
|
115
|
-
|
116
|
-
|
117
|
-
end
|