baboon 1.0.9 → 1.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +19 -0
- data/.rspec +4 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +24 -0
- data/LICENSE +22 -0
- data/README.md +113 -33
- data/Rakefile +2 -2
- data/baboon.gemspec +25 -0
- data/lib/baboon.rb +4 -4
- data/lib/baboon/cli.rb +155 -51
- data/lib/baboon/instructions/rails.rb +4 -2
- data/lib/baboon/util.rb +21 -15
- data/lib/baboon/version.rb +2 -2
- data/lib/generators/baboon/install/templates/baboon.yml +36 -17
- data/media/baboon.psd +0 -0
- data/spec/baboon.yml +30 -0
- data/spec/lib/baboon/cli_spec.rb +37 -28
- data/spec/lib/baboon/util_spec.rb +19 -0
- data/spec/lib/baboon_spec.rb +11 -3
- data/spec/spec_helper.rb +40 -3
- metadata +36 -220
- data/lib/baboon/cli/options.rb +0 -241
- data/lib/baboon/configuration.rb +0 -38
- data/lib/baboon/logger.rb +0 -153
- data/lib/generators/baboon/config/config_generator.rb +0 -17
- data/lib/generators/baboon/config/templates/baboon.yml +0 -11
- data/spec/lib/baboon/configuration_spec.rb +0 -115
data/lib/baboon/cli/options.rb
DELETED
@@ -1,241 +0,0 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
require 'baboon/version'
|
3
|
-
|
4
|
-
module Baboon
|
5
|
-
class CLI
|
6
|
-
module Options
|
7
|
-
def self.included(base)
|
8
|
-
base.extend(ClassMethods)
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
# Return a new CLI instance with the given arguments pre-parsed and
|
13
|
-
# ready for execution.
|
14
|
-
def parse(args)
|
15
|
-
cli = new(args)
|
16
|
-
cli.parse_options!
|
17
|
-
cli
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# The hash of (parsed) command-line options
|
22
|
-
attr_reader :options
|
23
|
-
|
24
|
-
def option_parser #:nodoc:
|
25
|
-
@logger = Logger.new
|
26
|
-
@option_parser ||= OptionParser.new do |opts|
|
27
|
-
opts.banner = "Usage: #{File.basename($0)} [options] action ..."
|
28
|
-
|
29
|
-
opts.on("-d", "--debug",
|
30
|
-
"Prompts before each remote command execution."
|
31
|
-
) { |value| options[:debug] = true }
|
32
|
-
|
33
|
-
opts.on("-e", "--explain TASK",
|
34
|
-
"Displays help (if available) for the task."
|
35
|
-
) { |value| options[:explain] = value }
|
36
|
-
|
37
|
-
opts.on("-F", "--default-config",
|
38
|
-
"Always use default config, even with -f."
|
39
|
-
) { options[:default_config] = true }
|
40
|
-
|
41
|
-
opts.on("-f", "--file FILE",
|
42
|
-
"A recipe file to load. May be given more than once."
|
43
|
-
) { |value| options[:recipes] << value }
|
44
|
-
|
45
|
-
opts.on("-H", "--long-help", "Explain these options and environment variables.") do
|
46
|
-
long_help
|
47
|
-
exit
|
48
|
-
end
|
49
|
-
|
50
|
-
opts.on("-h", "--help", "Display this help message.") do
|
51
|
-
puts opts
|
52
|
-
exit
|
53
|
-
end
|
54
|
-
|
55
|
-
opts.on("-l", "--logger [STDERR|STDOUT|file]",
|
56
|
-
"Choose logger method. STDERR used by default."
|
57
|
-
) do |value|
|
58
|
-
options[:output] = if value.nil? || value.upcase == 'STDERR'
|
59
|
-
# Using default logger.
|
60
|
-
nil
|
61
|
-
elsif value.upcase == 'STDOUT'
|
62
|
-
$stdout
|
63
|
-
else
|
64
|
-
value
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
opts.on("-n", "--dry-run",
|
69
|
-
"Prints out commands without running them."
|
70
|
-
) { |value| options[:dry_run] = true }
|
71
|
-
|
72
|
-
opts.on("-p", "--password",
|
73
|
-
"Immediately prompt for the password."
|
74
|
-
) { options[:password] = nil }
|
75
|
-
|
76
|
-
opts.on("-q", "--quiet",
|
77
|
-
"Make the output as quiet as possible."
|
78
|
-
) { options[:verbose] = 0 }
|
79
|
-
|
80
|
-
opts.on("-r", "--preserve-roles",
|
81
|
-
"Preserve task roles"
|
82
|
-
) { options[:preserve_roles] = true }
|
83
|
-
|
84
|
-
opts.on("-S", "--set-before NAME=VALUE",
|
85
|
-
"Set a variable before the recipes are loaded."
|
86
|
-
) do |pair|
|
87
|
-
name, value = pair.split(/=/, 2)
|
88
|
-
options[:pre_vars][name.to_sym] = value
|
89
|
-
end
|
90
|
-
|
91
|
-
opts.on("-s", "--set NAME=VALUE",
|
92
|
-
"Set a variable after the recipes are loaded."
|
93
|
-
) do |pair|
|
94
|
-
name, value = pair.split(/=/, 2)
|
95
|
-
options[:vars][name.to_sym] = value
|
96
|
-
end
|
97
|
-
|
98
|
-
opts.on("-T", "--tasks [PATTERN]",
|
99
|
-
"List all tasks (matching optional PATTERN) in the loaded recipe files."
|
100
|
-
) do |value|
|
101
|
-
options[:tasks] = if value
|
102
|
-
value
|
103
|
-
else
|
104
|
-
true
|
105
|
-
end
|
106
|
-
options[:verbose] ||= 0
|
107
|
-
end
|
108
|
-
|
109
|
-
opts.on("-t", "--tool",
|
110
|
-
"Abbreviates the output of -T for tool integration."
|
111
|
-
) { options[:tool] = true }
|
112
|
-
|
113
|
-
opts.on("-V", "--version",
|
114
|
-
"Display the Baboon version, and exit."
|
115
|
-
) do
|
116
|
-
require 'baboon/version'
|
117
|
-
puts "Baboon v#{Baboon::Version}"
|
118
|
-
exit
|
119
|
-
end
|
120
|
-
|
121
|
-
opts.on("-v", "--verbose",
|
122
|
-
"Be more verbose. May be given more than once."
|
123
|
-
) do
|
124
|
-
options[:verbose] ||= 0
|
125
|
-
options[:verbose] += 1
|
126
|
-
end
|
127
|
-
|
128
|
-
opts.on("-X", "--skip-system-config",
|
129
|
-
"Don't load the system config file (Baboon.configuration)"
|
130
|
-
) { options.delete(:sysconf) }
|
131
|
-
|
132
|
-
opts.on("-x", "--skip-user-config",
|
133
|
-
"Don't load the user config file (.caprc)"
|
134
|
-
) { options.delete(:dotfile) }
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# If the arguments to the command are empty, this will print the
|
139
|
-
# allowed options and exit. Otherwise, it will parse the command
|
140
|
-
# line and set up any default options.
|
141
|
-
def parse_options! #:nodoc:
|
142
|
-
@options = { :recipes => [], :actions => [],
|
143
|
-
:vars => {}, :pre_vars => {},
|
144
|
-
:sysconf => default_sysconf, :dotfile => default_dotfile }
|
145
|
-
|
146
|
-
if args.empty?
|
147
|
-
warn "Please specify at least one action to execute."
|
148
|
-
warn option_parser
|
149
|
-
exit
|
150
|
-
end
|
151
|
-
|
152
|
-
option_parser.parse!(args)
|
153
|
-
|
154
|
-
coerce_variable_types!
|
155
|
-
|
156
|
-
# if no verbosity has been specified, be verbose
|
157
|
-
options[:verbose] = 3 if !options.has_key?(:verbose)
|
158
|
-
|
159
|
-
look_for_default_recipe_file! if options[:default_config] || options[:recipes].empty?
|
160
|
-
extract_environment_variables!
|
161
|
-
|
162
|
-
options[:actions].concat(args)
|
163
|
-
|
164
|
-
password = options.has_key?(:password)
|
165
|
-
options[:password] = Proc.new { self.class.password_prompt }
|
166
|
-
options[:password] = options[:password].call if password
|
167
|
-
end
|
168
|
-
|
169
|
-
# Extracts name=value pairs from the remaining command-line arguments
|
170
|
-
# and assigns them as environment variables.
|
171
|
-
def extract_environment_variables! #:nodoc:
|
172
|
-
args.delete_if do |arg|
|
173
|
-
next unless arg.match(/^(\w+)=(.*)$/)
|
174
|
-
ENV[$1] = $2
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
# Looks for a default recipe file in the current directory.
|
179
|
-
def look_for_default_recipe_file! #:nodoc:
|
180
|
-
current = Dir.pwd
|
181
|
-
|
182
|
-
loop do
|
183
|
-
%w(Capfile capfile).each do |file|
|
184
|
-
if File.file?(file)
|
185
|
-
options[:recipes] << file
|
186
|
-
@logger.info "Using recipes from #{File.join(current,file)}"
|
187
|
-
return
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
pwd = Dir.pwd
|
192
|
-
Dir.chdir("..")
|
193
|
-
break if pwd == Dir.pwd # if changing the directory made no difference, then we're at the top
|
194
|
-
end
|
195
|
-
|
196
|
-
Dir.chdir(current)
|
197
|
-
end
|
198
|
-
|
199
|
-
def default_sysconf #:nodoc:
|
200
|
-
File.join(sysconf_directory, "Baboon.configuration")
|
201
|
-
end
|
202
|
-
|
203
|
-
def default_dotfile #:nodoc:
|
204
|
-
File.join(home_directory, ".caprc")
|
205
|
-
end
|
206
|
-
|
207
|
-
def sysconf_directory #:nodoc:
|
208
|
-
# TODO if anyone cares, feel free to submit a patch that uses a more
|
209
|
-
# appropriate location for this file in Windows.
|
210
|
-
ENV["SystemRoot"] || '/etc'
|
211
|
-
end
|
212
|
-
|
213
|
-
def home_directory #:nodoc:
|
214
|
-
ENV["HOME"] ||
|
215
|
-
(ENV["HOMEPATH"] && "#{ENV["HOMEDRIVE"]}#{ENV["HOMEPATH"]}") ||
|
216
|
-
"/"
|
217
|
-
end
|
218
|
-
|
219
|
-
def coerce_variable_types!
|
220
|
-
[:pre_vars, :vars].each do |collection|
|
221
|
-
options[collection].keys.each do |key|
|
222
|
-
options[collection][key] = coerce_variable(options[collection][key])
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def coerce_variable(value)
|
228
|
-
case value
|
229
|
-
when /^"(.*)"$/ then $1
|
230
|
-
when /^'(.*)'$/ then $1
|
231
|
-
when /^\d+$/ then value.to_i
|
232
|
-
when /^\d+\.\d*$/ then value.to_f
|
233
|
-
when "true" then true
|
234
|
-
when "false" then false
|
235
|
-
when "nil" then nil
|
236
|
-
else value
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|
data/lib/baboon/configuration.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'baboon'
|
2
|
-
|
3
|
-
module Baboon
|
4
|
-
# Baboon.configuration => output of configuration options
|
5
|
-
class << self
|
6
|
-
attr_accessor :configuration
|
7
|
-
end
|
8
|
-
|
9
|
-
# This method should be called with a block, even though none are given
|
10
|
-
# in the parameters of the method
|
11
|
-
def self.configure
|
12
|
-
self.configuration ||= Configuration.new
|
13
|
-
yield configuration
|
14
|
-
end
|
15
|
-
|
16
|
-
class Configuration
|
17
|
-
def initialize
|
18
|
-
# Cannot call attr inside of class, need to class_eval it
|
19
|
-
class << self
|
20
|
-
self
|
21
|
-
end.class_eval do
|
22
|
-
# Define all of the attributes
|
23
|
-
BABOON_CONFIGURATION_OPTIONS.each do |name|
|
24
|
-
attr_accessor name
|
25
|
-
|
26
|
-
# For each given symbol we generate accessor method that sets option's
|
27
|
-
# value being called with an argument, or returns option's current value
|
28
|
-
# when called without arguments
|
29
|
-
define_method name do |*values|
|
30
|
-
value = values.first
|
31
|
-
value ? self.send("#{name}=", value) : instance_variable_get("@#{name}")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
# Initialize defaults
|
36
|
-
end # initialize
|
37
|
-
end # class Configuration
|
38
|
-
end # module Baboon
|
data/lib/baboon/logger.rb
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
module Baboon
|
2
|
-
class Logger
|
3
|
-
attr_accessor :level, :device, :disable_formatters
|
4
|
-
|
5
|
-
IMPORTANT = 0
|
6
|
-
INFO = 1
|
7
|
-
DEBUG = 2
|
8
|
-
TRACE = 3
|
9
|
-
|
10
|
-
MAX_LEVEL = 3
|
11
|
-
|
12
|
-
COLORS = {
|
13
|
-
:none => "0",
|
14
|
-
:black => "30",
|
15
|
-
:red => "31",
|
16
|
-
:green => "32",
|
17
|
-
:yellow => "33",
|
18
|
-
:blue => "34",
|
19
|
-
:magenta => "35",
|
20
|
-
:cyan => "36",
|
21
|
-
:white => "37"
|
22
|
-
}
|
23
|
-
|
24
|
-
STYLES = {
|
25
|
-
:bright => 1,
|
26
|
-
:dim => 2,
|
27
|
-
:underscore => 4,
|
28
|
-
:blink => 5,
|
29
|
-
:reverse => 7,
|
30
|
-
:hidden => 8
|
31
|
-
}
|
32
|
-
|
33
|
-
# Set up default formatters
|
34
|
-
@formatters = [
|
35
|
-
# TRACE
|
36
|
-
{ :match => /command finished/, :color => :white, :style => :dim, :level => 3, :priority => -10 },
|
37
|
-
{ :match => /executing locally/, :color => :yellow, :level => 3, :priority => -20 },
|
38
|
-
|
39
|
-
# DEBUG
|
40
|
-
{ :match => /executing `.*/, :color => :green, :level => 2, :priority => -10, :timestamp => true },
|
41
|
-
{ :match => /.*/, :color => :yellow, :level => 2, :priority => -30 },
|
42
|
-
|
43
|
-
# INFO
|
44
|
-
{ :match => /.*out\] (fatal:|ERROR:).*/, :color => :red, :level => 1, :priority => -10 },
|
45
|
-
{ :match => /Permission denied/, :color => :red, :level => 1, :priority => -20 },
|
46
|
-
{ :match => /sh: .+: command not found/, :color => :magenta, :level => 1, :priority => -30 },
|
47
|
-
|
48
|
-
# IMPORTANT
|
49
|
-
{ :match => /^err ::/, :color => :red, :level => 0, :priority => -10 },
|
50
|
-
{ :match => /.*/, :color => :blue, :level => 0, :priority => -20 }
|
51
|
-
]
|
52
|
-
|
53
|
-
class << self
|
54
|
-
def add_formatter(options) #:nodoc:
|
55
|
-
@formatters.push(options)
|
56
|
-
@sorted_formatters = nil
|
57
|
-
end
|
58
|
-
|
59
|
-
def sorted_formatters
|
60
|
-
# Sort matchers in reverse order so we can break if we found a match.
|
61
|
-
@sorted_formatters ||= @formatters.sort_by { |i| -(i[:priority] || i[:prio] || 0) }
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def initialize(options={})
|
66
|
-
output = options[:output] || $stderr
|
67
|
-
if output.respond_to?(:puts)
|
68
|
-
@device = output
|
69
|
-
else
|
70
|
-
@device = File.open(output.to_str, "a")
|
71
|
-
@needs_close = true
|
72
|
-
end
|
73
|
-
|
74
|
-
@options = options
|
75
|
-
@level = options[:level] || 0
|
76
|
-
@disable_formatters = options[:disable_formatters]
|
77
|
-
end
|
78
|
-
|
79
|
-
def close
|
80
|
-
device.close if @needs_close
|
81
|
-
end
|
82
|
-
|
83
|
-
def log(level, message, line_prefix=nil)
|
84
|
-
if level <= self.level
|
85
|
-
# Only format output if device is a TTY or formatters are not disabled
|
86
|
-
if device.tty? && !@disable_formatters
|
87
|
-
color = :none
|
88
|
-
style = nil
|
89
|
-
|
90
|
-
Logger.sorted_formatters.each do |formatter|
|
91
|
-
if (formatter[:level] == level || formatter[:level].nil?)
|
92
|
-
if message =~ formatter[:match] || line_prefix =~ formatter[:match]
|
93
|
-
color = formatter[:color] if formatter[:color]
|
94
|
-
style = formatter[:style] || formatter[:attribute] # (support original cap colors)
|
95
|
-
message.gsub!(formatter[:match], formatter[:replace]) if formatter[:replace]
|
96
|
-
message = formatter[:prepend] + message unless formatter[:prepend].nil?
|
97
|
-
message = message + formatter[:append] unless formatter[:append].nil?
|
98
|
-
message = Time.now.strftime('%Y-%m-%d %T') + ' ' + message if formatter[:timestamp]
|
99
|
-
break unless formatter[:replace]
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
if color == :hide
|
105
|
-
# Don't do anything if color is set to :hide
|
106
|
-
return false
|
107
|
-
end
|
108
|
-
|
109
|
-
term_color = COLORS[color]
|
110
|
-
term_style = STYLES[style]
|
111
|
-
|
112
|
-
# Don't format message if no color or style
|
113
|
-
unless color == :none and style.nil?
|
114
|
-
unless line_prefix.nil?
|
115
|
-
line_prefix = format(line_prefix, term_color, term_style, nil)
|
116
|
-
end
|
117
|
-
message = format(message, term_color, term_style)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
indent = "%*s" % [MAX_LEVEL, "*" * (MAX_LEVEL - level)]
|
122
|
-
(RUBY_VERSION >= "1.9" ? message.lines : message).each do |line|
|
123
|
-
if line_prefix
|
124
|
-
device.puts "#{indent} [#{line_prefix}] #{line.strip}\n"
|
125
|
-
else
|
126
|
-
device.puts "#{indent} #{line.strip}\n"
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def important(message, line_prefix=nil)
|
133
|
-
log(IMPORTANT, message, line_prefix)
|
134
|
-
end
|
135
|
-
|
136
|
-
def info(message, line_prefix=nil)
|
137
|
-
log(INFO, message, line_prefix)
|
138
|
-
end
|
139
|
-
|
140
|
-
def debug(message, line_prefix=nil)
|
141
|
-
log(DEBUG, message, line_prefix)
|
142
|
-
end
|
143
|
-
|
144
|
-
def trace(message, line_prefix=nil)
|
145
|
-
log(TRACE, message, line_prefix)
|
146
|
-
end
|
147
|
-
|
148
|
-
def format(message, color, style, nl = "\n")
|
149
|
-
style = "#{style};" if style
|
150
|
-
"\e[#{style}#{color}m" + message.to_s.strip + "\e[0m#{nl}"
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'rails/generators/base'
|
2
|
-
|
3
|
-
module Baboon
|
4
|
-
module Generators
|
5
|
-
class ConfigGenerator < Rails::Generators::Base
|
6
|
-
desc 'Creates a yaml for Baboon at config/baboon.yml'
|
7
|
-
|
8
|
-
def self.source_root
|
9
|
-
@source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
10
|
-
end
|
11
|
-
|
12
|
-
def create_initializer_file
|
13
|
-
template "baboon.yml", "config/baboon.yml"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|