capium 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/capium.rb +488 -0
  2. metadata +65 -0
data/lib/capium.rb ADDED
@@ -0,0 +1,488 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ require 'benchmark'
3
+ require 'capistrano/recipes/deploy/scm'
4
+ require 'capistrano/recipes/deploy/strategy'
5
+
6
+ def _cset(name, *args, &block)
7
+ unless exists?(name)
8
+ set(name, *args, &block)
9
+ end
10
+ end
11
+
12
+ # =========================================================================
13
+ # These variables MUST be set in the client capfiles. If they are not set,
14
+ # the deploy will fail with an error.
15
+ # =========================================================================
16
+
17
+ _cset(:application) { abort "Please specify the name of your application, set :application, 'foo'" }
18
+ _cset(:repository) { abort "Please specify the repository that houses your application's code, set :repository, 'foo'" }
19
+
20
+ # =========================================================================
21
+ # These variables may be set in the client capfile if their default values
22
+ # are not sufficient.
23
+ # =========================================================================
24
+
25
+ _cset :scm, :subversion
26
+ _cset :deploy_via, :checkout
27
+
28
+ _cset(:deploy_to) { "/u/apps/#{application}" }
29
+ _cset(:revision) { source.head }
30
+ _cset(:lithium_repo) { "git://github.com/UnionOfRAD/lithium.git"}
31
+ _cset(:lithium_branch) { "master" }
32
+
33
+ # =========================================================================
34
+ # These variables should NOT be changed unless you are very confident in
35
+ # what you are doing. Make sure you understand all the implications of your
36
+ # changes if you do decide to muck with these!
37
+ # =========================================================================
38
+
39
+ _cset(:source) { Capistrano::Deploy::SCM.new(scm, self) }
40
+ _cset(:real_revision) { source.local.query_revision(revision) { |cmd| with_env("LC_ALL", "C") { run_locally(cmd) } } }
41
+
42
+ _cset(:strategy) { Capistrano::Deploy::Strategy.new(deploy_via, self) }
43
+
44
+ # If overriding release name, please also select an appropriate setting for :releases below.
45
+ _cset(:release_name) { set :deploy_timestamped, true; Time.now.utc.strftime("%Y%m%d%H%M%S") }
46
+
47
+ _cset :version_dir, "releases"
48
+ _cset :shared_dir, "shared"
49
+ _cset :shared_children, ['libraries']
50
+ _cset :current_dir, "current"
51
+
52
+ _cset(:releases_path) { File.join(deploy_to, version_dir) }
53
+ _cset(:shared_path) { File.join(deploy_to, shared_dir) }
54
+ _cset(:current_path) { File.join(deploy_to, current_dir) }
55
+ _cset(:release_path) { File.join(releases_path, release_name) }
56
+
57
+ _cset(:releases) { capture("ls -x #{releases_path}", :except => { :no_release => true }).split.sort }
58
+ _cset(:current_release) { releases.length > 0 ? File.join(releases_path, releases.last) : nil }
59
+ _cset(:previous_release) { releases.length > 1 ? File.join(releases_path, releases[-2]) : nil }
60
+
61
+ _cset(:current_revision) { capture("cat #{current_path}/REVISION", :except => { :no_release => true }).chomp }
62
+ _cset(:latest_revision) { capture("cat #{current_release}/REVISION", :except => { :no_release => true }).chomp }
63
+ _cset(:previous_revision) { capture("cat #{previous_release}/REVISION", :except => { :no_release => true }).chomp if previous_release }
64
+
65
+ _cset(:run_method) { fetch(:use_sudo, true) ? :sudo : :run }
66
+
67
+ # some tasks, like symlink, need to always point at the latest release, but
68
+ # they can also (occassionally) be called standalone. In the standalone case,
69
+ # the timestamped release_path will be inaccurate, since the directory won't
70
+ # actually exist. This variable lets tasks like symlink work either in the
71
+ # standalone case, or during deployment.
72
+ _cset(:latest_release) { exists?(:deploy_timestamped) ? release_path : current_release }
73
+
74
+ # =========================================================================
75
+ # These are helper methods that will be available to your recipes.
76
+ # =========================================================================
77
+
78
+ # Auxiliary helper method for the `deploy:check' task. Lets you set up your
79
+ # own dependencies.
80
+ def depend(location, type, *args)
81
+ deps = fetch(:dependencies, {})
82
+ deps[location] ||= {}
83
+ deps[location][type] ||= []
84
+ deps[location][type] << args
85
+ set :dependencies, deps
86
+ end
87
+
88
+ # Temporarily sets an environment variable, yields to a block, and restores
89
+ # the value when it is done.
90
+ def with_env(name, value)
91
+ saved, ENV[name] = ENV[name], value
92
+ yield
93
+ ensure
94
+ ENV[name] = saved
95
+ end
96
+
97
+ # logs the command then executes it locally.
98
+ # returns the command output as a string
99
+ def run_locally(cmd)
100
+ logger.trace "executing locally: #{cmd.inspect}" if logger
101
+ output_on_stdout = nil
102
+ elapsed = Benchmark.realtime do
103
+ output_on_stdout = `#{cmd}`
104
+ end
105
+ if $?.to_i > 0 # $? is command exit code (posix style)
106
+ raise Capistrano::LocalArgumentError, "Command #{cmd} returned status code #{$?}"
107
+ end
108
+ logger.trace "command finished in #{(elapsed * 1000).round}ms" if logger
109
+ output_on_stdout
110
+ end
111
+
112
+ # If a command is given, this will try to execute the given command, as
113
+ # described below. Otherwise, it will return a string for use in embedding in
114
+ # another command, for executing that command as described below.
115
+ #
116
+ # If :run_method is :sudo (or :use_sudo is true), this executes the given command
117
+ # via +sudo+. Otherwise is uses +run+. If :as is given as a key, it will be
118
+ # passed as the user to sudo as, if using sudo. If the :as key is not given,
119
+ # it will default to whatever the value of the :admin_runner variable is,
120
+ # which (by default) is unset.
121
+ #
122
+ # THUS, if you want to try to run something via sudo, and what to use the
123
+ # root user, you'd just to try_sudo('something'). If you wanted to try_sudo as
124
+ # someone else, you'd just do try_sudo('something', :as => "bob"). If you
125
+ # always wanted sudo to run as a particular user, you could do
126
+ # set(:admin_runner, "bob").
127
+ def try_sudo(*args)
128
+ options = args.last.is_a?(Hash) ? args.pop : {}
129
+ command = args.shift
130
+ raise ArgumentError, "too many arguments" if args.any?
131
+
132
+ as = options.fetch(:as, fetch(:admin_runner, nil))
133
+ via = fetch(:run_method, :sudo)
134
+ if command
135
+ invoke_command(command, :via => via, :as => as)
136
+ elsif via == :sudo
137
+ sudo(:as => as)
138
+ else
139
+ ""
140
+ end
141
+ end
142
+
143
+ # Same as sudo, but tries sudo with :as set to the value of the :runner
144
+ # variable (which defaults to "app").
145
+ def try_runner(*args)
146
+ options = args.last.is_a?(Hash) ? args.pop : {}
147
+ args << options.merge(:as => fetch(:runner, "app"))
148
+ try_sudo(*args)
149
+ end
150
+
151
+
152
+ def capium()
153
+ set :deploy_to, "/var/www/#{application}" if (deploy_to.empty?)
154
+ after("deploy:setup", "lithium:setup")
155
+ after("deploy:symlink", "lithium:configure_library_path", "lithium:clear_cache")
156
+ end
157
+ # =========================================================================
158
+ # These are the tasks that are available to help with deploying web apps,
159
+ # and specifically, Rails applications. You can have cap give you a summary
160
+ # of them with `cap -T'.
161
+ # =========================================================================
162
+
163
+ namespace :deploy do
164
+ desc <<-DESC
165
+ Deploys your project. Handy wrapper to hook into the beginning of the deployment. Note that \
166
+ this will generally only work for applications that have already been deployed \
167
+ once. For a "cold" deploy, you'll want to take a look at the `deploy:cold' \
168
+ task, which handles the cold start specifically.
169
+ DESC
170
+ task :default do
171
+ update
172
+ end
173
+
174
+ desc <<-DESC
175
+ Prepares one or more servers for deployment. Before you can use any \
176
+ of the Capistrano deployment tasks with your project, you will need to \
177
+ make sure all of your servers have been prepared with `cap deploy:setup'. When \
178
+ you add a new server to your cluster, you can easily run the setup task \
179
+ on just that server by specifying the HOSTS environment variable:
180
+
181
+ $ cap HOSTS=new.server.com deploy:setup
182
+
183
+ It is safe to run this task on servers that have already been set up; it \
184
+ will not destroy any deployed revisions or data.
185
+ DESC
186
+ task :setup, :except => { :no_release => true } do
187
+ dirs = [deploy_to, releases_path, shared_path]
188
+ dirs += shared_children.map { |d| File.join(shared_path, d) }
189
+ run "#{try_sudo} mkdir -p #{dirs.join(' ')} && #{try_sudo} chmod g+w #{dirs.join(' ')}"
190
+ end
191
+
192
+ desc <<-DESC
193
+ Copies your project and updates the symlink. It does this in a \
194
+ transaction, so that if either `update_code' or `symlink' fail, all \
195
+ changes made to the remote servers will be rolled back, leaving your \
196
+ system in the same state it was in before `update' was invoked. Usually, \
197
+ you will want to call `deploy' instead of `update', but `update' can be \
198
+ handy if you want to deploy, but not immediately restart your application.
199
+ DESC
200
+ task :update do
201
+ transaction do
202
+ update_code
203
+ symlink
204
+ end
205
+ end
206
+
207
+ desc <<-DESC
208
+ Copies your project to the remote servers. This is the first stage \
209
+ of any deployment; moving your updated code and assets to the deployment \
210
+ servers. You will rarely call this task directly, however; instead, you \
211
+ should call the `deploy' task (to do a complete deploy) or the `update' \
212
+ task (if you want to perform the `restart' task separately).
213
+
214
+ You will need to make sure you set the :scm variable to the source \
215
+ control software you are using (it defaults to :subversion), and the \
216
+ :deploy_via variable to the strategy you want to use to deploy (it \
217
+ defaults to :checkout).
218
+ DESC
219
+ task :update_code, :except => { :no_release => true } do
220
+ on_rollback { run "rm -rf #{release_path}; true" }
221
+ strategy.deploy!
222
+ finalize_update
223
+ end
224
+
225
+ desc <<-DESC
226
+ [internal] Touches up the released code. This is called by update_code \
227
+ after the basic deploy finishes. It assumes a Rails project was deployed, \
228
+ so if you are deploying something else, you may want to override this \
229
+ task with your own environment's requirements.
230
+
231
+ This task will make the release group-writable (if the :group_writable \
232
+ variable is set to true, which is the default). It will then set up \
233
+ symlinks to the shared directory for the log, system, and tmp/pids \
234
+ directories, and will lastly touch all assets in public/images, \
235
+ public/stylesheets, and public/javascripts so that the times are \
236
+ consistent (so that asset timestamping works). This touch process \
237
+ is only carried out if the :normalize_asset_timestamps variable is \
238
+ set to true, which is the default.
239
+ DESC
240
+ task :finalize_update, :except => { :no_release => true } do
241
+ run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true)
242
+ end
243
+
244
+ desc <<-DESC
245
+ Updates the symlink to the most recently deployed version. Capistrano works \
246
+ by putting each new release of your application in its own directory. When \
247
+ you deploy a new version, this task's job is to update the `current' symlink \
248
+ to point at the new version. You will rarely need to call this task \
249
+ directly; instead, use the `deploy' task (which performs a complete \
250
+ deploy, including `restart') or the 'update' task (which does everything \
251
+ except `restart').
252
+ DESC
253
+ task :symlink, :except => { :no_release => true } do
254
+ on_rollback do
255
+ if previous_release
256
+ run "rm -f #{current_path}; ln -s #{previous_release} #{current_path}; true"
257
+ else
258
+ logger.important "no previous release to rollback to, rollback of symlink skipped"
259
+ end
260
+ end
261
+
262
+ run "rm -f #{current_path} && ln -s #{latest_release} #{current_path}"
263
+ end
264
+
265
+ desc <<-DESC
266
+ Copy files to the currently deployed version. This is useful for updating \
267
+ files piecemeal, such as when you need to quickly deploy only a single \
268
+ file. Some files, such as updated templates, images, or stylesheets, \
269
+ might not require a full deploy, and especially in emergency situations \
270
+ it can be handy to just push the updates to production, quickly.
271
+
272
+ To use this task, specify the files and directories you want to copy as a \
273
+ comma-delimited list in the FILES environment variable. All directories \
274
+ will be processed recursively, with all files being pushed to the \
275
+ deployment servers.
276
+
277
+ $ cap deploy:upload FILES=templates,controller.rb
278
+
279
+ Dir globs are also supported:
280
+
281
+ $ cap deploy:upload FILES='config/apache/*.conf'
282
+ DESC
283
+ task :upload, :except => { :no_release => true } do
284
+ files = (ENV["FILES"] || "").split(",").map { |f| Dir[f.strip] }.flatten
285
+ abort "Please specify at least one file or directory to update (via the FILES environment variable)" if files.empty?
286
+
287
+ files.each { |file| top.upload(file, File.join(current_path, file)) }
288
+ end
289
+
290
+ namespace :rollback do
291
+ desc <<-DESC
292
+ [internal] Points the current symlink at the previous revision.
293
+ This is called by the rollback sequence, and should rarely (if
294
+ ever) need to be called directly.
295
+ DESC
296
+ task :revision, :except => { :no_release => true } do
297
+ if previous_release
298
+ run "rm #{current_path}; ln -s #{previous_release} #{current_path}"
299
+ else
300
+ abort "could not rollback the code because there is no prior release"
301
+ end
302
+ end
303
+
304
+ desc <<-DESC
305
+ [internal] Removes the most recently deployed release.
306
+ This is called by the rollback sequence, and should rarely
307
+ (if ever) need to be called directly.
308
+ DESC
309
+ task :cleanup, :except => { :no_release => true } do
310
+ run "if [ `readlink #{current_path}` != #{current_release} ]; then rm -rf #{current_release}; fi"
311
+ end
312
+
313
+ desc <<-DESC
314
+ Rolls back to the previously deployed version. The `current' symlink will \
315
+ be updated to point at the previously deployed version, and then the \
316
+ current release will be removed from the servers.
317
+ DESC
318
+ task :code, :except => { :no_release => true } do
319
+ revision
320
+ cleanup
321
+ end
322
+
323
+ desc <<-DESC
324
+ Rolls back to a previous version and restarts. This is handy if you ever \
325
+ discover that you've deployed a lemon; `cap rollback' and you're right \
326
+ back where you were, on the previously deployed version.
327
+ DESC
328
+ task :default do
329
+ revision
330
+ cleanup
331
+ end
332
+ end
333
+
334
+ desc <<-DESC
335
+ Clean up old releases. By default, the last 5 releases are kept on each \
336
+ server (though you can change this with the keep_releases variable). All \
337
+ other deployed revisions are removed from the servers. By default, this \
338
+ will use sudo to clean up the old releases, but if sudo is not available \
339
+ for your environment, set the :use_sudo variable to false instead.
340
+ DESC
341
+ task :cleanup, :except => { :no_release => true } do
342
+ count = fetch(:keep_releases, 5).to_i
343
+ if count >= releases.length
344
+ logger.important "no old releases to clean up"
345
+ else
346
+ logger.info "keeping #{count} of #{releases.length} deployed releases"
347
+
348
+ directories = (releases - releases.last(count)).map { |release|
349
+ File.join(releases_path, release) }.join(" ")
350
+
351
+ try_sudo "rm -rf #{directories}"
352
+ end
353
+ end
354
+
355
+ desc <<-DESC
356
+ Test deployment dependencies. Checks things like directory permissions, \
357
+ necessary utilities, and so forth, reporting on the things that appear to \
358
+ be incorrect or missing. This is good for making sure a deploy has a \
359
+ chance of working before you actually run `cap deploy'.
360
+
361
+ You can define your own dependencies, as well, using the `depend' method:
362
+
363
+ depend :remote, :gem, "tzinfo", ">=0.3.3"
364
+ depend :local, :command, "svn"
365
+ depend :remote, :directory, "/u/depot/files"
366
+ DESC
367
+ task :check, :except => { :no_release => true } do
368
+ dependencies = strategy.check!
369
+
370
+ other = fetch(:dependencies, {})
371
+ other.each do |location, types|
372
+ types.each do |type, calls|
373
+ if type == :gem
374
+ dependencies.send(location).command(fetch(:gem_command, "gem")).or("`gem' command could not be found. Try setting :gem_command")
375
+ end
376
+
377
+ calls.each do |args|
378
+ dependencies.send(location).send(type, *args)
379
+ end
380
+ end
381
+ end
382
+
383
+ if dependencies.pass?
384
+ puts "You appear to have all necessary dependencies installed"
385
+ else
386
+ puts "The following dependencies failed. Please check them and try again:"
387
+ dependencies.reject { |d| d.pass? }.each do |d|
388
+ puts "--> #{d.message}"
389
+ end
390
+ abort
391
+ end
392
+ end
393
+
394
+ desc <<-DESC
395
+ Deploys and starts a `cold' application. This is useful if you have not \
396
+ deployed your application before, or if your application is (for some \
397
+ other reason) not currently running. It will deploy the code, run any \
398
+ pending migrations, and then instead of invoking `deploy:restart', it will \
399
+ invoke `deploy:start' to fire up the application servers.
400
+ DESC
401
+ task :cold do
402
+ update
403
+ end
404
+
405
+ namespace :pending do
406
+ desc <<-DESC
407
+ Displays the `diff' since your last deploy. This is useful if you want \
408
+ to examine what changes are about to be deployed. Note that this might \
409
+ not be supported on all SCM's.
410
+ DESC
411
+ task :diff, :except => { :no_release => true } do
412
+ system(source.local.diff(current_revision))
413
+ end
414
+
415
+ desc <<-DESC
416
+ Displays the commits since your last deploy. This is good for a summary \
417
+ of the changes that have occurred since the last deploy. Note that this \
418
+ might not be supported on all SCM's.
419
+ DESC
420
+ task :default, :except => { :no_release => true } do
421
+ from = source.next_revision(current_revision)
422
+ system(source.local.log(from))
423
+ end
424
+ end
425
+
426
+ end
427
+
428
+ namespace :lithium do
429
+
430
+ desc <<-DESC
431
+ Prepares server for deployment of a Lithium application. \
432
+
433
+ By default, it will create a shallow clone of the Lithium repository \
434
+ inside {shared_path}/libraries/lithium and run deploy:lithium:update.
435
+
436
+ For more info about shallow clones: \
437
+ http://www.kernel.org/pub/software/scm/git/docs/git-clone.html \
438
+
439
+ Further customization will require that you write your own task.
440
+ DESC
441
+ task :setup do
442
+ run "cd #{shared_path}/libraries && #{try_sudo} git clone --depth 1 #{lithium_repo} lithium"
443
+ set :git_flag_quiet, "-q "
444
+ update
445
+ end
446
+ desc <<-DESC
447
+ Force Lithium installation to checkout a new branch/tag. \
448
+
449
+ By default, it will checkout the :lithium_branch you set in \
450
+ deploy.rb, but you can change that on runtime by specifying \
451
+ the BRANCH environment variable:
452
+
453
+ $ cap deploy:lithium:update \\
454
+ BRANCH="lithium-0.10"
455
+
456
+ Further customization will require that you write your own task.
457
+ DESC
458
+ task :update do
459
+ set :lithium_branch, ENV['BRANCH'] if ENV.has_key?('BRANCH')
460
+ stream "cd #{shared_path}/libraries/lithium && #{try_sudo} git checkout #{git_flag_quiet}#{lithium_branch}"
461
+ end
462
+
463
+ desc <<-DESC
464
+ Sets the path to the class libraries used by your Lithium application. \
465
+ This directory contain a copy of the Lithium core.
466
+ DESC
467
+ task :configure_library_path do
468
+ run "sed -i \"s/^define('LITHIUM_LIBRARY_PATH.*$/define('LITHIUM_LIBRARY_PATH', dirname(dirname(LITHIUM_APP_PATH)) . '\\/shared\\/libraries');/\" #{release_path}/config/bootstrap/libraries.php"
469
+ end
470
+
471
+ desc <<-DESC
472
+ Blow up all the cache files Lithium uses, ensuring a clean restart.
473
+ DESC
474
+ task :clear_cache do
475
+ run "rm -rf #{release_path}/resources/tmp/*"
476
+
477
+ run [
478
+ "mkdir -p #{release_path}/resources/tmp/cache/templates",
479
+ "mkdir -p #{release_path}/resources/tmp/logs",
480
+ "mkdir -p #{release_path}/resources/tmp/tests",
481
+
482
+ "chmod -R 777 #{release_path}/resources",
483
+ ].join(' && ')
484
+ end
485
+
486
+ end
487
+
488
+ end # Capistrano::Configuration.instance(:must_exist).load do
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capium
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Mehdi Lahmam B.
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-13 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: Deploy a Lithium app using Capistrano made easy
22
+ email: mehdi@lahmam.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/capium.rb
31
+ homepage: http://rubygems.org/gems/capium
32
+ licenses: []
33
+
34
+ post_install_message:
35
+ rdoc_options: []
36
+
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ hash: 3
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.8
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: A Capistrano deploy recipe for Lithium.
64
+ test_files: []
65
+