capricorn 0.2.00
Sign up to get free protection for your applications and to get access to all the features.
- data/app_generators/engine/engine_generator.rb +39 -0
- data/app_generators/engine/templates/Gmfile +20 -0
- data/app_generators/engine/templates/MIT-LICENSE.txt +20 -0
- data/app_generators/engine/templates/README.rdoc +7 -0
- data/app_generators/engine/templates/config/routes.rb +2 -0
- data/app_generators/engine/templates/gitignore +3 -0
- data/app_generators/engine/templates/init.rb +1 -0
- data/app_generators/engine/templates/lib/engine.rb +1 -0
- data/app_generators/engine/templates/rails/init.rb +1 -0
- data/app_generators/engine/templates/tasks/engine_tasks.rake +4 -0
- data/bin/capricorn +20 -0
- data/lib/capricorn.rb +100 -0
- data/lib/capricorn/actor.rb +23 -0
- data/lib/capricorn/actor/actions.rb +76 -0
- data/lib/capricorn/actors/apache_actor.rb +56 -0
- data/lib/capricorn/actors/base_actor.rb +276 -0
- data/lib/capricorn/actors/mysql_actor.rb +20 -0
- data/lib/capricorn/actors/passenger_actor.rb +19 -0
- data/lib/capricorn/actors/plesk_actor.rb +210 -0
- data/lib/capricorn/actors/sqlite3_actor.rb +44 -0
- data/lib/capricorn/app_runner.rb +119 -0
- data/lib/capricorn/apps/dev.rb +15 -0
- data/lib/capricorn/apps/engines.rb +33 -0
- data/lib/capricorn/apps/jobs.rb +35 -0
- data/lib/capricorn/apps/satellite.rb +32 -0
- data/lib/capricorn/apps/server.rb +67 -0
- data/lib/capricorn/client.rb +48 -0
- data/lib/capricorn/client/auth_token.rb +98 -0
- data/lib/capricorn/daemon.rb +71 -0
- data/lib/capricorn/exception_handler.rb +79 -0
- data/lib/capricorn/extentions/rubygems_plugin.rb +27 -0
- data/lib/capricorn/extentions/thor_extentions.rb +32 -0
- data/lib/capricorn/job_queue.rb +199 -0
- data/lib/capricorn/satellite.rb +50 -0
- data/lib/capricorn/satellite/actions.rb +35 -0
- data/lib/capricorn/satellite/dependency_loader.rb +78 -0
- data/lib/capricorn/satellite/persistence.rb +50 -0
- data/lib/capricorn/server.rb +122 -0
- data/lib/capricorn/server/daemon.rb +88 -0
- data/lib/capricorn/server/proxy.rb +25 -0
- data/lib/capricorn/server/security.rb +113 -0
- data/lib/capricorn/system.rb +184 -0
- data/lib/capricorn/system/config.rb +49 -0
- data/lib/capricorn/system/helper.rb +21 -0
- data/lib/capricorn/system/options.rb +79 -0
- data/lib/capricorn/system/process_user.rb +73 -0
- data/lib/capricorn/system/satellites.rb +44 -0
- data/lib/capricorn/system/shell.rb +80 -0
- data/lib/rubygems_plugin.rb +1 -0
- data/spec/actor/actions_spec.rb +13 -0
- data/spec/spec_helper.rb +1 -0
- metadata +108 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
Capricorn.runtime_gem('thor', Capricorn::THOR_VERSION)
|
2
|
+
|
3
|
+
class Thor
|
4
|
+
class << self
|
5
|
+
attr_accessor :real_namespace # :nodoc:
|
6
|
+
end
|
7
|
+
def self.namespace=(value)
|
8
|
+
Thor.real_namespace = value
|
9
|
+
end
|
10
|
+
def self.namespace
|
11
|
+
Thor.real_namespace
|
12
|
+
end
|
13
|
+
self.namespace = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
module Thor::Util # :nodoc:
|
17
|
+
class << self
|
18
|
+
alias_method :old_constant_to_thor_path, :constant_to_thor_path
|
19
|
+
alias_method :old_constant_from_thor_path, :constant_from_thor_path
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.constant_to_thor_path(*args) # :nodoc:
|
23
|
+
path = old_constant_to_thor_path(*args)
|
24
|
+
path.sub! /^#{Thor.namespace}:/, '' if Thor.namespace
|
25
|
+
path
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.constant_from_thor_path(path) # :nodoc:
|
29
|
+
path = "#{Thor.namespace}:"+path if Thor.namespace
|
30
|
+
old_constant_from_thor_path(path)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Capricorn
|
4
|
+
class JobQueue
|
5
|
+
include DRbUndumped
|
6
|
+
|
7
|
+
# create a new job queue
|
8
|
+
def initialize
|
9
|
+
@immediated_jobs = Array.new
|
10
|
+
@canceled_jobs = Array.new
|
11
|
+
@job_queue = Array.new
|
12
|
+
@jobs = Hash.new
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@next_id = 1
|
15
|
+
|
16
|
+
@worker = Thread.new(self) do |job_queue|
|
17
|
+
while job_queue.running? or job_queue.peek
|
18
|
+
|
19
|
+
if job = job_queue.peek
|
20
|
+
job.run(job_queue)
|
21
|
+
job_queue.delete(job.id)
|
22
|
+
else
|
23
|
+
sleep(1)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# enqueue a new job with the given +name+, +options+ and +proc+
|
31
|
+
def enqueue(name, options={}, &proc)
|
32
|
+
@mutex.synchronize do
|
33
|
+
job = Job.new(@next_id, name, options, &proc)
|
34
|
+
@next_id += 1
|
35
|
+
@jobs[job.id] = job
|
36
|
+
@job_queue.push job.id
|
37
|
+
return job.id
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# dequeue the next job of the queue.
|
42
|
+
def dequeue
|
43
|
+
@mutex.synchronize do
|
44
|
+
id = @job_queue.shift
|
45
|
+
return @jobs.delete(id) if id
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# delete the job associated with the given +id+.
|
50
|
+
def delete(id)
|
51
|
+
@mutex.synchronize do
|
52
|
+
id = @job_queue.delete(id)
|
53
|
+
return @jobs.delete(id) if id
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# peek at the next job in the queue
|
58
|
+
def peek
|
59
|
+
job = nil
|
60
|
+
@mutex.synchronize do
|
61
|
+
id = @job_queue.first
|
62
|
+
job = @jobs[id] if id
|
63
|
+
end
|
64
|
+
job
|
65
|
+
end
|
66
|
+
|
67
|
+
# get the size of the job queue
|
68
|
+
def size
|
69
|
+
@mutex.synchronize do
|
70
|
+
@job_queue.size
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# cancel the job associated with the given +id+.
|
75
|
+
def cancel(id)
|
76
|
+
@mutex.synchronize do
|
77
|
+
id = @job_queue.delete(id)
|
78
|
+
if id
|
79
|
+
@jobs.delete(id)
|
80
|
+
@canceled_jobs.push(id)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# is the job associated with the given +id+ canceled.
|
86
|
+
def canceled?(id)
|
87
|
+
@mutex.synchronize do
|
88
|
+
return !@canceled_jobs.delete(id).nil?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# run the job associated with the given +id+ immediately.
|
93
|
+
def immediate(id)
|
94
|
+
@mutex.synchronize do
|
95
|
+
@immediated_jobs.push(id) if @jobs[id]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# should the job associated with the given +id+ be run immediately.
|
100
|
+
def immediated?(id)
|
101
|
+
@mutex.synchronize do
|
102
|
+
return !@immediated_jobs.delete(id).nil?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# join the worker thread
|
107
|
+
def join!
|
108
|
+
@worker.join
|
109
|
+
end
|
110
|
+
|
111
|
+
# wait until the queue is empty then stop the worker
|
112
|
+
def stop!
|
113
|
+
@mutex.synchronize do
|
114
|
+
@stopped = true
|
115
|
+
end
|
116
|
+
join!
|
117
|
+
end
|
118
|
+
|
119
|
+
# is the queue stopping or stopped?
|
120
|
+
def stopped?
|
121
|
+
@mutex.synchronize do
|
122
|
+
return !!@stopped
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# is the queue running
|
127
|
+
def running?
|
128
|
+
!stopped?
|
129
|
+
end
|
130
|
+
|
131
|
+
# iterate through all the jobs on the queue
|
132
|
+
def each
|
133
|
+
@mutex.synchronize do
|
134
|
+
@job_queue.each do |id|
|
135
|
+
job = @jobs[id]
|
136
|
+
canceled = @canceled_jobs.include?(id)
|
137
|
+
immediated = @immediated_jobs.include?(id)
|
138
|
+
|
139
|
+
yield(job, canceled, immediated)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class Job
|
145
|
+
include DRbUndumped
|
146
|
+
|
147
|
+
attr_accessor :id, :name, :options, :proc
|
148
|
+
|
149
|
+
def initialize(id, name, options={}, &proc)
|
150
|
+
@id = id.to_i
|
151
|
+
@mutex = Mutex.new
|
152
|
+
@name, @options, @proc = name, options, proc
|
153
|
+
@run_at = Time.now + (options.delete(:delay) || 30)
|
154
|
+
end
|
155
|
+
|
156
|
+
def delay
|
157
|
+
@mutex.synchronize do
|
158
|
+
delay = @run_at - Time.now
|
159
|
+
delay = 0 if delay < 0
|
160
|
+
return delay
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def running?
|
165
|
+
@mutex.synchronize do
|
166
|
+
return @running
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def waiting?
|
171
|
+
@mutex.synchronize do
|
172
|
+
return @waiting
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def run(job_queue)
|
177
|
+
Capricorn.report do
|
178
|
+
@waiting = true
|
179
|
+
immediated = canceled = false
|
180
|
+
Capricorn.log "waiting #{@run_at - Time.now}s."
|
181
|
+
until immediated or canceled or @run_at <= Time.now
|
182
|
+
sleep(1)
|
183
|
+
canceled = job_queue.canceled?(self.id)
|
184
|
+
immediated = job_queue.immediated?(self.id)
|
185
|
+
end
|
186
|
+
|
187
|
+
unless canceled
|
188
|
+
@waiting = false
|
189
|
+
@running = true
|
190
|
+
Capricorn.log("[queue]> #{@name}")
|
191
|
+
@proc.call(@options)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
module Capricorn
|
3
|
+
class Satellite
|
4
|
+
include DRbUndumped
|
5
|
+
|
6
|
+
autoload :Actions, File.dirname(__FILE__)+'/satellite/actions'
|
7
|
+
autoload :Persistence, File.dirname(__FILE__)+'/satellite/persistence'
|
8
|
+
autoload :DependencyLoader, File.dirname(__FILE__)+'/satellite/dependency_loader'
|
9
|
+
|
10
|
+
include Capricorn::Satellite::Actions
|
11
|
+
include Capricorn::Satellite::Persistence
|
12
|
+
|
13
|
+
attr_reader :domain, :engines
|
14
|
+
|
15
|
+
def initialize(domain)
|
16
|
+
if Hash === domain
|
17
|
+
domain.each do |name, value|
|
18
|
+
instance_variable_set("@#{name}".to_sym, value)
|
19
|
+
end
|
20
|
+
else
|
21
|
+
@domain = domain
|
22
|
+
@engines = {}
|
23
|
+
end
|
24
|
+
@domain.gsub! /^www\./, ''
|
25
|
+
end
|
26
|
+
|
27
|
+
def basedomain
|
28
|
+
unless @basedomain
|
29
|
+
parts = self.domain.split('.')
|
30
|
+
parts = parts[-2..-1]
|
31
|
+
@basedomain = parts.join('.')
|
32
|
+
end
|
33
|
+
@basedomain
|
34
|
+
end
|
35
|
+
|
36
|
+
def subdomain
|
37
|
+
unless @subdomain
|
38
|
+
parts = self.domain.split('.')
|
39
|
+
parts = parts[0..-3]
|
40
|
+
@subdomain = parts.join('.')
|
41
|
+
end
|
42
|
+
@subdomain unless @subdomain == ''
|
43
|
+
end
|
44
|
+
|
45
|
+
def subdomain?
|
46
|
+
!self.subdomain.nil?
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
module Capricorn
|
3
|
+
class Satellite
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
def add_engine(name, options={})
|
7
|
+
unless @engines.key? name
|
8
|
+
@engines[name] = options
|
9
|
+
true
|
10
|
+
else
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def update_engine(name, options={})
|
16
|
+
if @engines.key? name
|
17
|
+
@engines[name] = options
|
18
|
+
true
|
19
|
+
else
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove_engine(name)
|
25
|
+
if @engines.key? name
|
26
|
+
@engines.delete(name)
|
27
|
+
true
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Capricorn
|
4
|
+
class Satellite
|
5
|
+
class DependencyLoader
|
6
|
+
|
7
|
+
attr_reader :names, :specs, :engines
|
8
|
+
|
9
|
+
def self.load_for(engines)
|
10
|
+
dependency_loader = self.new(engines)
|
11
|
+
dependency_loader.add_dependecies!
|
12
|
+
dependency_loader.order_by_dependecies!
|
13
|
+
|
14
|
+
return dependency_loader
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(engines)
|
18
|
+
specs = engines.collect do |k,r|
|
19
|
+
s = Gem.source_index.find_name(k, Gem::Requirement.new(r[:version] || ">= 0.0.0"))
|
20
|
+
s.last
|
21
|
+
end.compact
|
22
|
+
|
23
|
+
@names = specs.collect { |spec| spec.name }
|
24
|
+
@specs = specs.inject({}) { |h, spec| h[spec.name] = spec ; h }
|
25
|
+
@engines = engines
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_dependecies!
|
29
|
+
@specs.values.each do |spec|
|
30
|
+
add_dependecies_for spec
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def order_by_dependecies!
|
35
|
+
@names = tsort
|
36
|
+
end
|
37
|
+
|
38
|
+
def each
|
39
|
+
@names.each do |name|
|
40
|
+
yield(@specs[name])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def reverse_each
|
45
|
+
@names.reverse.each do |name|
|
46
|
+
yield(@specs[name])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
include TSort
|
53
|
+
|
54
|
+
def add_dependecies_for(spec)
|
55
|
+
engine_dependencies = spec.engine_dependencies || {}
|
56
|
+
engine_dependencies.each do |name, options|
|
57
|
+
gems = Gem.source_index.find_name(name, [options[:version]].compact)
|
58
|
+
next unless gem = gems.last
|
59
|
+
next if @names.include?(name) and gem.version <= @specs[gem.name].version
|
60
|
+
@specs[gem.name] = gem
|
61
|
+
@names.push(gem.name)
|
62
|
+
add_dependecies_for(gem)
|
63
|
+
end
|
64
|
+
@engines = @engines.merge(engine_dependencies)
|
65
|
+
end
|
66
|
+
|
67
|
+
def tsort_each_node(&block)
|
68
|
+
@names.each(&block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def tsort_each_child(node, &block)
|
72
|
+
engine_dependencies = @specs[node].engine_dependencies || {}
|
73
|
+
engine_dependencies.keys.each(&block)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Capricorn
|
4
|
+
class Satellite
|
5
|
+
module Persistence
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend Capricorn::Satellite::Persistence::ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def load(data)
|
14
|
+
Capricorn::Satellite.new(YAML.load(data))
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_file(path)
|
18
|
+
return nil unless File.exist?(path)
|
19
|
+
Capricorn::Satellite.new(YAML.load_file(path))
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def dump(io=nil)
|
25
|
+
data = {}
|
26
|
+
|
27
|
+
private_vars = %w( basedomain subdomain )
|
28
|
+
instance_variables.each do |ivar_name|
|
29
|
+
ivar_name = ivar_name.to_s
|
30
|
+
ivar_name =~ /^@(.+)$/
|
31
|
+
name = $1
|
32
|
+
unless private_vars.include? name
|
33
|
+
data[name] = instance_variable_get(ivar_name.to_sym)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if io
|
38
|
+
io.write YAML.dump(data)
|
39
|
+
else
|
40
|
+
YAML.dump(data)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def dump_file(path)
|
45
|
+
File.open(path, 'w+') { |f| dump(f) }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|