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.
- checksums.yaml +15 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +29 -0
- data/bin/zillabyte +18 -0
- data/lib/zillabyte/api/base.rb +11 -0
- data/lib/zillabyte/api/data.rb +126 -0
- data/lib/zillabyte/api/flows.rb +239 -0
- data/lib/zillabyte/api/locks.rb +4 -0
- data/lib/zillabyte/api/logs.rb +32 -0
- data/lib/zillabyte/api/metrics.rb +48 -0
- data/lib/zillabyte/api/queries.rb +58 -0
- data/lib/zillabyte/api/semantic_tags.rb +24 -0
- data/lib/zillabyte/api/settings.rb +8 -0
- data/lib/zillabyte/api/sources.rb +28 -0
- data/lib/zillabyte/api/zillalogs.rb +66 -0
- data/lib/zillabyte/api.rb +170 -0
- data/lib/zillabyte/auth.rb +155 -0
- data/lib/zillabyte/cli/auth.rb +33 -0
- data/lib/zillabyte/cli/base.rb +161 -0
- data/lib/zillabyte/cli/config.rb +63 -0
- data/lib/zillabyte/cli/counters.rb +61 -0
- data/lib/zillabyte/cli/flows.rb +702 -0
- data/lib/zillabyte/cli/help.rb +137 -0
- data/lib/zillabyte/cli/helpers/data_schema_builder.rb +3 -0
- data/lib/zillabyte/cli/host.rb +21 -0
- data/lib/zillabyte/cli/logs.rb +118 -0
- data/lib/zillabyte/cli/query.rb +172 -0
- data/lib/zillabyte/cli/relations.rb +326 -0
- data/lib/zillabyte/cli/sources.rb +37 -0
- data/lib/zillabyte/cli/templates/js/simple_function.js +33 -0
- data/lib/zillabyte/cli/templates/js/zillabyte.conf.yaml +2 -0
- data/lib/zillabyte/cli/templates/python/requirements.txt +7 -0
- data/lib/zillabyte/cli/templates/python/simple_function.py +27 -0
- data/lib/zillabyte/cli/templates/python/zillabyte.conf.yaml +4 -0
- data/lib/zillabyte/cli/templates/ruby/Gemfile +3 -0
- data/lib/zillabyte/cli/templates/ruby/simple_function.rb +36 -0
- data/lib/zillabyte/cli/templates/ruby/zillabyte.conf.yaml +2 -0
- data/lib/zillabyte/cli/version.rb +11 -0
- data/lib/zillabyte/cli/zillalogs.rb +86 -0
- data/lib/zillabyte/cli.rb +37 -0
- data/lib/zillabyte/command.rb +254 -0
- data/lib/zillabyte/common/progress.rb +17 -0
- data/lib/zillabyte/common/tar.rb +102 -0
- data/lib/zillabyte/common.rb +13 -0
- data/lib/zillabyte/helpers.rb +49 -0
- data/lib/zillabyte/queries.rb +39 -0
- data/lib/zillabyte-cli/version.rb +5 -0
- data/lib/zillabyte-cli.rb +5 -0
- data/zillabyte-cli.gemspec +42 -0
- data/zillabyte_emails.csv +1 -0
- data/zillaconf.json +3 -0
- 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,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,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,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
|
+
|