zillabyte-cli 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
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
+