mybot 0.0.2 → 0.0.3

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.
@@ -0,0 +1,41 @@
1
+ module Mybot
2
+ module Libs
3
+ def use(lib)
4
+ if lib.is_a?(Array)
5
+ lib.each do |l|
6
+ _use(l)
7
+ end
8
+ else
9
+ _use(lib)
10
+ end
11
+ end
12
+
13
+ def _use(lib)
14
+ lib_name = lib.split("/").last
15
+ lib_file = File.join(LIB_PATH, "#{lib}.rb")
16
+
17
+ unless File.exists?(lib_file)
18
+ error "cannot load lib '#{lib_file}'"
19
+ end
20
+
21
+ require lib_file
22
+ const = lib.split("/").map { |x| x.capitalize }.join("::")
23
+ klass = Kernel.qualified_const_get(const)
24
+
25
+ if klass.instance_method(:initialize).arity == 1
26
+ @libs[lib_name.to_sym] ||= klass.new(self)
27
+ else
28
+ warning "#{lib_name.capitalize} library constructor should " +
29
+ "take one argument"
30
+ end
31
+ end
32
+
33
+ def method_missing(name, *args, &block)
34
+ if @libs[name.to_sym]
35
+ @libs[name.to_sym]
36
+ else
37
+ error "no such library loaded: #{name}"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -3,23 +3,27 @@ require "colored"
3
3
  module Mybot
4
4
  module Messages
5
5
  def info(msg)
6
- info_format = "INFO".blue.bold
6
+ info_format = "INFO"
7
+ info_format = info_format.blue.bold if Fmt.use_color
7
8
  puts "#{info_format} #{msg}"
8
9
  end
9
10
 
10
11
  def warning(msg)
11
- warning_format = "WARNING".magenta.bold
12
+ warning_format = "WARNING"
13
+ warning_format = warning_format.magenta.bold if Fmt.use_color
12
14
  puts "#{warning_format} #{msg}"
13
15
  end
14
16
 
15
17
  def error(msg)
16
- error_format = "ERROR".red.bold
18
+ error_format = "ERROR"
19
+ error_format = error_format.red.bold if Fmt.use_color
17
20
  puts "#{error_format} #{msg}"
18
21
  abort
19
22
  end
20
23
 
21
24
  def task_info(name)
22
- task_format = "TASK".green.bold
25
+ task_format = "TASK"
26
+ task_format = task_format.green.bold if Fmt.use_color
23
27
  puts "#{task_format} #{name}"
24
28
  end
25
29
  end
@@ -4,6 +4,8 @@ require "net/sftp"
4
4
  module Mybot
5
5
  class Node
6
6
  include Messages
7
+ include Libs
8
+
7
9
  attr_accessor :host, :user, :options, :ssh, :sftp, :fmt
8
10
 
9
11
  def initialize(host, user, options = {})
@@ -20,50 +22,12 @@ module Mybot
20
22
  @sftp ||= Net::SFTP.start(@host, @user, @options)
21
23
  end
22
24
 
23
- def use(lib)
24
- if lib.is_a?(Array)
25
- lib.each do |l|
26
- _use(l)
27
- end
28
- else
29
- _use(lib)
30
- end
31
- end
32
-
33
- def _use(lib)
34
- lib_name = lib.split("/").last
35
- lib_file = File.join(LIB_PATH, "#{lib}.rb")
36
-
37
- unless File.exists?(lib_file)
38
- error "cannot load lib '#{lib_file}'"
39
- end
40
-
41
- require lib_file
42
- const = lib.split("/").map { |x| x.capitalize }.join("::")
43
- klass = Kernel.qualified_const_get(const)
44
-
45
- if klass.instance_method(:initialize).arity == 1
46
- @libs[lib_name.to_sym] ||= klass.new(self)
47
- else
48
- warning "#{lib_name.capitalize} library constructor should " +
49
- "take one argument"
50
- end
51
- end
52
-
53
- def method_missing(name, *args, &block)
54
- if @libs[name.to_sym]
55
- @libs[name.to_sym]
56
- else
57
- error "no such library loaded: #{name}"
58
- end
59
- end
60
-
61
25
  def run(options, &block)
62
26
  error "cmd not specified" unless options[:cmd]
63
27
 
64
28
  command = Command.new(self)
65
29
  yield command if block_given?
66
-
30
+
67
31
  ssh.open_channel do |ch|
68
32
  ch.request_pty do |ch, ok|
69
33
  @fmt.error "cannot request pty" unless ok
@@ -71,27 +35,20 @@ module Mybot
71
35
 
72
36
  command.channel = ch
73
37
 
74
- if options[:env]
75
- env = []
76
- options[:env].each do |k, v|
77
- env << "#{k}='#{v}'"
78
- end
79
- options[:cmd] = "#{env.join(" ")} #{options[:cmd]}"
80
- end
38
+ inject_env(options)
81
39
 
82
40
  if options[:sudo]
83
41
  options[:cmd] = "sudo #{options[:cmd]}"
84
42
  command.handle_sudo
85
43
  end
86
44
 
87
- if options[:cwd]
88
- options[:cmd] = "cd #{options[:cwd]} && #{options[:cmd]}"
89
- end
45
+ prepend_cwd(options)
46
+ prepend_sources(options)
90
47
 
91
48
  @fmt.run(options[:cmd])
92
49
 
93
50
  ch.exec options[:cmd] do |ch, ok|
94
- @fmt.error "run: cannot exec #{options[:cmd]}" unless ok
51
+ @fmt.error "cannot exec #{options[:cmd]}" unless ok
95
52
 
96
53
  ch.on_data do |ch, data|
97
54
  command.handle_stdout(data)
@@ -102,17 +59,51 @@ module Mybot
102
59
  end
103
60
 
104
61
  ch.on_request("exit-status") do |ch, data|
105
- command.exit_status = data.read_long
62
+ command.result.exit_status = data.read_long
106
63
  end
107
64
 
108
65
  ch.on_close do |ch|
109
- return command.handle_exit
66
+ #
110
67
  end
111
68
  end
112
69
  end
113
70
 
114
71
  ssh.loop
115
- return command.stdout_all
72
+ return command.result
73
+ end
74
+
75
+ private
76
+
77
+ def inject_env(options)
78
+ if options[:env]
79
+ env = []
80
+ options[:env].each do |k, v|
81
+ env << "#{k}='#{v}'"
82
+ end
83
+ options[:cmd] = "#{env.join(" ")} #{options[:cmd]}"
84
+ end
85
+ end
86
+
87
+ def prepend_cwd(options)
88
+ if options[:cwd]
89
+ options[:cmd] = "cd #{options[:cwd]} && #{options[:cmd]}"
90
+ end
91
+ end
92
+
93
+ def prepend_sources(options)
94
+ sources = [
95
+ File.join("~", ".bashrc"),
96
+ File.join("~", ".bash_profile"),
97
+ File.join("~", ".profile")
98
+ ].map { |f| File.expand_path(f) }
99
+
100
+ sources.reject! { |f| !File.exists?(f) }
101
+
102
+ prefix = sources.map do |s|
103
+ "source #{File.expand_path(s)}"
104
+ end.join(" && ")
105
+
106
+ options[:cmd] = "#{prefix} && #{options[:cmd]}"
116
107
  end
117
108
  end
118
109
  end
@@ -4,10 +4,10 @@ module Mybot
4
4
 
5
5
  def recipes
6
6
  @recipes ||= (
7
+ Dir["Botfile"] +
7
8
  Dir[File.join(GEM_PATH, "Botfile")] +
8
9
  Dir[File.join(MYBOT_PATH, "recipes", "**", "*.rb")].flatten +
9
- Dir[File.join(".mybot", "**", "*.rb")].flatten +
10
- Dir["Botfile"]
10
+ Dir[File.join(".mybot", "**", "*.rb")].flatten
11
11
  ).reject { |f| !File.exists?(f) }
12
12
  end
13
13
 
@@ -0,0 +1,26 @@
1
+ module Mybot
2
+ class Result
3
+ attr_accessor :exit_status
4
+ attr_writer :stdout, :stderr
5
+
6
+ def initialize
7
+ @stdout = @stderr = ""
8
+ @exit_status = -1
9
+ end
10
+
11
+ def stdout
12
+ filter(@stdout)
13
+ end
14
+
15
+ def stderr
16
+ filter(@stderr)
17
+ end
18
+
19
+ private
20
+
21
+ def filter(data)
22
+ data.gsub(/\[sudo\]\ password\ for\ [a-zA-Z0-9_].+\:/, "")
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ module Mybot
2
+ module Utils
3
+ def lib_to_path(lib)
4
+ lib.split("::").map{ |l| l.downcase }.join("/")
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module Mybot
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency "colored"
24
24
  spec.add_dependency "net-ssh"
25
25
  spec.add_dependency "net-sftp"
26
+ spec.add_dependency "listen"
26
27
  end
@@ -14,7 +14,7 @@ module Core
14
14
  elsif options[:dir]
15
15
  options[:cmd] = "test -e #{options[:dir]} && echo EXISTS"
16
16
  end
17
- @node.run(options).include?("EXISTS") ? true : false
17
+ @node.run(options).stdout.include?("EXISTS") ? true : false
18
18
  end
19
19
 
20
20
  def create(options = {})
@@ -23,13 +23,8 @@ module Core
23
23
  end
24
24
 
25
25
  if options[:file]
26
- options[:cmd] = "mktemp /tmp/mybot.XXXXX"
27
-
28
- # do not use sudo when creating tmp file to be able to move file
29
- sudo = options[:sudo]
30
- options[:sudo] = false
31
- tmp = @node.run(options)
32
- options[:sudo] = sudo
26
+ options[:pattern] = "/tmp/mybot.XXXXX"
27
+ tmp = mktemp(options)
33
28
 
34
29
  options[:content] ||= ""
35
30
  @node.sftp.file.open(tmp, "w") { |f| f.write options[:content] }
@@ -41,6 +36,17 @@ module Core
41
36
  end
42
37
  end
43
38
 
39
+ def mktemp(options = {})
40
+ error "pattern required" unless options[:pattern]
41
+
42
+ options[:cmd] = "mktemp #{options[:pattern]}"
43
+ sudo = options[:sudo]
44
+ options[:sudo] = false
45
+ tmp = @node.run(options).stdout
46
+ options[:sudo] = sudo
47
+ tmp.strip
48
+ end
49
+
44
50
  def remove(options = {})
45
51
  unless options[:file] || options[:dir]
46
52
  error "file or dir is required"
@@ -64,7 +70,7 @@ module Core
64
70
  @node.fmt.error "read: file '#{options[:file]}' does not exists"
65
71
  return ""
66
72
  end
67
- end
73
+ end.stdout
68
74
  end
69
75
 
70
76
  def upload(options = {})
@@ -0,0 +1,31 @@
1
+ module Core
2
+ module Osx
3
+ class Rails < Mybot::Lib
4
+ def initialize(node)
5
+ @node = node
6
+ @node.use [
7
+ "core/fs",
8
+ "core/osx/git"
9
+ ]
10
+ end
11
+
12
+ def prepare_release(options = {})
13
+ error "repo is required" unless options[:repo]
14
+ error "release is required" unless options[:release]
15
+
16
+ options[:dir] = "/tmp/#{options[:release]}"
17
+ @node.fs.remove(options)
18
+
19
+ options[:file] = "/tmp/#{options[:release]}.tar.gz"
20
+ @node.fs.remove(options)
21
+
22
+ options[:dest] = "/tmp/#{options[:release]}"
23
+ @node.git.clone(options)
24
+
25
+ options[:from] = "/tmp/#{options[:release]}"
26
+ options[:to] = "/tmp/#{options[:release]}.tar.gz"
27
+ @node.fs.compress(options)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ module Core
2
+ module Osx
3
+ class Static < Mybot::Lib
4
+ def initialize(node)
5
+ @node = node
6
+ @node.use [
7
+ "core/fs",
8
+ "core/osx/git"
9
+ ]
10
+ end
11
+
12
+ def prepare_release(options = {})
13
+ error "repo is required" unless options[:repo]
14
+ error "release is required" unless options[:release]
15
+
16
+ options[:dir] = "/tmp/#{options[:release]}"
17
+ @node.fs.remove(options)
18
+
19
+ options[:file] = "/tmp/#{options[:release]}.tar.gz"
20
+ @node.fs.remove(options)
21
+
22
+ options[:dest] = "/tmp/#{options[:release]}"
23
+ @node.git.clone(options)
24
+
25
+ options[:from] = "/tmp/#{options[:release]}"
26
+ options[:to] = "/tmp/#{options[:release]}.tar.gz"
27
+ @node.fs.compress(options)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -9,7 +9,15 @@ module Core
9
9
 
10
10
  def update(options = {})
11
11
  options[:cmd] = "#{DF} apt-get update"
12
- @node.run(options)
12
+ @node.run(options) do |cmd|
13
+ cmd.on "dpkg was interrupted" do
14
+ dpkg_reconfigure(options)
15
+ end
16
+
17
+ cmd.on "Could not get lock" do
18
+ error "Cannot update"
19
+ end
20
+ end
13
21
  end
14
22
 
15
23
  def upgrade(options = {})
@@ -26,7 +34,11 @@ module Core
26
34
  error "pkg not specified" unless options[:pkg]
27
35
 
28
36
  options[:cmd] = "#{DF} apt-get install -y #{options[:pkg]}"
29
- @node.run(options)
37
+ @node.run(options) do |cmd|
38
+ cmd.on "dpkg was interrupted" do
39
+ dpkg_reconfigure(options)
40
+ end
41
+ end
30
42
  end
31
43
 
32
44
  def remove(options = {})
@@ -35,6 +47,11 @@ module Core
35
47
  options[:cmd] = "#{DF} apt-get --purge autoremove -y #{options[:pkg]}"
36
48
  @node.run(options)
37
49
  end
50
+
51
+ def dpkg_reconfigure(options = {})
52
+ options[:cmd] = "#{DF} dpkg --configure -a"
53
+ @node.run(options)
54
+ end
38
55
  end
39
56
  end
40
57
  end
@@ -31,6 +31,18 @@ module Core
31
31
  options[:cmd] = "git clone #{options[:repo]} #{options[:dest]}"
32
32
  @node.run(options)
33
33
  end
34
+
35
+ def init(options = {})
36
+ error "repo not specified" unless options[:repo]
37
+
38
+ options[:cmd] = "git init #{options[:repo]}"
39
+
40
+ if options[:bare]
41
+ options[:cmd] += " --bare"
42
+ end
43
+
44
+ @node.run(options)
45
+ end
34
46
  end
35
47
  end
36
48
  end