procman 1.1.2 → 1.2.0

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.
data/Procfile CHANGED
@@ -1,19 +1,24 @@
1
- process :unicorn do
2
- start do
3
- puts "ENV: #{environment}"
4
- end
5
- stop {}
6
- restart {}
7
- end
1
+ process :example_worker do
8
2
 
9
- process :worker do
10
- start {}
11
- stop {}
12
- restart {}
13
- end
3
+ # Only action this process in production on a specific host
4
+ # constraint :environment => 'production', :host => 'app01.myapp.com'
14
5
 
15
- process :cron do
16
- start {}
17
- stop {}
18
- restart {}
6
+ # Only action this process in development
7
+ constraint :environment => 'development'
8
+
9
+ # Define the action to be carried out when this process should start
10
+ start do
11
+
12
+ end
13
+
14
+ # Define the action to be carried out when this process should stop
15
+ stop do
16
+
17
+ end
18
+
19
+ # Define the action to be carried out when this process should restart
20
+ restart do
21
+
22
+ end
23
+
19
24
  end
data/Procfile.template ADDED
@@ -0,0 +1,24 @@
1
+ process :example_worker do
2
+
3
+ # Only action this process in production on a specific host
4
+ # constraint :environment => 'production', :host => 'app01.myapp.com'
5
+
6
+ # Only action this process in development
7
+ # constraint :environment => 'development'
8
+
9
+ # Define the action to be carried out when this process should start
10
+ start do
11
+
12
+ end
13
+
14
+ # Define the action to be carried out when this process should stop
15
+ stop do
16
+
17
+ end
18
+
19
+ # Define the action to be carried out when this process should restart
20
+ restart do
21
+
22
+ end
23
+
24
+ end
data/README.md CHANGED
@@ -10,6 +10,28 @@ your application as a whole.
10
10
  The `Procfile` is a Ruby file which you can use to define how to manipulate
11
11
  your processes.
12
12
 
13
+ ## Setting up
14
+
15
+ If you're using Bundler (you should be) and wish to use procman, just include it within
16
+ your Gemfile and run `bundle` to install it.
17
+
18
+ ```ruby
19
+ gem 'procman'
20
+ ```
21
+
22
+ Once installed, you can execute commands as shown below but you should prefix `bundle exec`
23
+ to the start of the command.
24
+
25
+ ## Creating your initial Procfile
26
+
27
+ The command line tool allows you to create an example `Procfile` with a simple command. This
28
+ will create a `Procfile` in the root of the directory you are currently within. You can then
29
+ open this template and make changes as appropriate for your applications.
30
+
31
+ ```bash
32
+ $ procman init
33
+ ```
34
+
13
35
  ## Example Procfile
14
36
 
15
37
  Your Procfile can contain multiple types of process and each process should define
@@ -22,11 +44,11 @@ powered by our Ruby backgrounding system, rbg.
22
44
  process :unicorn do
23
45
 
24
46
  start do
25
- system("umask 002 && bundle exec unicorn_rails -E production -c config/unicorn.rb -D")
47
+ system("umask 002 && bundle exec unicorn_rails -E #{environment} -c #{root}/config/unicorn.rb -D")
26
48
  end
27
49
 
28
50
  stop do
29
- system("kill `cat tmp/pids/unicorn.production.pid`")
51
+ system("kill `cat #{root}/tmp/pids/unicorn.#{environment}.pid`")
30
52
  end
31
53
 
32
54
  restart { stop and start }
@@ -34,22 +56,46 @@ process :unicorn do
34
56
  end
35
57
 
36
58
  process :worker do
59
+
60
+ constraint :environment => 'production', :host => /\.production\.myapp\z/
61
+ constraint :environment => 'development', :host => /\.local\z/
37
62
 
38
63
  start do
39
- system("bundle exec rbg start -c config/processes/worker.rb -E production")
64
+ system("bundle exec rbg start -c #{root}/config/processes/worker.rb -E #{environment}")
40
65
  end
41
66
 
42
67
  stop do
43
- system("bundle exec rbg stop -c config/processes/worker.rb -E production")
68
+ system("bundle exec rbg stop -c #{root}/config/processes/worker.rb -E #{environment}")
44
69
  end
45
70
 
46
71
  restart do
47
- system("bundle exec rbg reload -c config/processes/worker.rb -E production")
72
+ system("bundle exec rbg reload -c #{root}/config/processes/worker.rb -E #{environment}")
48
73
  end
49
74
 
50
75
  end
51
76
  ```
52
77
 
78
+ ### Specifying constraints
79
+
80
+ If you only want certain processes to execute under certain environments or on specific hosts,
81
+ you can use constraints to restrict these.
82
+
83
+ You can specify any number of constraints for a process as shown below. If no constraints are defined
84
+ for a specific process, it will always be included when your action is executed. If a constraint is
85
+ added, the process's action will only be invoked when at least one of the constraints is matched otherwise
86
+ it will be skipped.
87
+
88
+ Constraints are configured by adding `constraint` "rules" to your process definitions.
89
+
90
+ ```ruby
91
+ # execute always in production
92
+ constraint :environment => 'production'
93
+ # execute on hosts where the hostname ends in .local
94
+ constraint :host => /\.local\z/
95
+ # execute in prodution and where the hostname is 'app01'
96
+ constraint :environment => 'production', :host => 'app01'
97
+ ```
98
+
53
99
  ## Executing process commands
54
100
 
55
101
  Once you have a Procfile, you can execute commands by sending them to the `procman`
@@ -60,6 +106,24 @@ the command using `bundle exec procman`.
60
106
  * `procman stop` - stop your processes
61
107
  * `procman restart` - restart your processes
62
108
 
109
+ In fact, you can define any actions you wish. You do not need to be constrained by start,
110
+ stop & restart. If you executed `procman jump`, it would call the `jump` method for each
111
+ process within your `Procfile`. There are various action names which are reserved, including:
112
+ `name`, `options`, `environment`, `host`, `root` and `constraint`.
113
+
114
+ Also, You can pass options to these methods to add extra functionality.
115
+
116
+ * `-e` - allows you specify the environment which is provided as the environment variable in your methods.
117
+ * `--processes` - allows you to specify which processes (comma separated) should be executed in the action.
118
+
119
+ Some examples of how to execute these options:
120
+
121
+ ```bash
122
+ $ procman start -e production
123
+ $ procman start -e production --processes worker
124
+ $ procman start --processes worker,unicorn
125
+ ```
126
+
63
127
  ## Executing on deployment
64
128
 
65
129
  You can use the included Capistrano recipe to automatically run your procman start/stop/restart
@@ -68,3 +132,5 @@ commands whenever you deploy. Just require the deploy recipes in your `Capfile`.
68
132
  ```ruby
69
133
  require 'proc_man/deploy'
70
134
  ```
135
+
136
+ This requires that you are using bundler and the `procman` gem has been included in your Gemfile.
data/bin/procman CHANGED
@@ -1,7 +1,29 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'proc_man'
3
3
  begin
4
- ProcMan.run(ARGV[0], ARGV[1])
4
+
5
+ # Convert command line arguments into the appropriate ruby objects
6
+ args = ARGV.dup
7
+ final_args = []
8
+ options = {}
9
+ until args.empty?
10
+ arg = args.shift
11
+ if arg =~ /\A\-/
12
+ options[arg.gsub(/\A\-+/, '').to_sym] = args.shift
13
+ else
14
+ final_args << arg
15
+ end
16
+ end
17
+
18
+ command = final_args.first
19
+ case command
20
+ when 'init'
21
+ ProcMan.init
22
+ else
23
+ # Execute the command
24
+ ProcMan.run(final_args.first, options)
25
+ end
26
+
5
27
  rescue ProcMan::Error => e
6
28
  puts "\e[31m" + e.message + "\e[0m"
7
29
  Process.exit(1)
data/lib/proc_man.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require 'proc_man/process'
2
2
  require 'proc_man/procfile'
3
+ require 'proc_man/constraint'
3
4
 
4
5
  module ProcMan
5
6
 
6
- VERSION = '1.1.2'
7
+ VERSION = '1.2.0'
7
8
 
8
9
  class Error < StandardError; end
9
10
 
@@ -22,16 +23,18 @@ module ProcMan
22
23
  @processes ||= Array.new
23
24
  end
24
25
 
25
- def run(method, environment = nil)
26
+ def run(method, options = {})
26
27
  load_procfile(File.expand_path('./Procfile'))
27
28
  if method.nil?
28
29
  raise Error, "Command to execute was not specified. For example, pass 'start' to start processes."
29
30
  else
30
31
  for process in self.processes
31
- process.environment = environment
32
+ process.options = options
32
33
  if process.defined_method?(method)
33
- puts "\e[33m#{method.capitalize}ing #{process.name}\e[0m"
34
- process.send(method)
34
+ if process.execute?
35
+ puts "\e[33m#{method.capitalize}ing #{process.name}\e[0m"
36
+ process.send(method)
37
+ end
35
38
  else
36
39
  puts "\e[31mThe #{process.name} process does not implement a '#{method}' method\e[0m"
37
40
  end
@@ -39,5 +42,17 @@ module ProcMan
39
42
  end
40
43
  end
41
44
 
45
+ # Create a new Procfile template in the current directory root
46
+ def init
47
+ path = File.expand_path('./Procfile')
48
+ if File.file?(path)
49
+ raise Error, "Procfile already exists at #{path}"
50
+ else
51
+ template_path = File.expand_path('../../Procfile.template', __FILE__)
52
+ File.open(path, 'w') { |f| f.write(File.read(template_path)) }
53
+ puts "\e[32mProcfile created at #{path}"
54
+ end
55
+ end
56
+
42
57
  end
43
58
  end
@@ -0,0 +1,34 @@
1
+ module ProcMan
2
+ class Constraint
3
+
4
+ def initialize(process, conditions)
5
+ @process = process
6
+ @conditions = conditions
7
+ end
8
+
9
+ def matches?
10
+ matches = 0
11
+ for key, value in @conditions
12
+ matches += 1 if compare(value, @process.send(key).to_s.downcase)
13
+ end
14
+ @conditions.size > 0 && matches == @conditions.size
15
+ end
16
+
17
+ private
18
+
19
+ def compare(condition, value)
20
+ value = value.to_s.downcase
21
+ case condition
22
+ when String
23
+ condition.to_s.downcase == value
24
+ when Regexp
25
+ !!condition.match(value)
26
+ when Array
27
+ condition.any? { |c| compare(c, value) }
28
+ else
29
+ false
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -20,7 +20,7 @@ Capistrano::Configuration.instance(:must_exist).load do
20
20
  after :restart, "procman:restart"
21
21
 
22
22
  def procman_command(command)
23
- command = "sh -c \"cd #{deploy_to} && bundle exec procman #{command} #{environment}\""
23
+ command = "sh -c \"cd #{deploy_to} && bundle exec procman #{command} --environment #{environment}\""
24
24
  if user = fetch(:procman_user, 'app')
25
25
  command = "sudo -u #{user} #{command}"
26
26
  end
@@ -1,24 +1,60 @@
1
1
  module ProcMan
2
2
  class Process
3
3
 
4
- attr_writer :environment
4
+ attr_writer :options
5
5
 
6
- def initialize(name, options = {})
6
+ # Initializes the new process by receiving it's name
7
+ def initialize(name)
7
8
  @name = name
9
+ @constraints = []
8
10
  end
9
11
 
12
+ # Returns the name of the process
10
13
  def name
11
14
  @name
12
15
  end
13
16
 
17
+ # Returns a hash of options which the user has specified
18
+ def options
19
+ @options ||= {}
20
+ end
21
+
22
+ # Returns the current environment
14
23
  def environment
15
- @environment || 'development'
24
+ self.options[:environment] || self.options[:e] || self.options[:env] || 'development'
16
25
  end
17
26
 
27
+ # Returns the current root directory path
18
28
  def root
19
29
  @root ||= File.expand_path('./')
20
30
  end
21
31
 
32
+ ## Returns the current hostname of the machine executing this action
33
+ def host
34
+ @host ||= `hostname -f`.strip
35
+ end
36
+
37
+ ## Sets a constraint for this process
38
+ def constraint(hash = {})
39
+ @constraints << Constraint.new(self, hash)
40
+ end
41
+
42
+ # Specifies whether or not actions for this process should be executed
43
+ # in the current context.
44
+ def execute?
45
+ (@constraints.empty? || @constraints.any?(&:matches?)) &&
46
+ (self.options[:processes].nil? || self.options[:processes].split(',').include?(self.name.to_s))
47
+ end
48
+
49
+ # Specifies whether or not the provided method has been defined in the Procfile
50
+ # for this process.
51
+ def defined_method?(name)
52
+ instance_variable_get("@#{name}").is_a?(Proc)
53
+ end
54
+
55
+ # Stores and calls different process actions for this process. If there is no
56
+ # block provided and we don't have a method it will return false otherwise it
57
+ # will store or call the action as appropriate.
22
58
  def method_missing(method, &block)
23
59
  if block_given?
24
60
  instance_variable_set("@#{method}", block)
@@ -29,9 +65,5 @@ module ProcMan
29
65
  end
30
66
  end
31
67
 
32
- def defined_method?(name)
33
- instance_variable_get("@#{name}").is_a?(Proc)
34
- end
35
-
36
68
  end
37
69
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: procman
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -20,13 +20,14 @@ extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
22
  - bin/procman
23
+ - lib/proc_man/constraint.rb
23
24
  - lib/proc_man/deploy.rb
24
25
  - lib/proc_man/process.rb
25
26
  - lib/proc_man/procfile.rb
26
27
  - lib/proc_man.rb
27
28
  - LICENCE
28
29
  - Procfile
29
- - procman-1.1.1.gem
30
+ - Procfile.template
30
31
  - procman.gemspec
31
32
  - README.md
32
33
  homepage: http://atechmedia.com
data/procman-1.1.1.gem DELETED
Binary file