zillabyte-cli 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +9 -9
  2. data/lib/#zillabyte-cli.rb# +5 -0
  3. data/lib/zillabyte/api/{flows.rb → apps.rb} +35 -23
  4. data/lib/zillabyte/api/data.rb +12 -1
  5. data/lib/zillabyte/api/logs.rb +4 -4
  6. data/lib/zillabyte/api/queries.rb +15 -6
  7. data/lib/zillabyte/api/zillalogs.rb +1 -1
  8. data/lib/zillabyte/api.rb +40 -38
  9. data/lib/zillabyte/auth.rb +19 -11
  10. data/lib/zillabyte/cli/#logs.rb# +12 -0
  11. data/lib/zillabyte/cli/{flows.rb → apps.rb} +407 -177
  12. data/lib/zillabyte/cli/auth.rb +1 -1
  13. data/lib/zillabyte/cli/base.rb +5 -4
  14. data/lib/zillabyte/cli/config.rb +3 -2
  15. data/lib/zillabyte/cli/counters.rb +1 -1
  16. data/lib/zillabyte/cli/help.rb +1 -1
  17. data/lib/zillabyte/cli/helpers/data_schema_builder.rb +1 -1
  18. data/lib/zillabyte/cli/helpers/table_output_builder.rb +25 -0
  19. data/lib/zillabyte/cli/log_formatter.rb +4 -3
  20. data/lib/zillabyte/cli/query.rb +107 -26
  21. data/lib/zillabyte/cli/relations.rb +226 -78
  22. data/lib/zillabyte/cli/sources.rb +1 -1
  23. data/lib/zillabyte/cli/templates/js/simple_function.js +5 -0
  24. data/lib/zillabyte/cli/templates/python/#simple_function.py# +27 -0
  25. data/lib/zillabyte/cli/templates/python/simple_function.py +3 -0
  26. data/lib/zillabyte/cli/templates/ruby/{simple_function.rb → simple_app.rb} +6 -6
  27. data/lib/zillabyte/cli/templates/ruby/zillabyte.conf.yaml +1 -1
  28. data/lib/zillabyte/cli/version.rb +1 -1
  29. data/lib/zillabyte/cli/zillalogs.rb +1 -1
  30. data/lib/zillabyte/command.rb +10 -2
  31. data/lib/zillabyte/common/{progress.rb → session.rb} +1 -1
  32. data/lib/zillabyte/helpers.rb +9 -4
  33. data/lib/zillabyte-cli/version.rb +1 -1
  34. data/zillabyte-cli.gemspec +2 -0
  35. metadata +25 -7
@@ -1,34 +1,42 @@
1
1
  require "zillabyte/cli/base"
2
+ require "zillabyte/cli/helpers/table_output_builder"
2
3
  require "csv"
3
4
  require "open-uri"
4
5
  require "aws-sdk"
6
+ require "json"
7
+
5
8
 
6
9
  # manage custom relations
7
10
  #
8
11
  class Zillabyte::Command::Relations < Zillabyte::Command::Base
9
12
 
13
+ MAX_POLL_SECONDS = 60 * 5
14
+ POLL_SLEEP = 0.5
15
+
10
16
  # relations
11
17
  #
12
18
  # lists your custom relations
19
+ # --type TYPE # specify an output type i.e. json
13
20
  #
14
21
  def index
15
22
  self.list
16
23
  end
17
24
 
18
25
 
19
-
20
26
  # relations
21
- #
27
+ # v
22
28
  # lists your custom relations
23
29
  #
30
+ # --type TYPE # The output format type
24
31
  def list
25
-
32
+ type = options[:type] || nil
33
+
26
34
  response = api.request(
27
35
  :expects => 200,
28
36
  :method => :get,
29
37
  :path => "/relations"
30
38
  )
31
-
39
+
32
40
  headings = []
33
41
  rows = response.body.map do |row|
34
42
  headings = row.keys if headings.size == 0
@@ -37,10 +45,11 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
37
45
  vals = row.values_at *headings
38
46
  vals
39
47
  end
40
-
41
- display "relations:\n" + Terminal::Table.new(:headings => headings, :rows => rows).to_s
42
- display "Total number of relations: "+rows.length.to_s
43
-
48
+
49
+ display "relations\n" if type.nil? && rows.size > 0
50
+ display TableOutputBuilder.build_table(headings, rows, type)
51
+ display "Total number of relations: "+rows.length.to_s if type.nil?
52
+
44
53
  end
45
54
  alias_command "rl:list", "relations:list"
46
55
 
@@ -49,13 +58,20 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
49
58
  #
50
59
  # deletes a relation
51
60
  #
52
- # -f, --force # Delete without asking for confirmation
61
+ # -f, --force # Delete without asking for confirmation
62
+ # --type TYPE # The output format type
53
63
  def delete
54
64
  id = options[:id] || shift_argument
55
65
  forced = options[:force]
56
- if not forced
66
+ type = options[:type] || nil
67
+
68
+ if !forced
69
+
70
+ if !type.nil?
71
+ error("specify -f, --force to confirm deletion", type)
72
+ end
73
+
57
74
  while true
58
-
59
75
  display "This operation cannot be undone. Are you sure you want to delete this relation? (yes/no):", false
60
76
  confirm = ask
61
77
  break if confirm == "yes" || confirm == "no"
@@ -66,11 +82,17 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
66
82
  confirmed = forced || confirm == "yes"
67
83
 
68
84
  if confirmed
69
- response = api.data.delete(id)
70
- display response["body"]
85
+ res = api.data.delete(id)
86
+ if res['error']
87
+ error(res['error'], type)
88
+ else
89
+ if type == "json"
90
+ display {}.to_json
91
+ else
92
+ display res["body"]
93
+ end
94
+ end
71
95
  end
72
-
73
-
74
96
  end
75
97
  alias_command "rl:delete", "relations:delete"
76
98
 
@@ -82,36 +104,47 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
82
104
  # --schema SCHEMA # Column names and types in the format "field_1:type_1,field_2:type_2,..."
83
105
  # --public SCOPE # Make the relation public
84
106
  # --file FILE # A data file
85
- # --type TYPE # File format type, defaults to csv
107
+ # --filetype FILETYPE # File format type, defaults to csv
86
108
  # --description DESCRIPTION # Description of relation contents
87
109
  # --aliases ALIASES # Relation name aliases in the format "alias_1,alias_2,..."
110
+ # --type TYPE # The output format type
88
111
  #
89
112
  def create
90
113
 
91
114
  name = options[:name] || shift_argument
92
115
  file = options[:file] || nil
93
- type = options[:type] || nil
116
+ filetype = options[:filetype] || nil
117
+ type = options[:type]
94
118
 
95
- error "no name given" if name.nil?
119
+ error("no name given", type) if name.nil?
96
120
 
97
121
  schema = options[:schema] if options[:schema]
98
122
  is_public = options[:public] || nil
99
123
  description = options[:description] || nil
100
124
  aliases = options[:aliases] || nil
101
-
102
- hash = set_relation_properties(schema,is_public,description,aliases)
125
+
126
+ if type.nil?
127
+ hash = get_relation_properties(schema,is_public,description,aliases)
128
+ else
129
+ hash = hash_relation_properties(schema,is_public,description,aliases, type)
130
+ end
131
+
103
132
  if file
104
- type ||= File.extname(file).gsub(".", "")
105
- rows = sanity_check_file(file,type, {"columns" => hash[:schema]})
133
+ filetype ||= File.extname(file).gsub(".", "")
134
+ rows = sanity_check_file(file,filetype, {"columns" => hash[:schema]}, type)
106
135
  hash[:rows] = rows
107
136
  end
108
137
 
109
138
  res = api.data.create name, hash
110
139
 
111
140
  if res['error']
112
- display "error: #{res['error_message']}"
141
+ error("#{res['error_message']}", type)
113
142
  else
114
- display "relation ##{res['id']} #{res['action']}. size: #{res['size'] || 0} rows."
143
+ if type == "json"
144
+ display {}.to_json
145
+ else
146
+ display "relation ##{res['id']} #{res['action']}. size: #{res['size'] || 0} rows."
147
+ end
115
148
  end
116
149
 
117
150
  end
@@ -121,8 +154,8 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
121
154
  # relations:append ID FILE
122
155
  #
123
156
  # adds data to an existing relation
124
- #
125
- # --type TYPE # File format type, defaults to csv
157
+ # --filetype FILETYPE # Input File format type, defaults to csv
158
+ # --type TYPE # Output formatting type i.e. json
126
159
  #
127
160
  def append
128
161
 
@@ -130,16 +163,22 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
130
163
  file = options[:file] || shift_argument
131
164
  type = options[:type]
132
165
 
133
- error "no id given" if id.nil?
134
- error "no file given" if file.nil?
135
- type ||= File.extname(file).gsub(".", "")
166
+ filetype = options[:filetype]
167
+ filetype ||= File.extname(file).gsub(".", "")
168
+ error("no id given", type) if id.nil?
169
+ error("no file given", type) if file.nil?
170
+
136
171
 
137
172
  relation = self.api.data.get(id)
138
173
  columns = relation["columns"].map{|col| {col["index"] => col["type"]}}
139
- rows = sanity_check_file(file,type,{"columns" => columns})
174
+ rows = sanity_check_file(file,filetype,{"columns" => columns}, type)
140
175
 
141
176
  res = self.api.data.append(id, {:rows => rows})
142
- display "relation ##{id} appended #{res["size"]} rows"
177
+ if type == "json"
178
+ display {}.to_json
179
+ else
180
+ display "relation ##{id} appended #{res["size"]} rows"
181
+ end
143
182
 
144
183
  end
145
184
  alias_command "append", "relations:append"
@@ -149,31 +188,36 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
149
188
  #
150
189
  # pulls relation data into OUTPUT.gz
151
190
  #
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)
191
+ # --cycle_id [cycle_id] # retrieve data generated for that cycle, only if this relation is associated with an app. (defaults to the last cycle
192
+ # --type TYPE # the output format type
153
193
  #
154
194
  def pull
155
195
 
156
196
  id = options[:id] || shift_argument
157
197
  file = options[:file] || shift_argument
158
- error "no id given" if id.nil?
159
- error "no output file given" if file.nil?
198
+ type = options[:type]
199
+ error("no id given", type) if id.nil?
200
+ error("no file given", type) if file.nil?
201
+
160
202
  file = "#{file}.gz" unless File.extname(file) == ".gz"
161
203
 
162
204
  res = self.api.data.pull(id, options)
205
+
163
206
  if(res["uri"])
164
- display "Waiting for download."
207
+ display "Waiting for download." if type.nil?
165
208
  File.open(file, "w") do |f|
166
209
  f.write open(res["uri"]).read
167
210
  end
168
211
  elsif(res["s3_credentials"])
169
- display "Request sent. Depending on the size of your file, this may take a while."
212
+ display "Request sent. Depending on the size of your file, this may take a while." if type.nil?
170
213
  s3 = AWS::S3.new(res["s3_credentials"])
171
214
  bucket = s3.buckets[res["s3_bucket"]]
172
215
  obj = bucket.objects.with_prefix("#{res["s3_file_key"]}/")
216
+
173
217
  while(true)
174
218
  keys = obj.collect(&:key)
175
219
  if keys.length > 0 and keys.include?("#{res["s3_file_key"]}/manifest")
176
- display "Starting to write to file..."
220
+ display "Starting to write to file..." if type.nil?
177
221
  File.open(file, "w") do |f|
178
222
  obj.each do |o|
179
223
  if o.key == "#{res["s3_file_key"]}/manifest"
@@ -189,7 +233,12 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
189
233
  end
190
234
  end
191
235
  end
192
- display "pulled data from relation ##{id} to file #{file}"
236
+
237
+ if type == "json"
238
+ display {}.to_json
239
+ else
240
+ display "pulled data from relation ##{id} to file #{file}"
241
+ end
193
242
 
194
243
  end
195
244
  alias_command "rl:pull", "relations:pull"
@@ -198,30 +247,37 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
198
247
  #
199
248
  # pulls relation data to S3_BUCKET/FILE_KEY/part***.gz
200
249
  #
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)
250
+ # --cycle_id [cycle_id] # retrieve data generated for that cycle, only if this relation is associated with an app. (defaults to the last cycle)
251
+ # -t, --type TYPE # the output format types
202
252
  #
253
+
203
254
  def pull_to_s3
204
255
 
205
256
  id = options[:id] || shift_argument
206
- error "no id given" if id.nil?
257
+ type = options[:type]
258
+ error("no id given", type) if id.nil?
207
259
 
208
260
  user_s3_access_key = options[:s3_access_key] || shift_argument
209
261
  user_s3_secret = options[:s3_secret] || shift_argument
210
262
  user_s3_bucket = options[:s3_bucket] || shift_argument
211
263
  user_s3_file_key = options[:s3_file_key] || shift_argument
212
- error "no s3 access key provided" if user_s3_access_key.nil?
213
- error "no s3 secret provided" if user_s3_secret.nil?
214
- error "no s3 bucket provided" if user_s3_bucket.nil?
215
- error "no s3 file path specified" if user_s3_file_key.nil?
264
+ error("no s3 access key provided", type) if user_s3_access_key.nil?
265
+ error("no s3 access secret provided", type) if user_s3_secret.nil?
266
+ error("no s3 access bucket provided", type) if user_s3_bucket.nil?
267
+ error("no s3 file path provided", type) if user_s3_file_key.nil?
216
268
 
217
269
  s3_params = {:s3_access_key => user_s3_access_key, :s3_secret => user_s3_secret,
218
270
  :s3_bucket => user_s3_bucket, :s3_file_key => user_s3_file_key}
219
271
  s3_params[:cycle_id] = options[:cycle_id] if options[:cycle_id]
220
272
 
221
273
  res = self.api.data.pull_to_s3(id, s3_params)
222
- display "downloading relation data to s3://#{res["s3_bucket"]}/#{res["s3_file_key"]}/"
223
- display "if the relation is large, this may take a while, please check your s3 account after a few minutes"
224
274
 
275
+ if type == "json"
276
+ display {}.to_json
277
+ else
278
+ display "downloading relation data to s3://#{res["s3_bucket"]}/#{res["s3_file_key"]}/"
279
+ display "if the relation is large, this may take a while, please check your s3 account after a few minutes"
280
+ end
225
281
  end
226
282
  alias_command "relations:pull:s3", "relations:pull_to_s3"
227
283
  alias_command "rl:pull:s3", "relations:pull_to_s3"
@@ -231,23 +287,65 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
231
287
  #
232
288
  # shows a sample of the data in a relation. see 'zillabyte queries' for more elaborate functionality
233
289
  #
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)
290
+ # --cycle_id [cycle_id] # retrieve data generated for that cycle, only if this relation is associated with an app. (defaults to the last cycle)
235
291
  # --no_truncation # don't truncate long strings
236
- #
292
+ # --type TYPE # the type of the output
237
293
  def show
238
-
239
294
  name = options[:name] || shift_argument
295
+ type = options[:type]
240
296
  error "no id given" if name.nil?
241
297
 
242
- res = self.api.data.get(name, options)
243
-
298
+ # Initial request..
299
+ res = self.api.data.show(name, :post, options)
300
+
301
+ if res['job_id']
302
+ job_id = res['job_id']
303
+ options[:job_id] = job_id
304
+
305
+ # Poll until the results are ready...
306
+ start = Time.now.utc
307
+
308
+ display "Fetching your data, please wait..." if type.nil?
309
+
310
+ while(Time.now.utc < start + MAX_POLL_SECONDS) do
311
+
312
+ # Poll
313
+ res = self.api.data.show(name, :get, options)
314
+
315
+ # Status?
316
+ case res['status']
317
+ when 'completed'
318
+ if res['return']
319
+ res = res['return']
320
+ else
321
+ throw "something is wrong: #{res}"
322
+ end
323
+ # success! continue below
324
+ break
325
+ when 'running'
326
+ sleep(POLL_SLEEP)
327
+ # display ".", false
328
+ else
329
+ throw "unknown status: #{res}"
330
+ end
331
+
332
+ end
333
+ else
334
+ if res['error']
335
+ error(res['error_message'] || res['error'], type)
336
+ else
337
+ error("remote server error (r256)", type)
338
+ end
339
+ end
340
+
341
+ # We only reach here after polling is complete...
244
342
  if res["rows"].size > 0
245
343
  headings = []
246
344
  concrete_headings = res["rows"].first.keys
247
345
  concrete_headings.delete("id")
248
346
  concrete_headings.each do |ch|
249
347
  has_alias = false
250
- res['column_aliases'].each do |al|
348
+ (res['column_aliases'] || []).each do |al|
251
349
  if(al["concrete_name"] == ch)
252
350
  headings << al["alias"]
253
351
  has_alias = true
@@ -256,9 +354,8 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
256
354
  headings << ch if !has_alias
257
355
  end
258
356
 
259
- table = Terminal::Table.new :headings => headings
357
+ rows = []
260
358
  res["rows"].each do |obj|
261
-
262
359
  new_row = concrete_headings.map do |heading|
263
360
  if options[:no_truncation]
264
361
  obj[heading]
@@ -270,16 +367,16 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
270
367
  end
271
368
  end
272
369
  end
273
-
274
- table.add_row new_row
275
-
370
+ rows << new_row
276
371
  end
277
- display table.to_s
278
-
372
+
373
+ display TableOutputBuilder.build_table(headings, rows, type)
279
374
  else
280
-
281
- display "empty relation"
282
-
375
+ if type == "json"
376
+ display {}.to_json
377
+ else
378
+ display "empty relation"
379
+ end
283
380
  end
284
381
 
285
382
  end
@@ -289,8 +386,53 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
289
386
  private
290
387
 
291
388
 
389
+ def hash_relation_properties(schema, is_public, description, aliases, type)
390
+ if !aliases.nil?
391
+ aliases = aliases.strip.split(",").map{|x| x.strip}.uniq
392
+ aliases.each do |a|
393
+ if(!(a =~ /^[a-zA-Z0-9\_]+$/i))
394
+ error_message = "(\"#{a}\" contains illegal characters. Only letters, numbers and underscore are allowed in alias names."
395
+ error_message += "If you would like to give alias names to your relation, please enter them below. (comma separated, only letters, number and underscore allowed)"
396
+ error(error_message, type)
397
+ end
398
+ end
399
+ else
400
+ aliases = []
401
+ end
292
402
 
293
- def set_relation_properties(schema,is_public,description,aliases)
403
+ valid_types=["string", "integer", "float"]
404
+ meta_names=["id", "confidence", "since", "source"]
405
+
406
+ if description.nil?
407
+ description = ""
408
+ end
409
+
410
+ if schema.nil?
411
+ error("specify a schema", type)
412
+ end
413
+ schema = schema.split(",").map { |x| Hash[*x.split(":")] }
414
+ schema.each do |s|
415
+ cname = s.keys[0]
416
+ if(cname =~ /^v[0-9]+$/i or meta_names.member?(cname.downcase))
417
+ error("\"v[number]\", \"id\", \"confidence\", \"since\" and \"source\" are special names in Zillabyte. Please name your column name something else.", type)
418
+ end
419
+ ctype = s[cname]
420
+ unless valid_types.member?(ctype)
421
+ error("invalid type: #{ctype}", type)
422
+ next
423
+ end
424
+ end
425
+
426
+ if is_public.nil?
427
+ error("specify public or private using --public")
428
+ end
429
+
430
+ {:schema => schema, :public => is_public, :description => description, :aliases => aliases}
431
+ end
432
+
433
+
434
+
435
+ def get_relation_properties(schema, is_public, description, aliases)
294
436
  if aliases.nil?
295
437
  display "If you would like to give alias names to your relation, please enter them below. (comma separated, only letters, number and underscore allowed)"
296
438
  aliases = ask.strip
@@ -371,7 +513,7 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
371
513
  {:schema => schema, :public => is_public, :description => description, :aliases => aliases}
372
514
  end
373
515
 
374
- def sanity_check_file(file,type,dataset)
516
+ def sanity_check_file(file, filetype, dataset, type = nil)
375
517
  rows = []
376
518
 
377
519
  n_columns = dataset["columns"].size
@@ -387,27 +529,33 @@ class Zillabyte::Command::Relations < Zillabyte::Command::Base
387
529
  end
388
530
  end
389
531
 
390
- case type
532
+ case filetype
391
533
  when "csv"
392
- CSV.foreach(file) do |row|
393
- if row.size != n_columns
394
- error "relation expect #{n_columns} column(s). Found a row with #{row.size}::\n #{row}"
395
- end
396
- float_cols.each do |i|
397
- if(!(row[i] =~ /^[+-]?(\d+(.\d+)?)$/))
398
- error "column #{i+1} should be a FLOAT in row::\n #{row}"
534
+ begin
535
+ CSV.foreach(file) do |row|
536
+ if row.size != n_columns
537
+ error("relation expect #{n_columns} column(s). Found a row with #{row.size}::\n #{row}", type)
399
538
  end
400
- end
401
- int_cols.each do |i|
402
- if(!(row[i] =~ /^[+-]?(\d+)$/))
403
- error "column #{i+1} should be an INTEGER in row::\n #{row}"
539
+
540
+ float_cols.each do |i|
541
+ if (!(row[i] =~ /^[+-]?(\d+(.\d+)?)$/))
542
+ error("column #{i+1} should be an INTEGER in row ::\n #{row}", type)
543
+ end
544
+ end
545
+
546
+ int_cols.each do |i|
547
+ if (!(row[i] =~ /^[+-]?(\d+)$/))
548
+ error("column #{i+1} should be an INTEGER in row #{row}::\n #{row}", type)
549
+ end
404
550
  end
551
+ rows << row
405
552
  end
406
- rows << row
553
+ rescue Exception => e
554
+ error("unable to parse csv", type)
407
555
  end
408
556
 
409
557
  else
410
- error "unsupported type: #{type}"
558
+ error "unsupported type: #{filetype}"
411
559
 
412
560
  end
413
561
  rows
@@ -34,4 +34,4 @@
34
34
  #
35
35
  #
36
36
  #
37
- # end
37
+ # end
@@ -15,6 +15,11 @@ function exec(controller, tuple) {
15
15
  }
16
16
 
17
17
  zillabyte.simple_function({
18
+ /**
19
+ * This specifies the function's name and is mandatory.
20
+ */
21
+ name: "simple_function",
22
+
18
23
  /**
19
24
  * This directive instructs zillabyte to give your function every
20
25
  * web page in our known universe. Your function will have access
@@ -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_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
+ )
@@ -12,6 +12,9 @@ def execute(controller, tup):
12
12
  return
13
13
 
14
14
  zillabyte.simple_function(\
15
+ # This specifies the function's name and is mandatory.
16
+ name = "simple_function", \
17
+
15
18
  # This directive instructs zillabyte to give your function every
16
19
  # web page in our known universe. Your function will have access
17
20
  # to two fields: URL and HTML
@@ -1,16 +1,16 @@
1
1
  require 'zillabyte'
2
2
 
3
- Zillabyte.simple_function do
3
+ Zillabyte.simple_app do
4
4
 
5
- # This specifies the function's name and is mandatory.
6
- name "simple_function"
5
+ # This specifies the app's name and is mandatory.
6
+ name "simple_app"
7
7
 
8
- # This directive instructs zillabyte to give your function every
9
- # web page in our known universe. Your function will have access
8
+ # This directive instructs zillabyte to give your app every
9
+ # web page in our known universe. Your app will have access
10
10
  # to two fields: URL and HTML
11
11
  matches "select * from web_pages"
12
12
 
13
- # This directive tells Zillabyte what kind of data your function
13
+ # This directive tells Zillabyte what kind of data your app
14
14
  # produces. In this case, we're saying we will emit a tuple that
15
15
  # is one-column wide and contains the field 'URL'
16
16
  emits [
@@ -1,2 +1,2 @@
1
1
  language: ruby
2
- script: simple_function.rb
2
+ script: simple_app.rb
@@ -8,4 +8,4 @@ class Zillabyte::Command::Version < Zillabyte::Command::Base
8
8
  display "Zillabyte CLI Version #{Zillabyte::CLI::VERSION}"
9
9
  end
10
10
 
11
- end
11
+ end
@@ -83,4 +83,4 @@
83
83
  #
84
84
  #
85
85
  #
86
- # end
86
+ # end
@@ -208,9 +208,17 @@ module Zillabyte
208
208
  object, method = prepare_run(cmd, arguments.dup)
209
209
  object.send(method)
210
210
  rescue Excon::Errors::SocketError => e
211
- error "remote server error: #{e.message}"
211
+ if ENV['BUBBLE_EXCEPTIONS']
212
+ raise e
213
+ else
214
+ error "remote server error: #{e.message}"
215
+ end
212
216
  rescue Errno::ECONNREFUSED => e
213
- error "remote server error: #{e.message}"
217
+ if ENV['BUBBLE_EXCEPTIONS']
218
+ raise e
219
+ else
220
+ error "remote server error: #{e.message}"
221
+ end
214
222
  end
215
223
  end
216
224
 
@@ -1,5 +1,5 @@
1
1
  module Zillabyte::Common
2
- class Progress
2
+ class Session
3
3
 
4
4
  def update(*args)
5
5
  display(*args)