zillabyte-cli 0.0.9

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.
Files changed (53) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +20 -0
  4. data/README.md +29 -0
  5. data/bin/zillabyte +18 -0
  6. data/lib/zillabyte/api/base.rb +11 -0
  7. data/lib/zillabyte/api/data.rb +126 -0
  8. data/lib/zillabyte/api/flows.rb +239 -0
  9. data/lib/zillabyte/api/locks.rb +4 -0
  10. data/lib/zillabyte/api/logs.rb +32 -0
  11. data/lib/zillabyte/api/metrics.rb +48 -0
  12. data/lib/zillabyte/api/queries.rb +58 -0
  13. data/lib/zillabyte/api/semantic_tags.rb +24 -0
  14. data/lib/zillabyte/api/settings.rb +8 -0
  15. data/lib/zillabyte/api/sources.rb +28 -0
  16. data/lib/zillabyte/api/zillalogs.rb +66 -0
  17. data/lib/zillabyte/api.rb +170 -0
  18. data/lib/zillabyte/auth.rb +155 -0
  19. data/lib/zillabyte/cli/auth.rb +33 -0
  20. data/lib/zillabyte/cli/base.rb +161 -0
  21. data/lib/zillabyte/cli/config.rb +63 -0
  22. data/lib/zillabyte/cli/counters.rb +61 -0
  23. data/lib/zillabyte/cli/flows.rb +702 -0
  24. data/lib/zillabyte/cli/help.rb +137 -0
  25. data/lib/zillabyte/cli/helpers/data_schema_builder.rb +3 -0
  26. data/lib/zillabyte/cli/host.rb +21 -0
  27. data/lib/zillabyte/cli/logs.rb +118 -0
  28. data/lib/zillabyte/cli/query.rb +172 -0
  29. data/lib/zillabyte/cli/relations.rb +326 -0
  30. data/lib/zillabyte/cli/sources.rb +37 -0
  31. data/lib/zillabyte/cli/templates/js/simple_function.js +33 -0
  32. data/lib/zillabyte/cli/templates/js/zillabyte.conf.yaml +2 -0
  33. data/lib/zillabyte/cli/templates/python/requirements.txt +7 -0
  34. data/lib/zillabyte/cli/templates/python/simple_function.py +27 -0
  35. data/lib/zillabyte/cli/templates/python/zillabyte.conf.yaml +4 -0
  36. data/lib/zillabyte/cli/templates/ruby/Gemfile +3 -0
  37. data/lib/zillabyte/cli/templates/ruby/simple_function.rb +36 -0
  38. data/lib/zillabyte/cli/templates/ruby/zillabyte.conf.yaml +2 -0
  39. data/lib/zillabyte/cli/version.rb +11 -0
  40. data/lib/zillabyte/cli/zillalogs.rb +86 -0
  41. data/lib/zillabyte/cli.rb +37 -0
  42. data/lib/zillabyte/command.rb +254 -0
  43. data/lib/zillabyte/common/progress.rb +17 -0
  44. data/lib/zillabyte/common/tar.rb +102 -0
  45. data/lib/zillabyte/common.rb +13 -0
  46. data/lib/zillabyte/helpers.rb +49 -0
  47. data/lib/zillabyte/queries.rb +39 -0
  48. data/lib/zillabyte-cli/version.rb +5 -0
  49. data/lib/zillabyte-cli.rb +5 -0
  50. data/zillabyte-cli.gemspec +42 -0
  51. data/zillabyte_emails.csv +1 -0
  52. data/zillaconf.json +3 -0
  53. metadata +278 -0
@@ -0,0 +1,326 @@
1
+ require "zillabyte/cli/base"
2
+ require "csv"
3
+
4
+ # manage custom relations
5
+ #
6
+ class Zillabyte::Command::Relations < Zillabyte::Command::Base
7
+
8
+ # relations
9
+ #
10
+ #
11
+ def index
12
+ self.list
13
+ end
14
+
15
+
16
+ # relations:list
17
+ #
18
+ # lists your custom relations
19
+ #
20
+ def list
21
+
22
+ response = api.request(
23
+ :expects => 200,
24
+ :method => :get,
25
+ :path => "/relations"
26
+ )
27
+
28
+ headings = []
29
+ rows = response.body.map do |row|
30
+ headings = row.keys if headings.size == 0
31
+ row["columns"] = row["columns"].map{|c| c['type']}.join(',')
32
+ vals = row.values_at *headings
33
+ vals
34
+ end
35
+
36
+ display "relations:\n" + Terminal::Table.new(:headings => headings, :rows => rows).to_s
37
+ display "Total number of relations: "+rows.length.to_s
38
+
39
+
40
+ end
41
+
42
+
43
+ alias_command "list", "relations:list"
44
+ alias_command "relations:list", "relations:list"
45
+ alias_command "relation:list", "relations:list"
46
+
47
+
48
+
49
+ # relations:status RELATION
50
+ #
51
+ # shows status of a relation
52
+ #
53
+ def status
54
+
55
+ name = options[:relation_name] || shift_argument
56
+ error "no name given" if name.nil?
57
+
58
+ res = api.request(
59
+ :path => "/metrics/#{name}",
60
+ :method => :get,
61
+ :expects => 200
62
+ )
63
+
64
+ if res['error']
65
+ error res['error_message']
66
+ end
67
+
68
+ data = res.body.first
69
+
70
+ if data.nil?
71
+ error "metric not found"
72
+ end
73
+
74
+ data = data["datapoints"]
75
+
76
+ last_date = data.last(30).first[1]
77
+ formatted = []
78
+ i = 0
79
+ data.each do |tup|
80
+ value = tup[0]
81
+ date = tup[1] - last_date
82
+ if date > 0
83
+ formatted << [i, value || 0]
84
+ i += 1
85
+ end
86
+ end
87
+
88
+ display "#{name}:"
89
+ display AsciiCharts::Cartesian.new(formatted, :bar => true, :hide_zero => true).draw
90
+
91
+
92
+ end
93
+
94
+
95
+
96
+ # relations:create NAME
97
+ #
98
+ # creates a new relation
99
+ #
100
+ # --schema SCHEMA # a JSON array of column types
101
+ # --semantics SEMANTICS # a JSON array of semantics within the relation
102
+ # --public # Make the relation public
103
+ #
104
+ def create
105
+
106
+ name = options[:name] || shift_argument
107
+ error "no name given" if name.nil?
108
+
109
+ schema = JSON.parse(options[:schema]) if options[:schema]
110
+ semantics = JSON.parse(options[:semantics]) if options[:semantics]
111
+ is_public = options[:public] || false
112
+
113
+ hash = set_relation_properties(schema,semantics,is_public)
114
+ res = api.data.create name, hash
115
+
116
+ if res['error']
117
+ display "error: #{res['error_message']}"
118
+ else
119
+ display "relation ##{res['id']} #{res['action']}. size: #{res['size']}"
120
+ end
121
+
122
+ end
123
+
124
+ #alias_command "upload", "data:upload"
125
+ alias_command "relations:upload", "relations:create"
126
+ alias_command "relation:upload", "relations:create"
127
+
128
+
129
+
130
+ # relations:append ID FILE
131
+ #
132
+ # adds data to an existing relation
133
+ #
134
+ # --type TYPE # interpret file as type [csv, xlsx]
135
+ #
136
+ def append
137
+
138
+ id = options[:id] || shift_argument
139
+ file = options[:file] || shift_argument
140
+ type = options[:type]
141
+
142
+ error "no id given" if id.nil?
143
+ error "no id given" if file.nil?
144
+ type ||= File.extname(file).gsub(".", "")
145
+
146
+ dataset = self.api.data.get(id)
147
+ rows = sanity_check_file(file,type,dataset)
148
+
149
+ #res = self.api.data.append(id, {:row => rows})
150
+ res = self.api.data.append(id, {:file => file})
151
+ display "relation #{id} appended"
152
+
153
+ end
154
+
155
+
156
+ # relations:show ID
157
+ #
158
+ # shows raw data in a relation. run 'queries' for more elaborate functionality
159
+ #
160
+ # --no_truncation # don't truncate long strings
161
+ #
162
+ def show
163
+
164
+ name = options[:name] || shift_argument
165
+ error "no id given" if name.nil?
166
+
167
+ res = self.api.data.get(name)
168
+
169
+ if res["rows"].size > 0
170
+
171
+ headings = res["rows"].first.keys
172
+ headings.delete("id")
173
+ table = Terminal::Table.new :headings => headings
174
+ res["rows"].each do |obj|
175
+
176
+ new_row = headings.map do |heading|
177
+ if options[:no_truncation]
178
+ obj[heading]
179
+ else
180
+ if obj[heading].to_s.size > 30
181
+ obj[heading].to_s[0..30] + "..."
182
+ else
183
+ obj[heading]
184
+ end
185
+ end
186
+ end
187
+
188
+ table.add_row new_row
189
+
190
+ end
191
+ display table.to_s
192
+
193
+ else
194
+
195
+ display "empty relation"
196
+
197
+ end
198
+
199
+ end
200
+
201
+ alias_command "relations:show", "relations:show"
202
+ alias_command "relation:show", "relations:show"
203
+
204
+ # relations:test NAME FILE
205
+ #
206
+ # creates test relation NAME and uploads FILE to NAME
207
+ #
208
+ def test
209
+ name = options[:name] || shift_argument
210
+ error "no name given" if name.nil?
211
+
212
+ file = options[:file] || shift_argument
213
+ error "no file given" if file.nil?
214
+
215
+ schema = options[:schema]
216
+ relations = options[:relations]
217
+ is_public = options[:public] || false
218
+
219
+ hash = set_dataset_properties(schema,relations,is_public)
220
+ res = api.data.create name, hash
221
+
222
+ type = options[:type]
223
+ type ||= File.extname(file).gsub(".", "")
224
+
225
+ id = res['id']
226
+ dataset = self.api.data.get(id)
227
+ rows = sanity_check_file(file,type,dataset)
228
+
229
+ #res = self.api.data.append(id, {:row => rows,:for_test => 1})
230
+ res = self.api.data.append(id, {:file => file,:for_test => 1})
231
+ display "relation (for test) #{id} appended"
232
+ end
233
+
234
+ private
235
+
236
+ def set_dataset_properties(schema,relations,is_public)
237
+ valid_types=["STRING", "NUMERIC", "FLOAT"]
238
+ if schema.nil?
239
+ schema = []
240
+
241
+ # Get the column types (required)
242
+ index = 0
243
+ while true
244
+
245
+ display "type for column v#{index} [#{valid_types.join(', ')}] (empty when done):", false
246
+ type = ask.upcase
247
+ break if type == "" || type.nil?
248
+ unless valid_types.member?(type)
249
+ warn "invalid type: #{type}"
250
+ next
251
+ end
252
+ index += 1
253
+ schema << type
254
+ end
255
+
256
+ display "using schema: #{schema.to_json}"
257
+
258
+ end
259
+
260
+ if relations.nil?
261
+
262
+ # Get the semantics (inner relations)
263
+ relations = []
264
+ display "would you like to define relations on your dataset? (yes/No): ", false
265
+ if ['y', 'yes'].include?(ask.downcase)
266
+
267
+ # Display the first bit of the taple
268
+ display Terminal::Table.new(:rows => [schema], :headings => schema.size.times.map{|i| "v#{i}"}).to_s
269
+
270
+ # Start collection relations
271
+ while true
272
+ display "relation predicate (ex: \"(company v0)\", \"(coordinates v1 v2)\"): ", false
273
+ input = ask
274
+ break if input.nil? || input == ""
275
+
276
+ pred = input.gsub("(","").gsub(")", "").split(/\s+/)
277
+ pred_name = pred[0]
278
+ pred_cols = pred[1..-1]
279
+ pred_cols.each_with_index do |col, pred_index|
280
+ m = /v(\d+)/.match(col)
281
+ if m.nil?
282
+ warn "the predicate variables must be of the form \"v[1-10]\""
283
+ next
284
+ end
285
+
286
+ column = m[1].to_i
287
+ if column >= schema.size
288
+ warn "the variable #{col} is out of range"
289
+ next
290
+ end
291
+
292
+ # Otherwise, successful
293
+ relations[column] ||= []
294
+ relations[column] << "#{pred_name}.#{pred_index}"
295
+ end
296
+
297
+ end
298
+
299
+ # Show them what the relation looks like
300
+ display "using relation: #{relations.to_json}"
301
+
302
+ end
303
+ end
304
+ {:schema => schema, :relations => relations, :public => is_public}
305
+ end
306
+
307
+ def sanity_check_file(file,type,dataset)
308
+ rows = []
309
+
310
+ case type
311
+ when "csv"
312
+ CSV.foreach(file) do |row|
313
+ if row.size != dataset['columns'].size
314
+ puts "relation expect #{dataset['columns'].size} column(s). Found a row with #{row.size}::\n #{row}"
315
+ else
316
+ rows << row
317
+ end
318
+ end
319
+
320
+ else
321
+ error "unsupported type: #{type}"
322
+
323
+ end
324
+ rows
325
+ end
326
+ end
@@ -0,0 +1,37 @@
1
+ # require "zillabyte/cli/base"
2
+ # require "csv"
3
+ #
4
+ # # data sources
5
+ # #
6
+ # class Zillabyte::Command::Sources < Zillabyte::Command::Base
7
+ #
8
+ #
9
+ # # sources
10
+ # #
11
+ # #
12
+ # def index
13
+ # self.list
14
+ # end
15
+ #
16
+ #
17
+ # # sources:list
18
+ # #
19
+ # # lists public and custom data sources
20
+ # #
21
+ # def list
22
+ #
23
+ # headings = []
24
+ # sources = api.sources.list.map do |row|
25
+ # headings = row.keys if headings.size == 0
26
+ # row.values_at *headings
27
+ # end
28
+ # display "data sources:\n" + Terminal::Table.new(:headings => headings, :rows => sources).to_s
29
+ #
30
+ # end
31
+ #
32
+ #
33
+ # alias_command "sources", "sources:list"
34
+ #
35
+ #
36
+ #
37
+ # end
@@ -0,0 +1,33 @@
1
+ var zillabyte = require('zillabyte');
2
+
3
+ function prep(controller) {
4
+ }
5
+
6
+ /**
7
+ * This is the heart of your algorithm. It's processed on every
8
+ * web page. This algorithm is run in parallel on possibly hundreds
9
+ * of machines.
10
+ */
11
+ function exec(controller, tuple) {
12
+ if(tuple.values["html"].indexOf("hello world") !== -1) {
13
+ controller.emit("has_hello_world",{"url":tuple.values["url"]});
14
+ }
15
+ }
16
+
17
+ zillabyte.simple_function({
18
+ /**
19
+ * This directive instructs zillabyte to give your function every
20
+ * web page in our known universe. Your function will have access
21
+ * to two fields: URL and HTML
22
+ */
23
+ matches: "select * from web_pages",
24
+
25
+ /**
26
+ * This directive tells Zillabyte what kind of data your function
27
+ * produces. In this case, we're saying we will emit a tuple that
28
+ * is one-column wide and contains the field 'URL'
29
+ */
30
+ emits: [["has_hello_world", [{"url":"string"}]]],
31
+ prepare: prep,
32
+ execute: exec
33
+ });
@@ -0,0 +1,2 @@
1
+ language: js
2
+ script: simple_function.js
@@ -0,0 +1,7 @@
1
+ # Indicate any required libraries here
2
+ # Default libraries installed:
3
+ # - numpy 1.8.0
4
+ # - scipy 0.13.0
5
+ # For all other libraries, enter one per line in the following format: LIBRARY==VERSION, e.g. numpy==1.8.0
6
+ # MAKE SURE LIBRARY DEPENDENCIES ARE ALSO INCLUDED, FOR EXAMPLE IF YOUR LIBRARY NEEDS MATPLOTLIB FUNCTIONS, THEN MATPLOTLIB
7
+ # MUST ALSO BE LISTED BELOW EVEN IF YOU DO NOT CALL ANY OF ITS FUNCTIONS EXPLICITLY.
@@ -0,0 +1,27 @@
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_pages", \
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
+ )
@@ -0,0 +1,4 @@
1
+ language: python
2
+ script: simple_function.py
3
+ ignore_files:
4
+ - ./vEnv
@@ -0,0 +1,3 @@
1
+
2
+ gem "zillabyte", :path => "~/zb1/multilang/"
3
+ gem "zillabyte-cli", :path => "~/zb1/cli/"
@@ -0,0 +1,36 @@
1
+ require 'zillabyte'
2
+
3
+ Zillabyte.simple_function do |fn|
4
+
5
+ # This directive instructs zillabyte to give your function every
6
+ # web page in our known universe. Your function will have access
7
+ # to two fields: URL and HTML
8
+ fn.matches "select * from web_pages"
9
+
10
+ # This directive tells Zillabyte what kind of data your function
11
+ # produces. In this case, we're saying we will emit a tuple that
12
+ # is one-column wide and contains the field 'URL'
13
+ fn.emits [["has_hello_world", [{"URL"=>:string}]]]
14
+
15
+
16
+ # This is the heart of your algorithm. It's processed on every
17
+ # web page. This algorithm is run in parallel on possibly hundreds
18
+ # of machines.
19
+ fn.execute do |controller, tuple|
20
+
21
+ # get the fields
22
+ url = tuple['v0']
23
+ html = tuple['v1']
24
+
25
+ # does this page contains the 'hello world' phrase? If so, emit it
26
+ if html.include?('hello') or html.include?('world')
27
+ controller.emit("URL" => url)
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+
35
+
36
+
@@ -0,0 +1,2 @@
1
+ language: ruby
2
+ script: simple_function.rb
@@ -0,0 +1,11 @@
1
+ require "zillabyte/cli/base"
2
+
3
+ # display version number
4
+ #
5
+ class Zillabyte::Command::Version < Zillabyte::Command::Base
6
+
7
+ def index(*direct_args)
8
+ display "Zillabyte CLI Version #{Zillabyte::CLI::VERSION}"
9
+ end
10
+
11
+ end
@@ -0,0 +1,86 @@
1
+ # require "zillabyte/cli/base"
2
+ # require "rest_client"
3
+ # require "json"
4
+ #
5
+ # # manage custom zillalogs
6
+ # #
7
+ # class Zillabyte::Command::Zillalogs < Zillabyte::Command::Base
8
+ #
9
+ #
10
+ # # zillalogs
11
+ # #
12
+ # #
13
+ # def index
14
+ # Zillabyte::Command::Help.new.index "zillalogs"
15
+ # end
16
+ #
17
+ #
18
+ #
19
+ # # zillalogs:list
20
+ # #
21
+ # # list custom zillalogs
22
+ # #
23
+ # def list
24
+ #
25
+ # rules = api.zillalogs.list.map do |row|
26
+ # row
27
+ # end
28
+ # display "your rules:\n" + Terminal::Table.new(:rows => rules).to_s
29
+ #
30
+ # end
31
+ #
32
+ #
33
+ #
34
+ #
35
+ # # zillalogs:show ID
36
+ # #
37
+ # # shows a zillalog
38
+ # #
39
+ # def show
40
+ #
41
+ # id = options[:id] || shift_argument
42
+ # rule = api.zillalogs.find(id)
43
+ #
44
+ # if rule['error']
45
+ # error "#{rule['error_message']}"
46
+ # else
47
+ # display rule["zillalog"]
48
+ # end
49
+ #
50
+ # end
51
+ #
52
+ #
53
+ #
54
+ #
55
+ # # zillalogs:add NAME [CONTENT]
56
+ # #
57
+ # # adds (or updates) a rule
58
+ # #
59
+ # def add
60
+ #
61
+ # name = options[:name] || shift_argument
62
+ # error "name is required" unless name
63
+ #
64
+ # content = options[:content] || shift_argument
65
+ # if content.nil?
66
+ # puts "type ^D to exit"
67
+ # content = STDIN.readlines.join("")
68
+ # display "saving..."
69
+ # end
70
+ #
71
+ # error "content is required" if content.nil?
72
+ # res = api.zillalogs.save nil, name, content
73
+ #
74
+ # if res['error']
75
+ # display "error: #{res['error_message']}"
76
+ # else
77
+ # display "rule ##{res['id']} #{res['action']}"
78
+ # end
79
+ #
80
+ # end
81
+ #
82
+ # # alias_command "add", "zillalogs:add"
83
+ #
84
+ #
85
+ #
86
+ # end
@@ -0,0 +1,37 @@
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 'zillabyte/cli/config'
5
+ require "zillabyte/auth"
6
+ require "zillabyte/command"
7
+ require 'terminal-table'
8
+ require 'chronic'
9
+ require 'ascii_charts'
10
+
11
+ # workaround for rescue/reraise to define errors in command.rb failing in 1.8.6
12
+ if RUBY_VERSION =~ /^1.8.6/
13
+ # require('zillabyte-api')
14
+ require('rest_client')
15
+ end
16
+
17
+ module Zillabyte::CLI
18
+
19
+ extend Zillabyte::Helpers
20
+
21
+ def self.start(*args)
22
+ begin
23
+ command = args.shift.strip rescue "help"
24
+ Zillabyte::Command.load
25
+ Zillabyte::Command.run(command, args)
26
+ rescue Interrupt
27
+ `stty icanon echo`
28
+ error("Command cancelled.")
29
+ rescue => error
30
+ raise
31
+ #display(error)
32
+ #exit(1)
33
+ end
34
+ end
35
+
36
+ end
37
+