zillabyte-cli 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YTcwMDBjODg0OTEyY2YxMzYzMjU4OTgwNmVhYTllOGRiZjEzZTZjYw==
4
+ MDRiNDYwNjlhZDQwYjc4NGNiNDZlNDkzYjE2NGNjZDhjYzMyNTdlMA==
5
5
  data.tar.gz: !binary |-
6
- YzYwNWU4ZThlMDM0OWMxOTA2OTFkYjEyZGEyOTE4NTcwODg4ZTA0Ng==
7
- SHA512:
6
+ YTUzMjI0MGQxYTkyZjE4ODQ0MDU4ODg3MTBkNWM0ZDliNGEwNWQ2NA==
7
+ !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- OGQzMDYyZjg4ZDkwODVlOTNlM2ZkNTc4MmZkMjJlMGY0MGIxMGM3ZDRkZTM4
10
- NzQyODU3MjkwN2NjMDM4YTRjZTAxYjliMmJkMjZmZTk0MWI3NGM1ZGM3MTZk
11
- YTQ4OWE2OTM4MmZjOWYzMDQ4ZTEzMTRmNDQ4NGU4ZjM3MmFhMjE=
9
+ MmE4Y2RhZWY0ODE2ZTQ2MWIzMTgxMjk1Yzg4NzU0NzhhZWE2YzE2MWJhYzU5
10
+ ZTJmZjE0NGJmNTBlMjBhOTQ2YTVjNTZlNGQ1ODMzOGMwYTU4N2M4MjhiZTIy
11
+ MzlkYjc2ZmU2OTM2MjJlMTU1NTQxMDRiMzRmMTYwYTY2YTVhY2U=
12
12
  data.tar.gz: !binary |-
13
- ZWI1YWZhYzk3MzMzNjQxOTVhYWEyY2ZlNjQ4MTZiMTM3MjIxN2Y3NGViNmEy
14
- NWI0MDU0NDhhYzQ2NjE3YzNiOTgzYTNkYTg0YWUxNjEwOGFhM2M4ZDk1ZmRj
15
- YjYzMTgzMTAyMGE2YTQ5NzRmNmQ5NzYxMTJkODYyMTVmNGUxZTM=
13
+ ZjAxMzlmOTEyYjI4ZTk2MmU2MWE1NThjMTQ5ODg4MmUxMjc1NDMzMmYxMjYz
14
+ ZmFlYWEyZjFlNTFmOGIwYTBhZDVkZWI5ZjZkNjI5NDBiMWExOGIzNDY3MTk0
15
+ ZGY5Yzc4Y2FjMTZhNDY0NTg2M2Q3ZTIwZjg1ZjA3MzA3Y2Y1YmQ=
@@ -1,5 +1,5 @@
1
1
  module Zillabyte
2
2
  module CLI
3
- VERSION = "0.0.15"
3
+ VERSION = "0.0.16"
4
4
  end
5
5
  end
data/lib/zillabyte/api.rb CHANGED
@@ -62,13 +62,70 @@ class Zillabyte::API
62
62
 
63
63
  def request(params, &block)
64
64
  begin
65
- # The @connection object handles connections to api.zillabyte.com via Excon, this sends a command to the Rails api code
66
- # with parameters in params (one of which contains the path to the method to be run in the form of a url, e.g. if the
67
- # :path parameter is set to /functions/#{id}?tar=1, then the show method in functions_controller.rb will be automatically
68
- # called...it will have it's own set of parameters which correspond to the items in the query string).
69
- response = @connection.request(params, &block)
65
+
66
+ # If a block is given, then we assume we're streaming (i.e. for logs)
67
+ if block_given?
68
+
69
+ # We tell excon to emit a chunk ever 50 bytes. This is an excon thing, doesn't
70
+ # affect the network IO chunk size
71
+ params[:chunk_size] = 50;
72
+ last_string = ""
73
+
74
+ # Executed on each chunk excon bubbles up
75
+ params[:response_block] = lambda do |chunk, remaining_bytes, total_bytes|
76
+
77
+ # assume single-line json, split by '\n'
78
+ last_string += chunk
79
+ ary = last_string.split("\n", -1)
80
+
81
+ # Are we at the end of a JSON record?
82
+ if ary.size > 1
83
+ last_string = ary.last + (if last_string.end_with?("\n") then "\n" else "" end)
84
+ json_records = ary[0..-2]
85
+ json_records.each do |json_record|
86
+
87
+ # Blank?
88
+ next if json_record.strip == ""
89
+
90
+ if json_record.start_with?("HTTP/1.1 50")
91
+ puts "internal server error (code 500)"
92
+ exit(1)
93
+ end
94
+
95
+ # Offer all the json records to the listening block
96
+ begin
97
+ block.call(JSON.parse(json_record))
98
+ rescue JSON::ParserError => e
99
+ error "unable to parse logs"
100
+ exit(1)
101
+ end
102
+
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ # Execute the request
109
+ response = @connection.request(params)
110
+
70
111
  rescue Excon::Errors::HTTPStatusError => error
71
- @progress.error "internal server error" if @progress
112
+ if @progress
113
+
114
+ # Show helpful error message
115
+ if error.response.body
116
+ begin
117
+ hash = JSON.parse(error.response.body)
118
+ if hash['error_message']
119
+ @progress.error hash['error_message']
120
+ end
121
+ rescue JSON::ParserError => e
122
+ # Trickle to generic message below
123
+ end
124
+ end
125
+
126
+ @progress.error "internal server error"
127
+
128
+ end
72
129
  raise error
73
130
  end
74
131
 
@@ -5,17 +5,17 @@ class Zillabyte::API::Logs < Zillabyte::API::Base
5
5
 
6
6
 
7
7
  # GET /flows/ID/logs
8
- def get(flow_id, operation_id, options = {})
8
+ def get(flow_id, operation_id, options = {}, &block)
9
9
 
10
10
  options = {
11
11
  }.merge(options)
12
12
 
13
- res = @api.request(
13
+ res = @api.request({
14
14
  :expects => 200,
15
15
  :method => :get,
16
- :path => "/flows/#{flow_id}/logs/#{operation_id}",
16
+ :path => "/flows/#{flow_id}/logs/#{operation_id}/stream",
17
17
  :body => options.to_json
18
- )
18
+ }, &block)
19
19
 
20
20
  res.body
21
21
 
@@ -23,6 +23,23 @@ class Zillabyte::API::Logs < Zillabyte::API::Base
23
23
 
24
24
 
25
25
 
26
+ def get_startup(flow_id, operation_id, options = {}, &block)
27
+
28
+ options = {
29
+ }.merge(options)
30
+
31
+ res = @api.request({
32
+ :expects => 200,
33
+ :method => :get,
34
+ :path => "/flows/#{flow_id}/logs/#{operation_id}/startup",
35
+ :body => options.to_json
36
+ }, &block)
37
+
38
+ res.body
39
+
40
+ end
41
+
42
+
26
43
 
27
44
 
28
45
  end
@@ -63,23 +63,22 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
63
63
  end
64
64
 
65
65
  display "Starting up your flow...please wait..."
66
- previous_logs = {}
67
- while true
68
- all_logs = api.logs.get(res['id'], "_ALL_", {:push => true})
69
- all_logs.each_pair do |op, logs|
70
- next if logs.length == 0
71
- difference = previous_logs[op] ? logs - previous_logs[op] : logs
72
- difference.each do |log|
73
- if ["start_up", "error"].include?(log["category"])
74
- display log["line"]
75
- end
76
- exit(0) if log["line"].downcase.include?("flow deployed")
77
- end
78
- previous_logs[op] = logs
79
- end
80
- sleep(0.5)
81
- end
66
+ sleep(2) # wait for kill command
82
67
 
68
+ lf = LogFormatter::Startup.new
69
+ api.logs.get_startup(res['id'], "_ALL_", {:push => true}) do |hash|
70
+
71
+ # Error?
72
+ error hash['error_message'] if hash['error']
73
+
74
+ # Print it
75
+ lf.print_log_line(hash)
76
+
77
+ # Exit when we get the 'done' message
78
+ # exit(0) if (hash['line'] || '').downcase.include?("flow deployed")
79
+
80
+ end
81
+
83
82
  end
84
83
  alias_command "push", "flows:push"
85
84
 
@@ -87,7 +86,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
87
86
 
88
87
  # flows:pull ID DIR
89
88
  #
90
- # pulls a flow source to a directory. The target directory must be empty
89
+ # pulls a flow source to a directory.
91
90
  #
92
91
  # --force # pulls even if the directory exists
93
92
  #
@@ -227,14 +226,12 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
227
226
  #
228
227
  # streams logs from the distributed workers
229
228
  #
230
- # -t, --tail # continuously watches for new results
231
229
  # -v, --verbose LEVEL # sets the verbosity (error, info, debug) (default: info)
232
230
  #
233
231
  def logs
234
232
 
235
233
  flow_id = options[:flow] || shift_argument
236
234
  operation_id = options[:operation] || shift_argument || '_ALL_'
237
- tail = options[:tail]
238
235
  category = options[:verbose] || '_ALL_'
239
236
  carry_settings = {
240
237
  :category => category
@@ -247,17 +244,13 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
247
244
  end
248
245
 
249
246
  display "Retrieving logs for flow ##{flow_id}...please wait..."
250
- begin
247
+ lf = LogFormatter::Operation.new
248
+ self.api.logs.get(flow_id, operation_id, api_options) do |line|
251
249
 
252
- res = self.api.logs.get(flow_id, operation_id, api_options)
253
-
254
- carry_settings = show_log_output(res, carry_settings)
255
- api_options[:since] = carry_settings[:since]
250
+ error line['error_message'] if line['error']
251
+ lf.print_log_line(line)
256
252
 
257
- if (tail)
258
- sleep(5) # HACK
259
- end
260
- end while(tail)
253
+ end
261
254
 
262
255
  end
263
256
  alias_command "logs", "flows:logs"
@@ -307,7 +300,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
307
300
  end
308
301
 
309
302
 
310
- # flows:test [TEST_DATASET_ID]
303
+ # flows:test
311
304
  #
312
305
  # tests a local flow with sample data
313
306
  #
@@ -349,6 +342,14 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
349
342
  write_stream.flush
350
343
  end
351
344
 
345
+ def truncate_message(msg)
346
+ return msg if(!msg.instance_of?(String))
347
+ t_length = 50 # truncates entries to this length
348
+ m_length = msg.length
349
+ msg_out = m_length > t_length ? msg[0..t_length-3]+"..." : msg
350
+ msg_out
351
+ end
352
+
352
353
  def handshake(write_stream, read_stream, node, color)
353
354
  begin
354
355
  write_message write_stream, "{\"pidDir\": \"/tmp\"}\n"
@@ -361,7 +362,6 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
361
362
 
362
363
 
363
364
  # INIT
364
- test_data = options[:test_data] || shift_argument
365
365
  dir = options[:dir] || Dir.pwd
366
366
 
367
367
  meta = Zillabyte::API::Flows.get_rich_meta_info_from_script(dir, self, {:test => true})
@@ -397,10 +397,10 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
397
397
  display "#{name} - #{msg}".colorize(override_color || color)
398
398
  end
399
399
 
400
- # A Spout?
401
- if type == "spout"
400
+ # A Source?
401
+ if type == "source"
402
402
 
403
- # A spout from relation?
403
+ # A source from relation?
404
404
  if node['matches'] or node["relation"]
405
405
  matches = node['matches'] || (node["relation"]["query"])
406
406
  op_display.call "Grabbing remote data"
@@ -426,6 +426,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
426
426
  end
427
427
  end
428
428
  read_msg = {"tuple" => values, "meta" => meta, "column_aliases" => column_aliases}.to_json
429
+ values = Hash[values.map{|k, v| [truncate_message(k), truncate_message(v)]}]
429
430
  op_display.call "emit tuple: #{values} #{meta}"
430
431
  stream_messages[default_stream] ||= []
431
432
  stream_messages[default_stream] << read_msg
@@ -436,7 +437,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
436
437
 
437
438
  else
438
439
 
439
- # A regular spout..
440
+ # A regular source..
440
441
  stream_messages[default_stream] ||= []
441
442
  batches.times do |i|
442
443
  stream_messages[default_stream] << "{\"command\": \"next\"}\n"
@@ -580,9 +581,10 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
580
581
  # Make it human-understable
581
582
  write_json = JSON.parse(write_msg)
582
583
  if write_json['tuple']
583
- op_display.call "receiving: #{write_json['tuple']}"
584
+ display_hash = Hash[write_json['tuple'].map{|k, v| [truncate_message(k), truncate_message(v)]}]
585
+ op_display.call "receiving: #{display_hash}"
584
586
  elsif write_json['command'] == 'next'
585
- op_display.call "starting next spout batch"
587
+ op_display.call "starting next source batch"
586
588
  else
587
589
  puts write_json
588
590
  end
@@ -628,7 +630,8 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
628
630
  emit_stream = obj['stream'] || default_stream
629
631
  stream_messages[emit_stream] ||= []
630
632
  stream_messages[emit_stream] << next_msg.to_json
631
- op_display.call "emitted: #{obj['tuple']} to #{emit_stream}"
633
+ display_hash = Hash[obj['tuple'].map{|k, v| [truncate_message(k), truncate_message(v)]}]
634
+ op_display.call "emitted: #{display_hash} to #{emit_stream}"
632
635
  elsif obj['command'] == 'log'
633
636
  op_display.call "log: #{obj['msg']}"
634
637
  else
@@ -671,7 +674,9 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
671
674
  # We need to check here to see if we need to turn on multistream mode.
672
675
  # Note that we still need the redundant checks above, in case the user
673
676
  # didn't honor the emits contract.
674
- split_branches = true if node["emits"].size() > 1
677
+ if node["emits"] && node["emits"].size() > 1
678
+ split_branches = true
679
+ end
675
680
  end
676
681
  end
677
682
 
@@ -709,7 +714,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
709
714
  # runs a local flow with live data
710
715
  #
711
716
  # --config CONFIG_FILE # use the given config file
712
- #
717
+ # HIDDEN:
713
718
  def live_run
714
719
 
715
720
  name = options[:name] || shift_argument
@@ -735,7 +740,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
735
740
  # outputs the info for the flow in the dir.
736
741
  #
737
742
  # --pretty # Pretty prints the info output
738
- #
743
+ #
739
744
  def info
740
745
  info_file = SecureRandom.uuid
741
746
  cmd = command("--info --file #{info_file}")
@@ -785,71 +790,6 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
785
790
 
786
791
  private
787
792
 
788
- def show_log_output(lines, settings = {})
789
-
790
- max_category_size = 0
791
- settings["start_up"] = :green
792
- settings["kill"] = :yellow
793
- settings["ipc"] = :cyan
794
- settings["error"] = :red
795
- settings["system"] = :white
796
- settings["run"] = :magenta
797
- all_lines = []
798
-
799
- lines.each_pair do |operation, lines|
800
- lines.each do |line_h|
801
-
802
- line = line_h['line']
803
- category = line_h['category']
804
- date = line_h['date']
805
-
806
- all_lines << {
807
- :line => line,
808
- :category => category,
809
- :color => settings[category],
810
- :date => date
811
- }
812
- max_category_size = [max_category_size, category.size].max
813
-
814
- if settings[:since]
815
- settings[:since] = [date, settings[:since]].max
816
- else
817
- settings[:since] = date
818
- end
819
-
820
- end
821
-
822
- end
823
-
824
- all_lines.sort! do |a,b|
825
- a[:date] <=> b[:date]
826
- end
827
-
828
- requested_category = settings[:category]
829
-
830
- all_lines.each do |h|
831
- color = h[:color]
832
-
833
- case h[:category]
834
- when nil
835
- next
836
- when 'start_up'
837
- next if ['kill', 'run', 'ipc'].member?(requested_category)
838
- when 'run'
839
- next if ['kill', 'start_up', 'ipc'].member?(requested_category)
840
- when 'ipc'
841
- next if ['kill', 'start_up', 'run'].member?(requested_category)
842
- when 'kill'
843
- next if ['start_up', 'run', 'ipc'].member?(requested_category)
844
- end
845
-
846
- display "#{h[:category].rjust(max_category_size)} - #{h[:date]} UTC - #{h[:line]}".colorize(color)
847
- end
848
-
849
- settings
850
- end
851
-
852
-
853
793
 
854
794
 
855
795
  def command(arg="--execute_live", ignore_stderr = false)
@@ -8,8 +8,16 @@ class Zillabyte::Command::Help < Zillabyte::Command::Base
8
8
 
9
9
 
10
10
  def index(*direct_args)
11
+
11
12
  if command = args.shift || direct_args.shift
12
- help_for_command(command)
13
+ if command == "aliases"
14
+ puts
15
+ puts "Useful aliases: "
16
+ puts
17
+ summary_for_aliases(Zillabyte::Command.command_aliases)
18
+ else
19
+ help_for_command(command)
20
+ end
13
21
  else
14
22
  help_for_root
15
23
  end
@@ -18,6 +26,7 @@ class Zillabyte::Command::Help < Zillabyte::Command::Base
18
26
  alias_command "-h", "help"
19
27
  alias_command "--help", "help"
20
28
 
29
+
21
30
  private
22
31
 
23
32
  def commands_for_namespace(name)
@@ -74,13 +83,14 @@ private
74
83
  end
75
84
 
76
85
  def summary_for_aliases(command_aliases)
77
- a_size = longest(command_aliases.map { |al,al_to| al })
78
- a_to_size = longest(command_aliases.map { |al,al_to| al_to })
79
- command_aliases.sort_by{|k,v| v}.each do |command_alias, alias_to|
86
+ used_aliases = command_aliases.select{|c,a| !c.include?("-") and !c.include?(":") and !skip_command?(commands[a])}
87
+ a_size = longest(used_aliases.map { |al,al_to| al }) + 2
88
+ a_to_size = longest(used_aliases.map { |al,al_to| al_to }) + 2
89
+ used_aliases.sort_by{|k,v| v}.each do |command_alias, alias_to|
80
90
  if command_alias.include?("-") or command_alias.include?(":")
81
91
  next #skip -h, -help and live-run etc.
82
92
  end
83
- puts command_alias.ljust(a_size) + " --> " + alias_to.ljust(a_to_size + 2) + " # " + commands[alias_to][:summary]
93
+ puts command_alias.ljust(a_size) + " --> " + alias_to.ljust(a_to_size) + " # " + commands[alias_to][:summary]
84
94
  end
85
95
  end
86
96
 
@@ -95,11 +105,9 @@ private
95
105
  puts
96
106
  summary_for_namespaces(additional_namespaces)
97
107
  puts
98
- puts "Useful aliases: "
99
- puts
100
- summary_for_aliases(Zillabyte::Command.command_aliases)
108
+ puts "Type \"zillabyte help aliases\" for shortcuts to common commands."
101
109
  puts
102
- puts "For help getting started, visit http://docs.zillabyte.com."
110
+ puts "Visit our documentation for more help: http://docs.zillabyte.com. "
103
111
  puts
104
112
  end
105
113
 
@@ -107,7 +115,7 @@ private
107
115
  namespace_commands = commands_for_namespace(name)
108
116
 
109
117
  unless namespace_commands.empty?
110
- size = longest(namespace_commands.map { |c| c[:banner] })
118
+ size = longest(namespace_commands.select{|c| !skip_command?(c)}.map { |c| c[:banner] })
111
119
  namespace_commands.sort_by { |c| c[:banner].to_s }.each do |command|
112
120
  next if skip_command?(command)
113
121
  command[:summary] ||= legacy_help_for_command(command[:command])
@@ -141,10 +149,10 @@ private
141
149
  end
142
150
 
143
151
  if !namespace_commands.empty?
144
- puts "Additional commands, type \"zillabyte help COMMAND\" for more details:"
145
152
  puts
146
153
  help_for_namespace(name)
147
154
  puts
155
+ puts "To see additional help for each of the commands, type \"zillabyte help COMMAND\"."
148
156
  elsif command.nil?
149
157
  error "#{name} is not a zillabyte command. See `zillabyte help`."
150
158
  end
@@ -0,0 +1,103 @@
1
+ class LogFormatter
2
+
3
+ ########################################################
4
+ ## Base / Generic ######################################
5
+ ########################################################
6
+
7
+ class Base
8
+
9
+ def initialize
10
+ @all_colors ||= [:green, :yellow, :magenta, :cyan, :light_black, :light_green, :light_yellow, :light_blue, :light_magenta, :light_cyan]
11
+ @color_map = {
12
+ 'flow' => :white
13
+ }
14
+ end
15
+
16
+ def print_log_line(hash)
17
+
18
+ # Dno't show heartbeats
19
+ return if hash['heartbeat']
20
+
21
+ # Init
22
+ line = hash['line']
23
+ category = hash['category']
24
+ date = hash['date']
25
+ name = hash['name']
26
+ index = hash['index']
27
+
28
+ # Don't display 'hidden' lines
29
+ if category == 'hidden'
30
+
31
+ handle_hidden(name, index, category, date, line);
32
+
33
+ else
34
+
35
+ # Print it out
36
+ display(name, index, category, date, line)
37
+
38
+ end
39
+
40
+
41
+ end
42
+
43
+
44
+ protected
45
+
46
+ def handle_hidden(operation_name, operation_index, category, date, line)
47
+ end
48
+
49
+ def display(operation_name, operation_index, category, date, line)
50
+ puts "#{get_name(operation_name, operation_index).rjust(9).colorize(color_for(operation_name))} - #{line}"
51
+ end
52
+
53
+
54
+ def get_name(operation_name, operation_index)
55
+ if operation_index and operation_index != ""
56
+ return "#{operation_name}.#{operation_index}"
57
+ else
58
+ return operation_name
59
+ end
60
+ end
61
+
62
+ def color_for(operation_name)
63
+ @color_map[operation_name] ||= @all_colors[ @color_map.size % @all_colors.size ]
64
+ @color_map[operation_name]
65
+ end
66
+
67
+ end
68
+
69
+
70
+ ########################################################
71
+ ## Startup #############################################
72
+ ########################################################
73
+
74
+ class Startup < Base
75
+
76
+ def display(operation_name, operation_index, category, date, line)
77
+ puts "#{get_name(operation_name, operation_index).rjust(15).colorize(color_for(operation_name))} : #{line}"
78
+ end
79
+
80
+ def handle_hidden(operation_name, operation_index, category, date, line)
81
+ case line
82
+ when 'REGISTER_FLOW_DEPLOYED', 'REGISTER_FLOW_TIMEOUT'
83
+ # done reading the logs
84
+ exit(0)
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+
91
+ ########################################################
92
+ ## Operation Colorized #################################
93
+ ########################################################
94
+
95
+ class Operation < Base
96
+ # TODO: color'ify each operation
97
+ end
98
+
99
+
100
+
101
+ end
102
+
103
+
@@ -163,9 +163,9 @@ class Zillabyte::Command::Query < Zillabyte::Command::Base
163
163
  alias_command "sql", "query:sql"
164
164
 
165
165
 
166
- # query:pull:s3 QUERY S3_KEY S3_SECRET S3_BUCKET S3_FILE_PATH
166
+ # query:pull:s3 QUERY S3_KEY S3_SECRET S3_BUCKET s3_FILE_KEY
167
167
  #
168
- # pulls query data to S3_BUCKET/FILE_PATH/part***.gz
168
+ # pulls query data to S3_BUCKET/FILE_KEY/part***.gz
169
169
  #
170
170
  def pull_to_s3
171
171
 
@@ -175,14 +175,14 @@ class Zillabyte::Command::Query < Zillabyte::Command::Base
175
175
  user_s3_access_key = options[:s3_access_key] || shift_argument
176
176
  user_s3_secret = options[:s3_secret] || shift_argument
177
177
  user_s3_bucket = options[:s3_bucket] || shift_argument
178
- user_s3_file_path = options[:s3_file_path] || shift_argument
178
+ user_s3_file_key = options[:s3_file_key] || shift_argument
179
179
  error "no s3 access key provided" if user_s3_access_key.nil?
180
180
  error "no s3 secret provided" if user_s3_secret.nil?
181
181
  error "no s3 bucket provided" if user_s3_bucket.nil?
182
- error "no s3 file path specified" if user_s3_file_path.nil?
182
+ error "no s3 file path specified" if user_s3_file_key.nil?
183
183
 
184
184
  s3_params = {:s3_access_key => user_s3_access_key, :s3_secret => user_s3_secret,
185
- :s3_bucket => user_s3_bucket, :s3_object_key => user_s3_file_path}
185
+ :s3_bucket => user_s3_bucket, :s3_file_key => user_s3_file_key}
186
186
 
187
187
  res = self.api.queries.pull_to_s3(query, s3_params)
188
188
  display "downloading query results to s3://#{res["s3_bucket"]}/#{res["s3_file_key"]}/"
@@ -82,7 +82,7 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
82
82
  # --schema SCHEMA # Column names and types in the format "field_1:type_1,field_2:type_2,..."
83
83
  # --public SCOPE # Make the relation public
84
84
  # --file FILE # A data file
85
- # --type FILE_TYPE # type of data file [csv (default), xlsx]
85
+ # --type TYPE # File format type, defaults to csv
86
86
  # --description DESCRIPTION # Description of relation contents
87
87
  # --aliases ALIASES # Relation name aliases in the format "alias_1,alias_2,..."
88
88
  #
@@ -122,7 +122,7 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
122
122
  #
123
123
  # adds data to an existing relation
124
124
  #
125
- # --type TYPE # interpret file as type [csv, xlsx]
125
+ # --type TYPE # File format type, defaults to csv
126
126
  #
127
127
  def append
128
128
 
@@ -149,7 +149,7 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
149
149
  #
150
150
  # pulls relation data into OUTPUT.gz
151
151
  #
152
- # --cycle_id [cycle_id] # if the relation is associated with a flow, cycle_id indicates the flow cycle to retrieve data for (defaults to the last cycle)
152
+ # --cycle_id [cycle_id] # retrieve data generated for that cycle, only if this relation is associated with a flow. (defaults to the last cycle)
153
153
  #
154
154
  def pull
155
155
 
@@ -157,7 +157,7 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
157
157
  file = options[:file] || shift_argument
158
158
  error "no id given" if id.nil?
159
159
  error "no output file given" if file.nil?
160
- file = file+".gz"
160
+ file = "#{file}.gz" unless File.extname(file) == ".gz"
161
161
 
162
162
  res = self.api.data.pull(id, options)
163
163
  if(res["uri"])
@@ -194,11 +194,11 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
194
194
  end
195
195
  alias_command "rl:pull", "relations:pull"
196
196
 
197
- # relations:pull:s3 ID S3_KEY S3_SECRET S3_BUCKET S3_FILE_PATH
197
+ # relations:pull:s3 ID S3_KEY S3_SECRET S3_BUCKET s3_FILE_KEY
198
198
  #
199
- # pulls relation data to S3_BUCKET/FILE_PATH/part***.gz
199
+ # pulls relation data to S3_BUCKET/FILE_KEY/part***.gz
200
200
  #
201
- # --cycle_id [cycle_id] # if the relation is associated with a flow, cycle_id indicates the flow cycle to retrieve data for (defaults to the last cycle)
201
+ # --cycle_id [cycle_id] # retrieve data generated for that cycle, only if this relation is associated with a flow. (defaults to the last cycle)
202
202
  #
203
203
  def pull_to_s3
204
204
 
@@ -208,14 +208,14 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
208
208
  user_s3_access_key = options[:s3_access_key] || shift_argument
209
209
  user_s3_secret = options[:s3_secret] || shift_argument
210
210
  user_s3_bucket = options[:s3_bucket] || shift_argument
211
- user_s3_file_path = options[:s3_file_path] || shift_argument
211
+ user_s3_file_key = options[:s3_file_key] || shift_argument
212
212
  error "no s3 access key provided" if user_s3_access_key.nil?
213
213
  error "no s3 secret provided" if user_s3_secret.nil?
214
214
  error "no s3 bucket provided" if user_s3_bucket.nil?
215
- error "no s3 file path specified" if user_s3_file_path.nil?
215
+ error "no s3 file path specified" if user_s3_file_key.nil?
216
216
 
217
217
  s3_params = {:s3_access_key => user_s3_access_key, :s3_secret => user_s3_secret,
218
- :s3_bucket => user_s3_bucket, :s3_object_key => user_s3_file_path}
218
+ :s3_bucket => user_s3_bucket, :s3_file_key => user_s3_file_key}
219
219
  s3_params[:cycle_id] = options[:cycle_id] if options[:cycle_id]
220
220
 
221
221
  res = self.api.data.pull_to_s3(id, s3_params)
@@ -229,9 +229,9 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
229
229
 
230
230
  # relations:show ID
231
231
  #
232
- # shows raw data in a relation. run 'queries' for more elaborate functionality
232
+ # shows a sample of the data in a relation. see 'zillabyte queries' for more elaborate functionality
233
233
  #
234
- # --cycle_id [cycle_id] # if the relation is associated with a flow, cycle_id indicates the flow cycle to retrieve data for (defaults to the last cycle)
234
+ # --cycle_id [cycle_id] # retrieve data generated for that cycle, only if this relation is associated with a flow. (defaults to the last cycle)
235
235
  # --no_truncation # don't truncate long strings
236
236
  #
237
237
  def show
@@ -1,22 +1,29 @@
1
1
  require 'zillabyte'
2
2
 
3
- Zillabyte.simple_function do |fn|
3
+ Zillabyte.simple_function do
4
+
5
+ # This specifies the function's name and is mandatory.
6
+ name "simple_function"
4
7
 
5
8
  # This directive instructs zillabyte to give your function every
6
9
  # web page in our known universe. Your function will have access
7
10
  # to two fields: URL and HTML
8
- fn.matches "select * from web_pages"
11
+ matches "select * from web_pages"
9
12
 
10
13
  # This directive tells Zillabyte what kind of data your function
11
14
  # produces. In this case, we're saying we will emit a tuple that
12
15
  # is one-column wide and contains the field 'URL'
13
- fn.emits [["has_hello_world", [{"URL"=>:string}]]]
16
+ emits [
17
+ [
18
+ "has_hello_world", [ {"URL"=>:string} ]
19
+ ]
20
+ ]
14
21
 
15
22
 
16
23
  # This is the heart of your algorithm. It's processed on every
17
24
  # web page. This algorithm is run in parallel on possibly hundreds
18
25
  # of machines.
19
- fn.execute do |controller, tuple|
26
+ execute do |tuple|
20
27
 
21
28
  # get the fields
22
29
  url = tuple['url']
@@ -27,13 +34,9 @@ Zillabyte.simple_function do |fn|
27
34
  # instead of
28
35
  # if html.include?('hello world')
29
36
  if html.include?('hello world')
30
- controller.emit("has_hello_world", "URL" => url)
37
+ emit("has_hello_world", "URL" => url)
31
38
  end
32
39
 
33
40
  end
34
41
 
35
42
  end
36
-
37
-
38
-
39
-
@@ -28,6 +28,8 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency "excon", "~> 0.31"
29
29
  spec.add_dependency "terminal-table", "~> 1.4"
30
30
  spec.add_dependency "activesupport", "~> 3.2.11"
31
+ spec.add_dependency "multi_json", "~> 1.0"
32
+ spec.add_dependency "mini_portile", "~> 0.5.0"
31
33
 
32
34
  spec.add_dependency "bundler", "~> 1.3"
33
35
  spec.add_dependency "colorize", "~> 0.6"
@@ -36,4 +38,5 @@ Gem::Specification.new do |spec|
36
38
  spec.add_dependency "indentation", "~> 0.1"
37
39
  spec.add_dependency "aws-sdk", "~> 1.33.0"
38
40
  spec.add_dependency "time_difference"
41
+
39
42
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zillabyte-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - zillabyte
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-25 00:00:00.000000000 Z
11
+ date: 2014-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -94,6 +94,34 @@ dependencies:
94
94
  - - ~>
95
95
  - !ruby/object:Gem::Version
96
96
  version: 3.2.11
97
+ - !ruby/object:Gem::Dependency
98
+ name: multi_json
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: mini_portile
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 0.5.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: 0.5.0
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: bundler
99
127
  requirement: !ruby/object:Gem::Requirement
@@ -201,7 +229,6 @@ extensions: []
201
229
  extra_rdoc_files: []
202
230
  files:
203
231
  - bin/zillabyte
204
- - lib/zillabyte/#api.rb#
205
232
  - lib/zillabyte/api/base.rb
206
233
  - lib/zillabyte/api/data.rb
207
234
  - lib/zillabyte/api/flows.rb
@@ -215,7 +242,6 @@ files:
215
242
  - lib/zillabyte/api/zillalogs.rb
216
243
  - lib/zillabyte/api.rb
217
244
  - lib/zillabyte/auth.rb
218
- - lib/zillabyte/cli/#logs.rb#
219
245
  - lib/zillabyte/cli/auth.rb
220
246
  - lib/zillabyte/cli/base.rb
221
247
  - lib/zillabyte/cli/config.rb
@@ -224,12 +250,12 @@ files:
224
250
  - lib/zillabyte/cli/help.rb
225
251
  - lib/zillabyte/cli/helpers/data_schema_builder.rb
226
252
  - lib/zillabyte/cli/host.rb
253
+ - lib/zillabyte/cli/log_formatter.rb
227
254
  - lib/zillabyte/cli/query.rb
228
255
  - lib/zillabyte/cli/relations.rb
229
256
  - lib/zillabyte/cli/sources.rb
230
257
  - lib/zillabyte/cli/templates/js/simple_function.js
231
258
  - lib/zillabyte/cli/templates/js/zillabyte.conf.yaml
232
- - lib/zillabyte/cli/templates/python/#simple_function.py#
233
259
  - lib/zillabyte/cli/templates/python/requirements.txt
234
260
  - lib/zillabyte/cli/templates/python/simple_function.py
235
261
  - lib/zillabyte/cli/templates/python/zillabyte.conf.yaml
@@ -273,7 +299,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
273
299
  version: '0'
274
300
  requirements: []
275
301
  rubyforge_project:
276
- rubygems_version: 2.1.10
302
+ rubygems_version: 2.0.7
277
303
  signing_key:
278
304
  specification_version: 4
279
305
  summary: The Official Zillabyte CLI Gem
@@ -1,170 +0,0 @@
1
- # load('zillabyte/helpers.rb') # reload helpers after possible inject_loadpath
2
- # load('zillabyte/updater.rb') # reload updater after possible inject_loadpath
3
-
4
- require "base64"
5
- require "excon"
6
- # require "securerandom"
7
- require "uri"
8
- require "zlib"
9
- require "active_support/core_ext/object/to_query.rb"
10
- require 'json'
11
-
12
-
13
- # workaround for rescue/reraise to define errors in command.rb failing in 1.8.6
14
- if RUBY_VERSION =~ /^1.8.6/
15
- # require('zillabyte-api')
16
- require('rest_client')
17
- end
18
-
19
- class Zillabyte::API
20
-
21
- HEADERS = {
22
- 'Accept' => 'application/json',
23
- 'Content-Type' => 'application/json',
24
- # 'Accept-Encoding' => 'gzip',
25
- 'User-Agent' => "zillabyte/#{Zillabyte::CLI::VERSION}",
26
- 'X-Ruby-Version' => RUBY_VERSION,
27
- 'X-Ruby-Platform' => RUBY_PLATFORM
28
- }
29
-
30
- OPTIONS = {
31
- :headers => {},
32
- :host => ENV['ZILLABYTE_API_HOST'] || 'api.zillabyte.com',
33
- :port => (ENV['ZILLABYTE_API_PORT'] || '80').to_i,
34
- :nonblock => false,
35
- :scheme => 'http'
36
- }
37
-
38
-
39
-
40
- def initialize(options={})
41
- options = OPTIONS.merge(options)
42
-
43
- @progress = options.delete(:progress)
44
- @api_key = options.delete(:api_key) || ENV['ZILLABYTE_API_KEY']
45
-
46
- options[:headers] = HEADERS.merge({
47
- 'Authorization' => "auth_token #{@api_key}",
48
- }).merge(options[:headers])
49
-
50
- @options = options.clone
51
- @options[:bubble_exceptions] = ENV['BUBBLE_EXCEPTIONS'] || false
52
-
53
- @connection = Excon.new("#{options[:scheme]}://#{options[:host]}", options)
54
-
55
- end
56
-
57
-
58
- def host
59
- @options[:host]
60
- end
61
-
62
-
63
- def request(params, &block)
64
- begin
65
- # The @connection object handles connections to api.zillabyte.com via Excon, this sends a command to the Rails api code
66
- # with parameters in params (one of which contains the path to the method to be run in the form of a url, e.g. if the
67
- # :path parameter is set to /functions/#{id}?tar=1, then the show method in functions_controller.rb will be automatically
68
- # called...it will have it's own set of parameters which correspond to the items in the query string).
69
- response = @connection.request(params, &block)
70
- rescue Excon::Errors::HTTPStatusError => error
71
- @progress.error "internal server error" if @progress
72
- raise error
73
- end
74
-
75
- if response.body && !response.body.empty?
76
- # decompress_response!(response)
77
- begin
78
- response.body = JSON.parse(response.body)
79
- rescue Exception => e
80
- raise e if @options[:bubble_exceptions]
81
- @progress.error "unknown server response: \n #{response.body}" if @progress
82
- end
83
- end
84
-
85
- # Errors?
86
- if response.body.is_a?(Hash)
87
- if response.body["status"] == "error"
88
- if @progress
89
- if response.body["error"] == "authentication_error"
90
- @progress.error "authentication error. run 'zillabyte login'"
91
- else
92
- @progress.error response.body["error_message"]
93
- end
94
- end
95
- end
96
- end
97
-
98
-
99
- # reset (non-persistent) connection
100
- @connection.reset
101
-
102
- response
103
- end
104
-
105
-
106
- def data
107
- @_data ||= ::Zillabyte::API::Data.new(self)
108
- end
109
-
110
- def logs
111
- @_logs ||= ::Zillabyte::API::Logs.new(self)
112
- end
113
-
114
-
115
- def queries
116
- @_queries ||= ::Zillabyte::API::Queries.new(self)
117
- end
118
- alias_method :query, :queries
119
-
120
- def flows
121
- @_flows ||= ::Zillabyte::API::Flows.new(self)
122
- end
123
- alias_method :flow, :flows
124
-
125
- def metrics
126
- @_metrics ||= ::Zillabyte::API::Metrics.new(self)
127
- end
128
- alias_method :metric, :metrics
129
-
130
- def zillalogs
131
- @_rules ||= ::Zillabyte::API::Zillalogs.new(self)
132
- end
133
- alias_method :zillalog, :zillalogs
134
-
135
- def sources
136
- @_sources ||= ::Zillabyte::API::Sources.new(self)
137
- end
138
- alias_method :source, :sources
139
-
140
-
141
- def collectors
142
- @_collectors ||= ::Zillabyte::API::Collectors.new(self)
143
- end
144
- alias_method :collector, :collectors
145
-
146
- def semantic_tags
147
- @_rules ||= ::Zillabyte::API::SemanticTags.new(self)
148
- end
149
- alias_method :zillalog, :zillalogs
150
-
151
-
152
-
153
-
154
-
155
- def self.load
156
- Dir[File.join(File.dirname(__FILE__), "api", "*.rb")].sort.each do |file|
157
- require file
158
- end
159
-
160
- Dir[File.join(File.dirname(__FILE__), "api", "helpers", "*.rb")].sort.each do |file|
161
- require file
162
- end
163
- end
164
-
165
-
166
- end
167
-
168
-
169
- # Load all helpers...
170
- Zillabyte::API.load()
@@ -1,12 +0,0 @@
1
- require "zillabyte/cli/base"
2
-
3
- # manage custom logs
4
- #
5
- class Zillabyte::Command::Logs < Zillabyte::Command::Base
6
-
7
-
8
-
9
-
10
-
11
-
12
- end
@@ -1,27 +0,0 @@
1
- import zillabyte
2
-
3
- def prep(controller):
4
- return
5
-
6
- # This is the heart of your algorithm. It's processed on every
7
- # web page. This algorithm is run in parallel on possibly hundreds
8
- # of machines.
9
- def execute(controller, tup):
10
- if("hello world" in tup.values["html"]):
11
- controller.emit("has_hello_world",{"url":tup.values["url"]})
12
- return
13
-
14
- zillabyte.simple_function(\
15
- # This directive instructs zillabyte to give your function every
16
- # web page in our known universe. Your function will have access
17
- # to two fields: URL and HTML
18
- matches = "select * from web_pa", \
19
-
20
- # This directive tells Zillabyte what kind of data your function
21
- # produces. In this case, we're saying we will emit a tuple that
22
- # is one-column wide and contains the field 'URL'
23
- emits = [["has_hello_world", [{"url":"string"}]]], \
24
-
25
- prepare = prep, \
26
- execute = execute\
27
- )