zillabyte-cli 0.0.11 → 0.0.12
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/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
|