mybot 0.0.2 → 0.0.3

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