between_meals 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,197 @@
1
+ # vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
2
+
3
+ require 'json'
4
+ require 'fileutils'
5
+ require 'digest/md5'
6
+ require 'between_meals/util'
7
+
8
+ module BetweenMeals
9
+ # Knife does not have a usable API for using it as a lib
10
+ # This could be possibly refactored to touch its internals
11
+ # instead of shelling out
12
+ class Knife
13
+ include BetweenMeals::Util
14
+
15
+ def initialize(opts = {})
16
+ @logger = opts[:logger] || nil
17
+ @user = opts[:user] || ENV['USER']
18
+ @home = opts[:home] || ENV['HOME']
19
+ @host = opts[:host] || 'localhost'
20
+ @port = opts[:port] || 4000
21
+ @config = opts[:config] ||
22
+ "#{@home}/.chef/knife-#{@user}-taste-tester.rb"
23
+ @knife = opts[:bin] || 'knife'
24
+ @pem = opts[:pem] ||
25
+ "#{@home}/.chef/#{@user}-taste-tester.pem"
26
+ @role_dir = opts[:role_dir]
27
+ @cookbook_dirs = opts[:cookbook_dirs]
28
+ @databag_dir = opts[:databag_dir]
29
+ @checksum_dir = opts[:checksum_dir]
30
+ @client_key =
31
+ File.expand_path("#{@home}/.chef/#{@user}-taste-tester.pem")
32
+ end
33
+
34
+ def role_upload_all
35
+ roles = File.join(@role_dir, '*.rb')
36
+ exec!("#{@knife} role from file #{roles} -c #{@config}", @logger)
37
+ end
38
+
39
+ def role_upload(roles)
40
+ if roles.any?
41
+ roles = roles.map { |x| File.join(@role_dir, "#{x.name}.rb") }.join(' ')
42
+ exec!("#{@knife} role from file #{roles} -c #{@config}", @logger)
43
+ end
44
+ end
45
+
46
+ def role_delete(roles)
47
+ if roles.any?
48
+ roles.each do |role|
49
+ exec!(
50
+ "#{@knife} role delete #{role.name} --yes -c #{@config}", @logger
51
+ )
52
+ end
53
+ end
54
+ end
55
+
56
+ def cookbook_upload_all
57
+ exec!("#{@knife} cookbook upload -a -c #{@config}", @logger)
58
+ end
59
+
60
+ def cookbook_upload(cookbooks)
61
+ if cookbooks.any?
62
+ cookbooks = cookbooks.map { |x| x.name }.join(' ')
63
+ exec!("#{@knife} cookbook upload #{cookbooks} -c #{@config}", @logger)
64
+ end
65
+ end
66
+
67
+ def cookbook_delete(cookbooks)
68
+ if cookbooks.any?
69
+ cookbooks.each do |cookbook|
70
+ exec!("#{@knife} cookbook delete #{cookbook.name}" +
71
+ " --purge --yes -c #{@config}", @logger)
72
+ end
73
+ end
74
+ end
75
+
76
+ def databag_upload_all
77
+ glob = File.join(@databag_dir, '*', '*.json')
78
+ items = Dir.glob(glob).map do |file|
79
+ BetweenMeals::Changes::Databag.new(
80
+ { :status => :modified, :path => file }, @databag_dir
81
+ )
82
+ end
83
+ databag_upload(items)
84
+ end
85
+
86
+ def databag_upload(databags)
87
+ if databags.any?
88
+ databags.group_by { |x| x.name }.each do |dbname, dbs|
89
+ create_databag_if_missing(dbname)
90
+ dbitems = dbs.map do |x|
91
+ File.join(@databag_dir, dbname, "#{x.item}.json")
92
+ end.join(' ')
93
+ exec!("#{@knife} data bag from file #{dbname} #{dbitems}", @logger)
94
+ end
95
+ end
96
+ end
97
+
98
+ def databag_delete(databags)
99
+ if databags.any?
100
+ databags.group_by { |x| x.name }.each do |dbname, dbs|
101
+ dbs.each do |db|
102
+ exec!("#{@knife} data bag delete #{dbname} #{db.item}" +
103
+ " --yes -c #{@config}", @logger)
104
+ end
105
+ delete_databag_if_empty(dbname)
106
+ end
107
+ end
108
+ end
109
+
110
+ def write_user_config
111
+ cfg = <<-BLOCK
112
+ user = ENV['USER']
113
+ log_level :info
114
+ log_location STDOUT
115
+ node_name user
116
+ chef_server_url "http://#{@host}:#{@port}"
117
+ cache_type 'BasicFile'
118
+ client_key '#{@client_key}'
119
+ cache_options(:path => File.expand_path("#{@checksum_dir}"))
120
+ cookbook_path [
121
+ BLOCK
122
+ @cookbook_dirs.each do |dir|
123
+ cfg << " \"#{dir}\",\n"
124
+ end
125
+ cfg << "]\n"
126
+ unless File.directory?(File.dirname(@config))
127
+ Dir.mkdir(File.dirname(@config), 0755)
128
+ end
129
+ if !File.exists?(@config) ||
130
+ ::Digest::MD5.hexdigest(cfg) !=
131
+ ::Digest::MD5.hexdigest(File.read(@config))
132
+ @logger.info("Generating #{@config}")
133
+ File.write(@config, cfg)
134
+ end
135
+
136
+ # Won't work with shorter keys
137
+ pem = <<-BLOCK
138
+ -----BEGIN PRIVATE KEY-----
139
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCs4Ih8+R/2hcYS
140
+ tccwJHd0cXHcUibC2wGYmRwf1fKxXLADvfuLRVBHOI5Hgd/ZXF70dowC5mDQ03gr
141
+ ouk8e7RL72MCKzPuG2V92sh/FnyKhkNsHCOEKaRRiP9lHVbZkS9LEotCKF7eOkL0
142
+ SVkGWx8pVZzrOFmhZgHaOFJ2/2t1irUTRFqTikrRsP2KvnhHdDlnnbUumZWxSuEN
143
+ oN6aSAQEOkKbEOLSn/EIMzEb2jtks7L7wkRErajH094jGoZbQvLiwRHDeM0C9uG7
144
+ 2sdQ45BG9EQOCdBzy1We5keqtJbXBcpwuBa0d1nQZIsGxnDb88+Kmh9h6k9/WmYN
145
+ zEQEeSSdAgMBAAECggEATFWQru4p6ObEwTo2y9EuVeJJzmkP6HZfzAu/WWdVFG/C
146
+ 4MQgsCxY+DnGyVhViVq6KuO1iwpCsbLOmyYCKszMncMESs7czUSXmezjHwrEzz3d
147
+ w3zhSdhBUCdX7kP4N3VeFp4Hk5zT1viO2+MPRjkyF0RQV6S4HwY1xy+baiP6RRnS
148
+ dGhUYsdz6fjxSkYEQy3/xHm9VLT6ZDV4pN2aA+LOFeveHKcnOjKFCBy4WzkO6fvj
149
+ 6H3jghxsHXoL7loCHfi9WX3xKjeXG/NjGbUfTH8P7IldUPha+ru/e8W/P+jjE1os
150
+ VkScWt08Vu6iTl1EkYeFxOMtSDZxeXNnDkPI0iDQgQKBgQDUMFYncQcZ4uLIfoZq
151
+ B+Lx7WJGlIwulOdobnraTd5lsrBHj1sC1+/f4cBSpJwUij2l3GdmmnOpuFAof5eu
152
+ mrBGu++5jy+0eIeT5O2d30O8GOBryJ+oAKI2/BPVCmM8d986wl5Esauycb++O7UO
153
+ RhpZFOCKbFvlNjhg+CdlvHSl7QKBgQDQkkvpnE//yWmhCPg27n7w3bTg5QPNrzTO
154
+ pF2iwvLK4XjRceTeW3P4f42HONzJNnmt5TexM9NbdE9g/exA5uNt59ZB5FeFiKAu
155
+ NmVXbmswPX6R/dlyidqzz1guGrL04e0dZehHZBNDr5Sio8IBjMWrpDIxjDJqEwUa
156
+ 4qCu4e6jcQKBgQDN0FTAzRFmOnxenNsj3aJzpx27+DpAtI4A7aicNwuQ+VGjF5nf
157
+ mDRDpGU3xBLgmXZSewaQrx+hb/XQUnJ+Ge0BrylHg2tyUbav7U3N49F/kWGdKmwy
158
+ OOsfCkLyUbEP5fXQuNdXKj6wR0UE8EUeI0FLRsTFf3VjTsRAynLsa295wQKBgAo3
159
+ QDSfDWQP73aNw+qc3+bYVSW20erfLAz7DAMO3WmGha5sj7M8c3+2b64x4M6SNn+H
160
+ /KRXT4DpP4IWrd238WfOtTXhA1BtErtwuqH/rIxeVra74kyz59xqyXzond9UuZJ5
161
+ DVmB01e7X+Jfdv8wb/YqQrMelNGRQOzCMPCf7FphAoGAbUh5HzNF2aciQJGA6Qk8
162
+ zvgEHqbS0/QkJGOZ+UifPRanTDuGYQkPdHHOER4UghbM+Kz5rZbBicJ3bCyNOsah
163
+ IAMAEpsWX2s2A6phgMCx7kH6wMmoZn3hb7Thh9+PfR8Jtp2/7k+ibCeF4gEWUCs5
164
+ 6wX4GR84dwyhG80yd4TP8Qo=
165
+ -----END PRIVATE KEY-----
166
+ BLOCK
167
+
168
+ unless File.exists?(@pem)
169
+ @logger.info("Generating #{@pem}")
170
+ File.write(@pem, pem)
171
+ end
172
+ end
173
+
174
+ private
175
+
176
+ def create_databag_if_missing(databag)
177
+ s = Mixlib::ShellOut.new("#{@knife} data bag list" +
178
+ " --format json -c #{@config}").run_command
179
+ s.error!
180
+ db = JSON.load(s.stdout)
181
+ unless db.include?(databag)
182
+ exec!("#{@knife} data bag create #{databag} -c #{@config}", @logger)
183
+ end
184
+ end
185
+
186
+ def delete_databag_if_empty(databag)
187
+ s = Mixlib::ShellOut.new("#{@knife} data bag show #{databag}" +
188
+ " --format json -c #{@config}").run_command
189
+ s.error!
190
+ db = JSON.load(s.stdout)
191
+ if db.empty?
192
+ exec!("#{@knife} data bag delete #{databag} --yes -c #{@config}",
193
+ @logger)
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,204 @@
1
+ # vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
2
+
3
+ require 'rugged'
4
+ require 'mixlib/shellout'
5
+ require 'between_meals/changeset'
6
+
7
+ module BetweenMeals
8
+ # Local checkout wrapper
9
+ class Repo
10
+ # Git provider
11
+ class Git < BetweenMeals::Repo
12
+ def setup
13
+ if File.exists?(File.expand_path(@repo_path))
14
+ @repo = Rugged::Repository.new(File.expand_path(@repo_path))
15
+ else
16
+ @repo = nil
17
+ end
18
+ @bin = 'git'
19
+ end
20
+
21
+ def exists?
22
+ @repo && !@repo.empty?
23
+ end
24
+
25
+ def head_rev
26
+ @repo.head.target.oid
27
+ end
28
+
29
+ def last_msg
30
+ @repo.head.target.message
31
+ end
32
+
33
+ def last_msg=(msg)
34
+ @repo.head.target.amend(
35
+ {
36
+ :message => msg,
37
+ :update_ref => 'HEAD',
38
+ }
39
+ )
40
+ end
41
+
42
+ def last_author
43
+ @repo.head.target.to_hash[:author]
44
+ end
45
+
46
+ def head_parents
47
+ @repo.head.target.parents
48
+ end
49
+
50
+ def checkout(url)
51
+ s = Mixlib::ShellOut.new(
52
+ "#{@bin} clone #{url} #{@repo} #{@repo_path}"
53
+ ).run_command
54
+ s.error!
55
+ @repo = Rugged::Repository.new(File.expand_path(@repo_path))
56
+ end
57
+
58
+ # Return files changed between two revisions
59
+ def changes(start_ref, end_ref)
60
+ check_refs(start_ref, end_ref)
61
+ s = Mixlib::ShellOut.new(
62
+ "#{@bin} diff --name-status #{start_ref} #{end_ref}",
63
+ :cwd => File.expand_path(@repo_path)
64
+ )
65
+ s.run_command.error!
66
+ begin
67
+ parse_status(s.stdout).compact
68
+ rescue => e
69
+ # We've seen some weird non-reproducible failures here
70
+ @logger.error(
71
+ 'Something went wrong. Please please report this output.'
72
+ )
73
+ @logger.error(e)
74
+ s.stdout.lines.each do |line|
75
+ @logger.error(line.strip)
76
+ end
77
+ exit(1)
78
+ end
79
+ end
80
+
81
+ def update
82
+ cmd = Mixlib::ShellOut.new(
83
+ "#{@bin} pull --rebase", :cwd => File.expand_path(@repo_path)
84
+ )
85
+ cmd.run_command
86
+ if cmd.exitstatus != 0
87
+ @logger.error('Something went wrong with git!')
88
+ @logger.error(cmd.stdout)
89
+ fail
90
+ end
91
+ cmd.stdout
92
+ end
93
+
94
+ # Return all files
95
+ def files
96
+ @repo.index.map { |x| { :path => x[:path], :status => :created } }
97
+ end
98
+
99
+ def status
100
+ cmd = Mixlib::ShellOut.new(
101
+ "#{@bin} status --porcelain 2>&1",
102
+ :cwd => File.expand_path(@repo_path)
103
+ )
104
+ cmd.run_command
105
+ if cmd.exitstatus != 0
106
+ @logger.error('Something went wrong with git!')
107
+ @logger.error(cmd.stdout)
108
+ fail
109
+ end
110
+ cmd.stdout
111
+ end
112
+
113
+ private
114
+
115
+ def check_refs(start_ref, end_ref)
116
+ unless @repo.exists?(start_ref)
117
+ fail Changeset::ReferenceError
118
+ end
119
+ unless end_ref.nil?
120
+ unless @repo.exists?(end_ref)
121
+ fail Changeset::ReferenceError
122
+ end
123
+ end
124
+ end
125
+
126
+ def parse_status(changes)
127
+ # man git-diff-files
128
+ # Possible status letters are:
129
+ #
130
+ # A: addition of a file
131
+ # C: copy of a file into a new one
132
+ # D: deletion of a file
133
+ # M: modification of the contents or mode of a file
134
+ # R: renaming of a file
135
+ # T: change in the type of the file
136
+ # U: file is unmerged (you must complete the merge before it can
137
+ # be committed)
138
+ # X: "unknown" change type (most probably a bug, please report it)
139
+
140
+ # rubocop:disable MultilineBlockChain
141
+ changes.lines.map do |line|
142
+ case line
143
+ when /^A\s+(\S+)$/
144
+ # A path
145
+ {
146
+ :status => :modified,
147
+ :path => Regexp.last_match(1)
148
+ }
149
+ when /^C(?:\d*)\s+(\S+)\s+(\S+)/
150
+ # C<numbers> path1 path2
151
+ {
152
+ :status => :modified,
153
+ :path => Regexp.last_match(2)
154
+ }
155
+ when /^D\s+(\S+)$/
156
+ # D path
157
+ {
158
+ :status => :deleted,
159
+ :path => Regexp.last_match(1)
160
+ }
161
+ when /^M(?:\d*)\s+(\S+)$/
162
+ # M<numbers> path
163
+ {
164
+ :status => :modified,
165
+ :path => Regexp.last_match(1)
166
+ }
167
+ when /^R(?:\d*)\s+(\S+)\s+(\S+)/
168
+ # R<numbers> path1 path2
169
+ [
170
+ {
171
+ :status => :deleted,
172
+ :path => Regexp.last_match(1)
173
+ },
174
+ {
175
+ :status => :modified,
176
+ :path => Regexp.last_match(2)
177
+ }
178
+ ]
179
+ when /^T\s+(\S+)$/
180
+ # T path
181
+ [
182
+ {
183
+ :status => :deleted,
184
+ :path => Regexp.last_match(1)
185
+ },
186
+ {
187
+ :status => :modified,
188
+ :path => Regexp.last_match(1)
189
+ }
190
+ ]
191
+ else
192
+ fail 'No match'
193
+ end
194
+ end.flatten.map do |x|
195
+ {
196
+ :status => x[:status],
197
+ :path => x[:path].sub("#{@repo_path}/", '')
198
+ }
199
+ end
200
+ # rubocop:enable MultilineBlockChain
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,121 @@
1
+ # vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
2
+
3
+ require 'between_meals/repo'
4
+ require 'between_meals/changeset'
5
+ require 'mixlib/shellout'
6
+
7
+ module BetweenMeals
8
+ # Local checkout wrapper
9
+ class Repo
10
+ # SVN implementation
11
+ class Svn < BetweenMeals::Repo
12
+ def setup
13
+ @bin = 'svn'
14
+ end
15
+
16
+ def exists?
17
+ # this shuold be better
18
+ Dir.exists?(@repo_path)
19
+ end
20
+
21
+ def head_rev
22
+ s = Mixlib::ShellOut.new("#{@bin} info #{@repo_path}").run_command
23
+ s.error!
24
+ s.stdout.each_line do |line|
25
+ m = line.match(/Last Changed Rev: (\d+)$/)
26
+ return m[1] if m
27
+ end
28
+ end
29
+
30
+ def latest_revision
31
+ s = Mixlib::ShellOut.new("#{@bin} info #{@repo_path}").run_command
32
+ s.error!
33
+ s.stdout.each do |line|
34
+ m = line.match(/Revision: (\d+)$/)
35
+ return m[1] if m
36
+ end
37
+ end
38
+
39
+ def checkout(url)
40
+ s = Mixlib::ShellOut.new(
41
+ "#{@bin} co --ignore-externals #{url} #{@repo_path}").run_command
42
+ s.error!
43
+ end
44
+
45
+ # Return files changed between two revisions
46
+ def changes(start_ref, end_ref)
47
+ check_refs(start_ref, end_ref)
48
+ s = Mixlib::ShellOut.new(
49
+ "#{@bin} diff -r #{start_ref}:#{end_ref} --summarize #{@repo_path}")
50
+ s.run_command.error!
51
+ @logger.info("Diff between #{start_ref} and #{end_ref}")
52
+ s.stdout.lines.map do |line|
53
+ m = line.match(/^(\w)\w?\s+(\S+)$/)
54
+ fail "Could not parse line: #{line}" unless m
55
+
56
+ {
57
+ :status => m[1] == 'D' ? :deleted : :modified,
58
+ :path => m[2].sub("#{@repo_path}/", '')
59
+ }
60
+ end
61
+ end
62
+
63
+ def update
64
+ cleanup
65
+ revert
66
+ up
67
+ end
68
+
69
+ # Return all files
70
+ def files
71
+ s = Mixlib::ShellOut.new("#{@bin} ls --depth infinity #{@repo_path}")
72
+ s.run_command
73
+ s.error!
74
+ s.stdout.split("\n").map do |x|
75
+ { :path => x, :status => :created }
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def run(cmd)
82
+ Mixlib::ShellOut.new(cmd).run_command.error!
83
+ end
84
+
85
+ def revert
86
+ run("#{@bin} revert -R #{@repo_path}")
87
+ end
88
+
89
+ def up
90
+ run("#{@bin} update #{@repo_path}")
91
+ end
92
+
93
+ def cleanup
94
+ run("#{@bin} cleanup #{@repo_path}")
95
+ end
96
+
97
+ def first_revision
98
+ 0
99
+ end
100
+
101
+ private
102
+
103
+ def check_refs(start_ref, end_ref)
104
+ s = Mixlib::ShellOut.new(
105
+ "#{@bin} info -r #{start_ref}",
106
+ :cwd => @repo_path
107
+ ).run_command
108
+ s.error!
109
+ if end_ref
110
+ s = Mixlib::ShellOut.new(
111
+ "#{@bin} info -r #{end_ref}",
112
+ :cwd => @repo_path
113
+ ).run_command
114
+ s.error!
115
+ end
116
+ rescue
117
+ raise Changeset::ReferenceError
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,113 @@
1
+ # vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
2
+
3
+ require 'mixlib/shellout'
4
+
5
+ module BetweenMeals
6
+ # Local checkout wrapper
7
+ class Repo
8
+ attr_reader :repo_path
9
+ attr_writer :bin
10
+
11
+ def initialize(repo_path, logger)
12
+ @repo_path = repo_path
13
+ @logger = logger
14
+ @repo = nil
15
+ @bin = nil
16
+ setup
17
+ rescue
18
+ @logger.warn("Unable to read repo from #{File.expand_path(repo_path)}")
19
+ exit(1)
20
+ end
21
+
22
+ def self.get(type, repo_path, logger)
23
+ case type
24
+ when 'svn'
25
+ require 'between_meals/repo/svn'
26
+ BetweenMeals::Repo::Svn.new(repo_path, logger)
27
+ when 'git'
28
+ require 'between_meals/repo/git'
29
+ BetweenMeals::Repo::Git.new(repo_path, logger)
30
+ else
31
+ fail "Do not know repo type #{type}"
32
+ end
33
+ end
34
+
35
+ def exists?
36
+ fail 'Not implemented'
37
+ end
38
+
39
+ def status
40
+ fail 'Not implemented'
41
+ end
42
+
43
+ def setup
44
+ fail 'Not implemented'
45
+ end
46
+
47
+ def head_rev
48
+ fail 'Not implemented'
49
+ end
50
+
51
+ def head_msg
52
+ fail 'Not implemented'
53
+ end
54
+
55
+ def head_msg=
56
+ fail 'Not implemented'
57
+ end
58
+
59
+ def head_parents
60
+ fail 'Not implemented'
61
+ end
62
+
63
+ def latest_revision
64
+ fail 'Not implemented'
65
+ end
66
+
67
+ def create(_url)
68
+ fail 'Not implemented'
69
+ end
70
+
71
+ # Return files changed between two revisions
72
+ def changes(_start_ref, _end_ref)
73
+ fail 'Not implemented'
74
+ end
75
+
76
+ def update
77
+ fail 'Not implemented'
78
+ end
79
+
80
+ # Return all files
81
+ def files
82
+ fail 'Not implemented'
83
+ end
84
+
85
+ def latest_revision
86
+ fail 'Not implemented'
87
+ end
88
+
89
+ def head
90
+ fail 'Not implemented'
91
+ end
92
+
93
+ def checkout
94
+ fail 'Not implemented'
95
+ end
96
+
97
+ def update
98
+ fail 'Not implemented'
99
+ end
100
+
101
+ def last_author
102
+ fail 'Not implemented'
103
+ end
104
+
105
+ def last_msg
106
+ fail 'Not implemented'
107
+ end
108
+
109
+ def last_msg=
110
+ fail 'Not implemented'
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,74 @@
1
+ # vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
2
+
3
+ require 'colorize'
4
+ require 'socket'
5
+ require 'timeout'
6
+
7
+ module BetweenMeals
8
+ # A set of simple utility functions used throughout BetweenMeals
9
+ #
10
+ # Feel freeo to use... note that if you pass in a logger once
11
+ # you don't need to again, but be safe and always pass one in. :)
12
+
13
+ # Util classes need class vars :)
14
+ # rubocop:disable ClassVars
15
+ module Util
16
+ @@logger = nil
17
+
18
+ def time(logger = nil)
19
+ @@logger = logger if logger
20
+ t0 = Time.now
21
+ yield
22
+ info("Executed in #{format('%.2f', Time.now - t0)}s")
23
+ end
24
+
25
+ def exec!(command, logger = nil)
26
+ @@logger = logger if logger
27
+ c = execute(command)
28
+ c.error!
29
+ return c.status.exitstatus, c.stdout
30
+ end
31
+
32
+ def exec(command, logger = nil)
33
+ @@logger = logger if logger
34
+ c = execute(command)
35
+ return c.status.exitstatus, c.stdout
36
+ end
37
+
38
+ private
39
+
40
+ def info(msg)
41
+ @@logger.info(msg) if @@logger
42
+ end
43
+
44
+ def execute(command)
45
+ info("Running: #{command}")
46
+ c = Mixlib::ShellOut.new(command)
47
+ c.run_command
48
+ c.stdout.lines.each do |line|
49
+ info("STDOUT: #{line.strip}")
50
+ end
51
+ c.stderr.lines.each do |line|
52
+ info("STDERR: #{line.strip.red}")
53
+ end
54
+ return c
55
+ end
56
+
57
+ def port_open?(port)
58
+ begin
59
+ Timeout.timeout(1) do
60
+ begin
61
+ s = TCPSocket.new('localhost', port)
62
+ s.close
63
+ return true
64
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
65
+ return false
66
+ end
67
+ end
68
+ rescue Timeout::Error
69
+ return false
70
+ end
71
+ return false
72
+ end
73
+ end
74
+ end