golden_brindle 0.2 → 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,45 @@
1
+ module GoldenBrindle
2
+ module Actions
3
+
4
+ class Stop < ::GoldenBrindle::Base
5
+
6
+ def configure
7
+ options [
8
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded).", :@cwd, "."],
9
+ ['-C', '--config PATH', "Use a mongrel based config file", :@config_file, nil],
10
+ ['-f', '--force', "Force the shutdown (kill -9).", :@force, false],
11
+ ['-w', '--wait SECONDS', "Wait SECONDS before forcing shutdown", :@wait, "0"],
12
+ ['-P', '--pid FILE', "Where the PID file is located.", :@pid_file, "tmp/pids/unicorn.pid"]
13
+ ]
14
+ end
15
+
16
+ def validate
17
+ if @config_file
18
+ valid_exists?(@config_file, "Config file not there: #@config_file")
19
+ @config_file = File.expand_path(@config_file)
20
+ load_config
21
+ return @valid
22
+ end
23
+
24
+ @cwd = File.expand_path(@cwd)
25
+ valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
26
+ valid_exists? File.join(@cwd,@pid_file), "PID file #@pid_file does not exist. Not running?"
27
+ return @valid
28
+ end
29
+
30
+ def run
31
+ @pid_file = File.join(@cwd,@pid_file)
32
+ if @force
33
+ @wait.to_i.times do |waiting|
34
+ exit(0) if not File.exist? @pid_file
35
+ sleep 1
36
+ end
37
+ GoldenBrindle::send_signal("KILL", @pid_file) if File.exist? @pid_file
38
+ else
39
+ GoldenBrindle::send_signal("TERM", @pid_file)
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,89 @@
1
+ module GoldenBrindle
2
+ class Base
3
+ include Validations
4
+ attr_reader :valid, :done_validating, :original_args
5
+
6
+ # Called by the subclass to setup the command and parse the argv arguments.
7
+ # The call is destructive on argv since it uses the OptionParser#parse! function.
8
+ def initialize(argv)
9
+ @opt = ::OptionParser.new
10
+ @opt.banner = GoldenBrindle::Const::BANNER
11
+ @valid = true
12
+ # this is retarded, but it has to be done this way because -h and -v exit
13
+ @done_validating = false
14
+ @original_args = argv.dup
15
+ configure
16
+ # I need to add my own -h definition to prevent the -h by default from exiting.
17
+ @opt.on_tail("-h", "--help", "Show this message") do
18
+ @done_validating = true
19
+ puts @opt
20
+ end
21
+ # I need to add my own -v definition to prevent the -v from exiting by default as well.
22
+ @opt.on_tail("--version", "Show version") do
23
+ @done_validating = true
24
+ if VERSION
25
+ puts "Version #{GoldenBrindle::Const::VERSION}"
26
+ end
27
+ end
28
+ @opt.parse! argv
29
+ end
30
+
31
+ # Called by the implemented command to set the options for that command.
32
+ # Every option has a short and long version, a description, a variable to
33
+ # set, and a default value. No exceptions.
34
+ def options(opts)
35
+ # process the given options array
36
+ opts.each do |short, long, help, variable, default|
37
+ self.instance_variable_set(variable, default)
38
+ @opt.on(short, long, help) do |arg|
39
+ self.instance_variable_set(variable, arg)
40
+ end
41
+ end
42
+ end
43
+
44
+ def configure
45
+ options []
46
+ end
47
+
48
+ def config_keys
49
+ GoldenBrindle::Const::CONFIG_KEYS
50
+ end
51
+
52
+ def load_config
53
+ settings = {}
54
+ begin
55
+ settings = ::YAML.load_file(@config_file)
56
+ ensure
57
+ STDERR.puts "** Loading settings from #{@config_file} (they override command line)." unless @daemon || settings[:daemon]
58
+ end
59
+
60
+ # Config file settings will override command line settings
61
+ settings.each do |key, value|
62
+ key = key.to_s
63
+ if config_keys.include?(key)
64
+ key = 'address' if key == 'host'
65
+ self.instance_variable_set("@#{key}", value)
66
+ else
67
+ failure "Unknown configuration setting: #{key}"
68
+ @valid = false
69
+ end
70
+ end
71
+ end
72
+
73
+ # Returns true/false depending on whether the command is configured properly.
74
+ def validate
75
+ @valid
76
+ end
77
+
78
+ # Returns a help message. Defaults to OptionParser#help which should be good.
79
+ def help
80
+ @opt.help
81
+ end
82
+
83
+ # Runs the command doing it's job. You should implement this otherwise it will
84
+ # throw a NotImplementedError as a reminder.
85
+ def run
86
+ raise NotImplementedError
87
+ end
88
+ end
89
+ end
@@ -1,194 +1,60 @@
1
1
  module GoldenBrindle
2
-
3
-
4
- def GoldenBrindle::send_signal(signal, pid_file)
5
- pid = open(pid_file).read.to_i
6
- print "Sending #{signal} to Unicorn at PID #{pid}..."
7
- begin
8
- Process.kill(signal, pid)
9
- rescue Errno::ESRCH
10
- puts "Process does not exist. Not running."
2
+
3
+ class << self
4
+ def send_signal(signal, pid_file)
5
+ pid = open(pid_file).read.to_i
6
+ print "Sending #{signal} to Unicorn at PID #{pid}..."
7
+ begin
8
+ Process.kill(signal, pid)
9
+ rescue Errno::ESRCH
10
+ puts "Process does not exist. Not running."
11
+ end
12
+ puts "Done."
11
13
  end
12
- puts "Done."
13
14
  end
14
-
15
- module Command
16
-
17
- module Base
18
-
19
- attr_reader :valid, :done_validating, :original_args
20
15
 
21
- # Called by the implemented command to set the options for that command.
22
- # Every option has a short and long version, a description, a variable to
23
- # set, and a default value. No exceptions.
24
- def options(opts)
25
- # process the given options array
26
- opts.each do |short, long, help, variable, default|
27
- self.instance_variable_set(variable, default)
28
- @opt.on(short, long, help) do |arg|
29
- self.instance_variable_set(variable, arg)
30
- end
31
- end
32
- end
16
+ # A Singleton class that manages all of the available commands
17
+ # and handles running them.
18
+ class Registry
33
19
 
34
- # Called by the subclass to setup the command and parse the argv arguments.
35
- # The call is destructive on argv since it uses the OptionParser#parse! function.
36
- def initialize(options={})
37
- argv = options[:argv] || []
38
- @opt = OptionParser.new
39
- @opt.banner = GoldenBrindle::Const::BANNER
40
- @valid = true
41
- # this is retarded, but it has to be done this way because -h and -v exit
42
- @done_validating = false
43
- @original_args = argv.dup
44
- configure
45
- # I need to add my own -h definition to prevent the -h by default from exiting.
46
- @opt.on_tail("-h", "--help", "Show this message") do
47
- @done_validating = true
48
- puts @opt
49
- end
20
+ class << self
50
21
 
51
- # I need to add my own -v definition to prevent the -v from exiting by default as well.
52
- @opt.on_tail("--version", "Show version") do
53
- @done_validating = true
54
- if VERSION
55
- puts "Version #{GoldenBrindle::Const::VERSION}"
56
- end
22
+ def constantize(camel_cased_word)
23
+ names = camel_cased_word.split('::')
24
+ names.shift if names.empty? || names.first.empty?
25
+ constant = Object
26
+ names.each do |name|
27
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
57
28
  end
58
- @opt.parse! argv
29
+ constant
59
30
  end
60
31
 
61
- def configure
62
- options []
63
- end
64
-
65
- def config_keys
66
- @config_keys ||=
67
- %w(address host port cwd log_file pid_file environment servers daemon debug config_script workers timeout user group prefix preload listen bundler)
68
- end
69
-
70
- def load_config
71
- settings = {}
72
- begin
73
- settings = YAML.load_file(@config_file)
74
- ensure
75
- STDERR.puts "** Loading settings from #{@config_file} (they override command line)." unless @daemon || settings[:daemon]
76
- end
77
-
78
- # Config file settings will override command line settings
79
- settings.each do |key, value|
80
- key = key.to_s
81
- if config_keys.include?(key)
82
- key = 'address' if key == 'host'
83
- self.instance_variable_set("@#{key}", value)
32
+ # Builds a list of possible commands from the Command derivates list
33
+ def commands
34
+ GoldenBrindle::Actions.constants.inject([]) do |memo, action|
35
+ constants = constantize("GoldenBrindle::Actions::#{action.to_s}").constants
36
+ if constants.empty?
37
+ memo << action.to_s.downcase
84
38
  else
85
- failure "Unknown configuration setting: #{key}"
86
- @valid = false
39
+ constants.each do |subaction|
40
+ memo << "#{action.to_s}::#{subaction.to_s}".downcase
41
+ end
87
42
  end
43
+ memo
88
44
  end
89
45
  end
90
46
 
91
- # Returns true/false depending on whether the command is configured properly.
92
- def validate
93
- @valid
94
- end
95
-
96
- # Returns a help message. Defaults to OptionParser#help which should be good.
97
- def help
98
- @opt.help
99
- end
100
-
101
- # Runs the command doing it's job. You should implement this otherwise it will
102
- # throw a NotImplementedError as a reminder.
103
- def run
104
- raise NotImplementedError
105
- end
106
-
107
- # Validates the given expression is true and prints the message if not, exiting.
108
- def valid?(exp, message)
109
- if !@done_validating && !exp
110
- failure message
111
- @valid = false
112
- @done_validating = true
113
- end
114
- end
115
-
116
- # Validates that a file exists and if not displays the message
117
- def valid_exists?(file, message)
118
- valid?(File.exist?(file), message)
119
- end
120
-
121
- # Validates that the file is a file and not a directory or something else.
122
- def valid_file?(file, message)
123
- valid?(File.file?(file), message)
124
- end
125
-
126
- # Validates that the given directory exists
127
- def valid_dir?(file, message)
128
- valid?(File.directory?(file), message)
129
- end
130
-
131
- def can_change_user?
132
- valid?(Process.euid.to_i == 0, "if you want to change workers UID/GID you must run script from root")
133
- end
134
-
135
- def valid_user?(user)
136
- valid?(@group, "You must also specify a group.")
137
- can_change_user?
138
- begin
139
- Etc.getpwnam(user)
140
- rescue
141
- failure "User does not exist: #{user}"
142
- @valid = false
143
- end
144
- end
145
-
146
- def valid_group?(group)
147
- valid?(@user, "You must also specify a user.")
148
- begin
149
- Etc.getgrnam(group)
150
- rescue
151
- failure "Group does not exist: #{group}"
152
- @valid = false
153
- end
154
- end
155
-
156
- # Just a simple method to display failure until something better is developed.
157
- def failure(message)
158
- STDERR.puts "!!! #{message}"
159
- end
160
-
161
- end
162
-
163
- # A Singleton class that manages all of the available commands
164
- # and handles running them.
165
- class Registry
166
- include Singleton
167
-
168
- # Builds a list of possible commands from the Command derivates list
169
- def commands
170
- pmgr = GemPlugin::Manager.instance
171
- list = pmgr.plugins["/commands"].keys
172
- list.sort
173
- end
174
-
175
47
  # Prints a list of available commands.
176
48
  def print_command_list
177
49
  puts "#{GoldenBrindle::Const::BANNER}\nAvailable commands are:\n\n"
178
-
179
- self.commands.each do |name|
180
- if /brindle::/ =~ name
181
- name = name[9 .. -1]
182
- end
183
-
184
- puts " - #{name[1 .. -1]}\n"
50
+ commands.each do |name|
51
+ puts " - #{name}\n"
185
52
  end
186
53
 
187
54
  puts "\nEach command takes -h as an option to get help."
188
55
 
189
56
  end
190
57
 
191
-
192
58
  # Runs the args against the first argument as the command name.
193
59
  # If it has any errors it returns a false, otherwise it return true.
194
60
  def run(args)
@@ -204,10 +70,9 @@ module GoldenBrindle
204
70
  end
205
71
 
206
72
  begin
207
- if ["start", "stop", "restart", "configure", "reload"].include? cmd_name
208
- cmd_name = "brindle::" + cmd_name
209
- end
210
- command = GemPlugin::Manager.instance.create("/commands/#{cmd_name}", :argv => args)
73
+ cmd_name = cmd_name.split("::").map{|x| x.capitalize}.join("::")
74
+ constant = constantize("GoldenBrindle::Actions::#{cmd_name}")
75
+ command = constant.new(args)
211
76
  rescue OptionParser::InvalidOption
212
77
  STDERR.puts "#$! for command '#{cmd_name}'"
213
78
  STDERR.puts "Try #{cmd_name} -h to get help."
@@ -233,7 +98,7 @@ module GoldenBrindle
233
98
  true
234
99
  end
235
100
  end
236
-
101
+
237
102
  end
238
-
103
+
239
104
  end
@@ -1,12 +1,12 @@
1
1
  module GoldenBrindle
2
-
3
2
  module Const
4
-
5
3
  # current version
6
- VERSION="0.2"
4
+ VERSION="0.3"
7
5
  # main banner
8
6
  BANNER = "Usage: golden_brindle <command> [options]"
9
-
7
+ # config options names
8
+ CONFIG_KEYS = %w(address host port cwd log_file pid_file environment servers daemon debug config_script workers timeout user group prefix preload listen bundler)
9
+ ANSI_RED = "\033[0;31m"
10
+ ANSI_RESET = "\033[0m"
10
11
  end
11
-
12
12
  end
@@ -1,5 +1,6 @@
1
- module Brindle
1
+ module GoldenBrindle
2
2
  module Hooks
3
+
3
4
  def collect_hooks
4
5
  [:after_fork, :after_reload, :before_fork, :before_exec].inject({}) do |memo, sym|
5
6
  memo[sym] = send(sym)
@@ -1,4 +1,4 @@
1
- module Brindle
1
+ module GoldenBrindle
2
2
  class RailsSupport
3
3
  class << self
4
4
 
@@ -68,7 +68,7 @@ module Brindle
68
68
  unless defined?(ActionDispatch::Static)
69
69
  use Rails::Rack::Static
70
70
  end
71
- run Brindle::RailsSupport.rails_dispatcher
71
+ run ::GoldenBrindle::RailsSupport.rails_dispatcher
72
72
  end
73
73
  end
74
74
  end.to_app
@@ -0,0 +1,56 @@
1
+ module GoldenBrindle
2
+ module Validations
3
+
4
+ # Validates the given expression is true and prints the message if not, exiting.
5
+ def valid?(exp, message)
6
+ if !exp
7
+ failure message
8
+ @valid = false
9
+ end
10
+ end
11
+
12
+ # Validates that a file exists and if not displays the message
13
+ def valid_exists?(file, message)
14
+ valid?(File.exist?(file), message)
15
+ end
16
+
17
+ # Validates that the file is a file and not a directory or something else.
18
+ def valid_file?(file, message)
19
+ valid?(::File.file?(file), message)
20
+ end
21
+
22
+ # Validates that the given directory exists
23
+ def valid_dir?(file, message)
24
+ valid?(::File.directory?(file), message)
25
+ end
26
+
27
+ def can_change_user?
28
+ valid?(::Process.euid.zero?, "if you want to change workers UID/GID you must run programm from root")
29
+ end
30
+
31
+ def valid_user?(user)
32
+ return unless can_change_user?
33
+ begin
34
+ ::Etc.getpwnam(user)
35
+ rescue
36
+ failure "User does not exist: #{user}"
37
+ @valid = false
38
+ end
39
+ end
40
+
41
+ def valid_group?(group)
42
+ begin
43
+ ::Etc.getgrnam(group)
44
+ rescue
45
+ failure "Group does not exist: #{group}"
46
+ @valid = false
47
+ end
48
+ end
49
+
50
+ # Just a simple method to display failure until something better is developed.
51
+ def failure(message)
52
+ STDERR.puts "#{::GoldenBrindle::Const::ANSI_RED}!!! * #{message}#{::GoldenBrindle::Const::ANSI_RESET}"
53
+ end
54
+
55
+ end
56
+ end