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.
@@ -1,5 +1,5 @@
1
1
  module Zillabyte
2
2
  module CLI
3
- VERSION = "0.0.11"
3
+ VERSION = "0.0.12"
4
4
  end
5
5
  end
@@ -0,0 +1,5 @@
1
+ module Zillabyte
2
+ module CLI
3
+ VERSION = "0.0.11"
4
+ end
5
+ end
@@ -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
 
@@ -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
 
@@ -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
- end
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
- if type == "sink"
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 # a JSON array of column types
126
- # --public # Make the relation public
127
- # --file # A data file
128
- # --type # type of data file [csv (default), xlsx]
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] || shift_argument || nil
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 = JSON.parse(options[:schema]) if options[:schema]
139
- is_public = options[:public] || false
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
- rows = sanity_check_file(file,type,relation)
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 #{id} appended"
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
- valid_types=["STRING", "NUMERIC", "FLOAT"]
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((cname[0].downcase == "v" and cname[1...-1].respond_to?("to_i") and cname[1...-1].to_i >= 0) or meta_names.member?(cname.downcase))
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 << {cname => ctype}
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
- {:schema => schema, :public => is_public}
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 != dataset['columns'].size
297
- puts "relation expect #{dataset['columns'].size} column(s). Found a row with #{row.size}::\n #{row}"
298
- else
299
- rows << row
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.values["html"].indexOf("hello world") !== -1) {
13
- controller.emit("has_hello_world",{"url":tuple.values["url"]});
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.values["html"]):
11
- controller.emit("has_hello_world",{"url":tup.values["url"]})
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['v0']
23
- html = tuple['v1']
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') or html.include?('world')
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
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency "chronic", "~> 0.10"
35
35
  spec.add_dependency "ascii_charts", "~> 0.9.1"
36
36
  spec.add_dependency "indentation", "~> 0.1"
37
+ spec.add_dependency "aws-sdk", "~> 1.33.0"
37
38
  end
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.11
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-15 00:00:00.000000000 Z
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
@@ -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