zillabyte-cli 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,9 @@ require "zillabyte/runner/app_runner"
15
15
  # HIDDEN: superclass for components and apps
16
16
  #
17
17
  class Zillabyte::Command::Flows < Zillabyte::Command::Base
18
+
19
+ MAX_POLL_SECONDS = 60 * 15
20
+ POLL_SLEEP = 2.0
18
21
 
19
22
  # flows:status [DIR]
20
23
  #
@@ -95,7 +98,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
95
98
  if type == "json"
96
99
  display "{}"
97
100
  else
98
- display "flow ##{res['id']} pulled to #{dir}"
101
+ display "Flow ##{res['id']} pulled to #{dir}"
99
102
  end
100
103
  end
101
104
 
@@ -333,12 +336,12 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
333
336
  # --output_type OUTPUT_TYPE # specify an output type i.e. json
334
337
  #
335
338
  def delete
336
- flow_id = options[:id] || shift_argument
339
+ id = options[:id] || shift_argument
337
340
 
338
- if flow_id.nil?
339
- flow_id = read_name_from_conf(options)
341
+ if id.nil?
342
+ id = read_name_from_conf(options)
340
343
  options[:is_name] = true
341
- elsif !(flow_id =~ /^\d*$/)
344
+ elsif !(id =~ /^\d*$/)
342
345
  options[:is_name] = true
343
346
  end
344
347
  forced = options[:force]
@@ -362,12 +365,48 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
362
365
  confirmed = forced || confirm == "yes"
363
366
 
364
367
  if confirmed
365
- response = api.flows.delete(flow_id, options)
366
- if type == "json"
367
- display "{}"
368
+ display "Destroying flow ##{id}...please wait..." if type.nil?
369
+ response = api.flows.create_delete(id, options)
370
+
371
+ if response["job_id"]
372
+ options[:job_id] = response["job_id"]
373
+ flow_id = response["flow_id"]
374
+ options.delete :is_name
375
+
376
+ start = Time.now.utc
377
+ display "Destroy request sent. Please wait..." if type.nil?
378
+
379
+ while(Time.now.utc < start + MAX_POLL_SECONDS) do
380
+
381
+ # Poll
382
+ res = self.api.flows.poll_delete(flow_id, options)
383
+
384
+ case res['status']
385
+ when 'completed'
386
+ if res['return']
387
+ if type == "json"
388
+ display "{}"
389
+ else
390
+ display "Flow ##{id} destroyed"
391
+ end
392
+ else
393
+ throw "something is wrong: #{res}"
394
+ end
395
+ # success! continue below
396
+ break
397
+ when 'running'
398
+ sleep(POLL_SLEEP)
399
+ else
400
+ throw "unknown status: #{res}"
401
+ end
402
+
403
+ end
404
+ elsif response["error"]
405
+ error(response["error"], type)
368
406
  else
369
- display response["body"]
407
+ error("remote server error (f413)", type)
370
408
  end
409
+
371
410
  end
372
411
 
373
412
  end
@@ -428,7 +467,7 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
428
467
  # --input INPUT_FILE # writes sink output to a file
429
468
  # --output OUTPUT_FILE # writes sink output to a file
430
469
  # --cycles CYCLES # number of cycles to emit (default 1)
431
- # --directory DIR # app directory
470
+ # --directory DIR # flow directory
432
471
  # -i, --interactive # allow user to control input and read output
433
472
  #
434
473
  def test
@@ -440,11 +479,23 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
440
479
  end
441
480
  options[:directory] = dir
442
481
 
482
+ # Get the flow_type
483
+ meta = Zillabyte::API::Flows.get_rich_meta_info_from_script(dir, session, {:test => true})
484
+ if meta.nil? || meta["nodes"].nil?
485
+ error "this is not a valid zillabyte app directory"
486
+ exit
487
+ end
443
488
 
444
- # Get the class
445
- flow_class = read_class_from_conf(options)
489
+ # Check that multilang version is atleast 0.1.0
490
+ version = meta["multilang_version"] || "0.0.0"
491
+ version_arr = version.split('.').map {|v| v.to_i}
492
+ if version_arr.empty? || (version_arr[0] == 0 && version_arr[1] < 1)
493
+ display "The version of zillabyte used in your application is outdated."
494
+ display "Please use upgrade your zillabyte gem via 'bundle update zillabyte; gem cleanup zillabyte'"
495
+ return
496
+ end
446
497
 
447
- case flow_class
498
+ case meta["flow_type"]
448
499
  when "component"
449
500
  runner = Zillabyte::Runner::ComponentRunner.new()
450
501
  when "app"
@@ -455,12 +506,76 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
455
506
  end
456
507
 
457
508
  # Start Runner
458
- runner.run(dir, self, options)
509
+ runner.run(meta, dir, self, options)
459
510
 
460
511
  end
461
512
  alias_command "test", "flows:test"
462
513
 
463
514
 
515
+ # flows:kill ID
516
+ #
517
+ # kills the given flow
518
+ #
519
+ # --config CONFIG_FILE # use the given config file
520
+ # --output_type OUTPUT_TYPE # specify an output type i.e. json
521
+ #
522
+ def kill
523
+ id = options[:id] || shift_argument
524
+ type = options[:output_type]
525
+
526
+ if id.nil?
527
+ id = read_name_from_conf(options)
528
+ options[:is_name] = true
529
+ elsif !(id =~ /^\d*$/)
530
+ options[:is_name] = true
531
+ end
532
+
533
+ display "Killing flow ##{id}...please wait..." if type.nil?
534
+ response = api.flows.create_kill(id, options)
535
+
536
+ if response["job_id"]
537
+ options[:job_id] = response["job_id"]
538
+ flow_id = response["flow_id"]
539
+ options.delete :is_name
540
+
541
+ start = Time.now.utc
542
+ display "Kill request sent. Please wait..." if type.nil?
543
+
544
+ while(Time.now.utc < start + MAX_POLL_SECONDS) do
545
+
546
+ # Poll
547
+ res = self.api.flows.poll_kill(flow_id, options)
548
+
549
+ case res['status']
550
+ when 'completed'
551
+ if res['return']
552
+ if type == "json"
553
+ display "{}"
554
+ else
555
+ display "Flow ##{id} killed"
556
+ end
557
+ else
558
+ throw "something is wrong: #{res}"
559
+ end
560
+ # success! continue below
561
+ break
562
+ when 'running'
563
+ sleep(POLL_SLEEP)
564
+ # display ".", false
565
+ else
566
+ throw "unknown status: #{res}"
567
+ end
568
+
569
+ end
570
+ elsif response["error"]
571
+ error(response["error"], type)
572
+ else
573
+ error("remote server error (f569)", type)
574
+ end
575
+
576
+ end
577
+
578
+
464
579
  private
465
580
 
466
581
  #
@@ -506,13 +621,6 @@ class Zillabyte::Command::Flows < Zillabyte::Command::Base
506
621
  hash["name"]
507
622
  end
508
623
 
509
- def read_class_from_conf(options = {})
510
- type = options[:output_type]
511
- hash = Zillabyte::API::Apps.get_rich_meta_info_from_script Dir.pwd, options
512
- error("No id given and current directory does not contain a valid Zillabyte configuration file. Please specify a flow id or run command from the directory containing the flow.",type) if hash["error"]
513
- hash["class"]
514
- end
515
-
516
624
  def fetch_logs(hash, operation=nil, exit_on=nil)
517
625
  def color_for(operation_name)
518
626
  @color_map[operation_name] ||= @all_colors[ @color_map.size % @all_colors.size ]
@@ -22,17 +22,14 @@ class Zillabyte::Command::Git < Zillabyte::Command::Base
22
22
  # ! Git remote zillabyte already exists
23
23
  #
24
24
  def remote
25
+
25
26
  git_options = args.join(" ")
26
27
  remote = options[:remote] || 'zillabyte'
27
- app_name = options[:name] || File.basename(Dir.pwd)
28
-
29
- if git('remote').split("\n").include?(remote)
30
- # already exists.. remove it.
31
- git("remote remove #{remote}")
32
- end
33
-
34
- git_url = "git@#{Zillabyte::Auth.git_host}:#{Zillabyte::Auth.user}/#{app_name}"
35
- create_git_remote(remote, git_url)
28
+ name = options[:name] || get_flow_name()
29
+ error "could not infer app name" if name.nil?
30
+
31
+ add_git_remote(name, remote)
32
+
36
33
  end
37
34
 
38
35
  end
@@ -0,0 +1,38 @@
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["html"].indexOf("hello world") !== -1) {
13
+ controller.emit("has_hello_world",{"url":tuple["url"]});
14
+ }
15
+ }
16
+
17
+ zillabyte.simple_function({
18
+ /**
19
+ * This specifies the function's name and is mandatory.
20
+ */
21
+ name: "simple_function",
22
+
23
+ /**
24
+ * This directive instructs zillabyte to give your function every
25
+ * web page in our known universe. Your function will have access
26
+ * to two fields: URL and HTML
27
+ */
28
+ matches: "select * from web_pages",
29
+
30
+ /**
31
+ * This directive tells Zillabyte what kind of data your function
32
+ * produces. In this case, we're saying we will emit a tuple that
33
+ * is one-column wide and contains the field 'URL'
34
+ */
35
+ emits: [["has_hello_world", [{"url":"string"}]]],
36
+ prepare: prep,
37
+ execute: exec
38
+ });
@@ -0,0 +1,2 @@
1
+ language: js
2
+ script: simple_function.js
@@ -0,0 +1,17 @@
1
+ import zillabyte
2
+
3
+ # This function takes a tuple and emits its url field
4
+ def execute(controller, tuple):
5
+ controller.emit("urls",{"url":tuple["url"]})
6
+
7
+ component = zillabyte.component(name = "hello_world")
8
+
9
+
10
+ # Declare the schema for inputs to the component
11
+ input_stream = component.inputs(name = "url_stream", fields = [{"url" : "string", "html" : "string"}])
12
+
13
+ # Extract urls from the input_stream
14
+ url_stream = input_stream.each(execute = execute)
15
+
16
+ # Declare the output schema of the component
17
+ url_stream.outputs(name = "urls", fields = [{"url":"string"}])
@@ -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,4 @@
1
+ language: python
2
+ script: component.py
3
+ ignore_files:
4
+ - ./vEnv
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "zillabyte"
@@ -0,0 +1,20 @@
1
+ require 'zillabyte'
2
+
3
+ comp = Zillabyte.component("<%= name %>")
4
+
5
+ # Declare the schema for inputs to the component
6
+ url_stream = comp.inputs do
7
+ name "urls"
8
+ field "url", :string
9
+ end
10
+
11
+ # This component strips HTTP and HTTPS prefixes
12
+ suffix_streams = url_stream.each do |tuple|
13
+ emit :urls => tuple["url"].gsub(/^http(s)?:\/\//,"")
14
+ end
15
+
16
+ # Declare the output schema for the component
17
+ suffix_streams.outputs do
18
+ name "suffix_urls"
19
+ field "urls", :string
20
+ end
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ script: component.rb
3
+ flow_type: component
4
+
5
+
@@ -66,7 +66,7 @@ module Zillabyte
66
66
  return if git('remote').split("\n").include?(remote)
67
67
  return unless File.exists?(".git")
68
68
  git "remote add #{remote} #{url}"
69
- display "Git remote #{remote} added"
69
+ display "git remote #{remote} added"
70
70
  end
71
71
 
72
72
 
@@ -113,6 +113,46 @@ module Zillabyte
113
113
  remote == "" ? nil : remote
114
114
  end
115
115
 
116
+
117
+ def add_git_remote(name, remote = "zillabyte")
118
+
119
+ remotes = {}
120
+ remotes[remote] = Zillabyte::Auth.git_host
121
+
122
+ if ENV["ZILLABYTE_EXTRA_GIT_REMOTES"]
123
+ # This is for dev purposes -- auto init various git env endpoints
124
+ JSON.parse(ENV["ZILLABYTE_EXTRA_GIT_REMOTES"]).each_pair do |remote, host|
125
+ remotes[remote] = host
126
+ end
127
+ end
128
+
129
+ # Maybe initialize a git directory at the app root...
130
+ if File.exists?(File.join(Dir.pwd, ".git")) == false && File.exists?(File.join(Dir.pwd, "zillabyte.conf.yaml"))
131
+ git("init .")
132
+ end
133
+
134
+ # Install each git remote
135
+ remotes.each_pair do |remote, host|
136
+
137
+ if git('remote').split("\n").include?(remote)
138
+ # already exists.. remove it.
139
+ git("remote remove #{remote}")
140
+ end
141
+
142
+ git_url = "git@#{host}:#{Zillabyte::Auth.user}/#{name}"
143
+ create_git_remote(remote, git_url)
144
+
145
+ end
146
+
147
+ end
148
+
149
+
150
+ def get_flow_name(dir = Dir.pwd)
151
+ meta = Zillabyte::API::Flows.get_rich_meta_info_from_script(dir)
152
+ return meta["name"] if meta
153
+ return nil
154
+ end
155
+
116
156
 
117
157
  end
118
158
  end
@@ -8,35 +8,20 @@ require 'thread'
8
8
  class Zillabyte::Runner::AppRunner < Zillabyte::Command::Base
9
9
  include Zillabyte::Helpers
10
10
 
11
- def run (dir = Dir.pwd, session = nil, options = {})
11
+ def run (meta, dir = Dir.pwd, session = nil, options = {})
12
12
 
13
- if session.nil?
13
+ if meta.nil? or session.nil?
14
14
  return
15
15
  end
16
16
 
17
17
  @session = session
18
+
18
19
  @colors = {}
19
20
  output = options[:output]
20
21
  otype = options[:output_type]
21
22
  interactive = options[:interactive]
22
23
  cycles = (options[:cycles] || "1").to_i
23
24
 
24
- # Get app metadata
25
- meta = Zillabyte::API::Flows.get_rich_meta_info_from_script(dir, @session, {:test => true})
26
- if meta.nil? || meta["nodes"].nil?
27
- error "this is not a valid zillabyte app directory"
28
- exit
29
- end
30
-
31
- # Check that multilang version is atleast 0.1.0
32
- version = meta["multilang_version"] || "0.0.0"
33
- version_arr = version.split('.').map {|v| v.to_i}
34
- if version_arr.empty? || (version_arr[0] == 0 && version_arr[1] < 1)
35
- display "The version of zillabyte used in your application is outdated."
36
- display "Please use upgrade your zillabyte gem via 'bundle update zillabyte; gem cleanup zillabyte'"
37
- return
38
- end
39
-
40
25
  # Show the user what we know about their app...
41
26
  display "inferring your app details..."
42
27
  describe_app(meta)
@@ -151,7 +136,11 @@ class Zillabyte::Runner::AppRunner < Zillabyte::Command::Base
151
136
  end
152
137
 
153
138
  if interactive
139
+ display "To view results: Enter 'end' "
140
+ display "To exit the test: Enter 'Ctrl-C' "
154
141
  display ""
142
+
143
+
155
144
  while true
156
145
  display "Enter an input tuple in JSON format i.e.{ \"url\" : \"foo.com\", \"html\" : \"bar.html\" }"
157
146
  msg = ask
@@ -223,4 +212,4 @@ class Zillabyte::Runner::AppRunner < Zillabyte::Command::Base
223
212
  end
224
213
 
225
214
 
226
- end
215
+ end