edploy 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/MIT-LICENSE +92 -0
  4. data/README.rdoc.fast_remote_cache +48 -0
  5. data/Rakefile +1 -0
  6. data/TODO.TXT +17 -0
  7. data/bin/dploy +15 -0
  8. data/bin/dploygen +39 -0
  9. data/bin/dployify +29 -0
  10. data/edploy.gemspec +21 -0
  11. data/lib/capistrano/ext/mailer.rb +90 -0
  12. data/lib/capistrano/ext/multistage.rb +59 -0
  13. data/lib/capistrano/ext/output_catcher.rb +97 -0
  14. data/lib/capistrano/ext/output_hooks.rb +54 -0
  15. data/lib/capistrano/recipes/deploy/strategy/fast_remote_cache.rb +44 -0
  16. data/lib/capistrano/recipes/deploy/strategy/utilities/copy.rb +53 -0
  17. data/lib/edploy/environment_capistrano.rb +19 -0
  18. data/lib/edploy/recipes/apache.rb +8 -0
  19. data/lib/edploy/recipes/bundle_install.rb +15 -0
  20. data/lib/edploy/recipes/fast_remote_cache.rb +43 -0
  21. data/lib/edploy/recipes/fast_remote_cache_extensions.rb +11 -0
  22. data/lib/edploy/recipes/hooks.rb +24 -0
  23. data/lib/edploy/recipes/production.rb +56 -0
  24. data/lib/edploy/recipes/rails.rb +5 -0
  25. data/lib/edploy/recipes/setup_project.rb +26 -0
  26. data/lib/edploy/recipes/smart_deploy.rb +47 -0
  27. data/lib/edploy/recipes/templates.rb +60 -0
  28. data/lib/edploy/recipes/web_disable_enable.rb +32 -0
  29. data/lib/edploy.rb +17 -0
  30. data/lib/edployify/configuration.rb +140 -0
  31. data/lib/edployify/preferences.rb +176 -0
  32. data/lib/edployify/project.rb +69 -0
  33. data/lib/edployify/template.rb +84 -0
  34. data/lib/edployify.rb +6 -0
  35. data/lib/edployscripts/archive.rb +27 -0
  36. data/lib/edployscripts/environment_scripts.rb +47 -0
  37. data/lib/edployscripts/file_handling.rb +28 -0
  38. data/lib/edployscripts/git.rb +27 -0
  39. data/lib/edployscripts.rb +6 -0
  40. data/templates/config/edploy/copy/extract/.gitkeep +0 -0
  41. data/templates/config/edploy/copy/init_scripts/.gitkeep +0 -0
  42. data/templates/config/edploy/copy/project_files/.gitkeep +0 -0
  43. data/templates/config/edploy/scripts/after_deploy_setup/.gitkeep +0 -0
  44. data/templates/config/edploy/scripts/after_deploy_symlink/passenger/clear_file_cache.erb +7 -0
  45. data/templates/config/edploy/scripts/after_deploy_update_code/make_symlinks.erb +74 -0
  46. data/templates/config/edploy/scripts/edploygen/01_bundle_install.erb +5 -0
  47. data/templates/config/edploy/scripts/edploygen/01_prepare_servers.post.erb +12 -0
  48. data/templates/config/edploy/scripts/edploygen/02_whenever_configs.erb +36 -0
  49. data/templates/config/edploy/templates/passenger/activate.rb.erb +2 -0
  50. data/templates/config/edploy/templates/passenger/after_config.rb.erb +2 -0
  51. data/templates/config/edploy/templates/passenger/apache_vhost.erb.erb +107 -0
  52. data/templates/config/edploy/templates/passenger/config.rb.erb +3 -0
  53. data/templates/config/edploy/templates/passenger/deactivate.rb.erb +1 -0
  54. data/templates/config/edploy/whenever/generic.rb.erb +12 -0
  55. metadata +113 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in edploy.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,92 @@
1
+ edploy gem, and all code and files, excluding what's mentioned below:
2
+
3
+ # Copyright (c) 2012 by Ewout Vonk, All rights reserved.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ fast_remote_cache rails plugin:
25
+
26
+ # Copyright (c) 2008 by 37signals, LLC
27
+ #
28
+ # Permission is hereby granted, free of charge, to any person obtaining
29
+ # a copy of this software and associated documentation files (the
30
+ # "Software"), to deal in the Software without restriction, including
31
+ # without limitation the rights to use, copy, modify, merge, publish,
32
+ # distribute, sublicense, and/or sell copies of the Software, and to
33
+ # permit persons to whom the Software is furnished to do so, subject to
34
+ # the following conditions:
35
+ #
36
+ # The above copyright notice and this permission notice shall be
37
+ # included in all copies or substantial portions of the Software.
38
+ #
39
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
40
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
41
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
42
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
43
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
44
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
45
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46
+
47
+ multistage capistrano extension:
48
+
49
+ # Copyright (c) 2006 Jamis Buck
50
+ #
51
+ # Permission is hereby granted, free of charge, to any person obtaining
52
+ # a copy of this software and associated documentation files (the
53
+ # "Software"), to deal in the Software without restriction, including
54
+ # without limitation the rights to use, copy, modify, merge, publish,
55
+ # distribute, sublicense, and/or sell copies of the Software, and to
56
+ # permit persons to whom the Software is furnished to do so, subject to
57
+ # the following conditions:
58
+ #
59
+ # The above copyright notice and this permission notice shall be
60
+ # included in all copies or substantial portions of the Software.
61
+ #
62
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
63
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
64
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
65
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
66
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
67
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
68
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
69
+
70
+ mailer capistrano plugin:
71
+
72
+ # Copyright (c) 2009 9thBit LLC (http://www.9thbit.net)
73
+ # Copyright (c) 2007-8 Sagebit, LLC (http://www.sagebit.com)
74
+ #
75
+ # Permission is hereby granted, free of charge, to any person obtaining
76
+ # a copy of this software and associated documentation files (the
77
+ # "Software"), to deal in the Software without restriction, including
78
+ # without limitation the rights to use, copy, modify, merge, publish,
79
+ # distribute, sublicense, and/or sell copies of the Software, and to
80
+ # permit persons to whom the Software is furnished to do so, subject to
81
+ # the following conditions:
82
+ #
83
+ # The above copyright notice and this permission notice shall be
84
+ # included in all copies or substantial portions of the Software.
85
+ #
86
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
88
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
89
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
90
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
91
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
92
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,48 @@
1
+ = Fast Remote Cache
2
+
3
+ The FastRemoteCache is a custom deployment strategy that specializes the standard RemoteCache strategy. It works just like the RemoteCache, but instead of actually copying the cache to the final release directory, it uses a custom "copy.rb" script to hard link the files. This allows the copy stage to be very fast.
4
+
5
+ For small applications, and especially for those that aren't bundling vendor/rails, this won't make much of a difference. But for large applications the speed-up will be significant.
6
+
7
+ == Dependencies
8
+
9
+ * Capistrano 2 or later (http://www.capify.org)
10
+
11
+ == Assumptions
12
+
13
+ The FastRemoteCache, as the RemoteCache, assumes that your source repository is accessible from both your local (deploying) host, as well as the remote (target) hosts. If either of these is not true, you will not be able to use the FastRemoteCache strategy.
14
+
15
+ Furthermore, it assumes that you have Ruby (1.8.6, preferably) installed on the target machines. If it is not installed in a standard location, you can set the :ruby variable to the location of the ruby executable.
16
+
17
+ == Usage
18
+
19
+ When using this with Rails applications, all you need to do is install this as a plugin in your application. Make sure your Capfile has a line like the following:
20
+
21
+ Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
22
+
23
+ It should be just before the line that loads the 'config/deploy' file. If that line is not there, add it (or rerun "capify .").
24
+
25
+ If you are not using this with a Rails application, you'll need to explicitly load recipes/fast_remote_cache.rb in your Capfile.
26
+
27
+ Next, tell Capistrano to use the fast_remote_cache deployment strategy by putting the following line in your config/deploy.rb (or Capfile, if you aren't deploying a Rails app):
28
+
29
+ set :deploy_via, :fast_remote_cache
30
+
31
+ Lastly, if you want to exclude certain directories or files from being deployed, set the copy_exclude variable:
32
+
33
+ set :copy_exclude, %w(test .git doc config/database.yml)
34
+
35
+ The copy_exclude array can also include glob patterns, if you want to get tricky.
36
+
37
+ == Tips
38
+
39
+ For the fastest possible deploys:
40
+
41
+ * Always deploy as the same user. If you're part of a team where everyone can (and does) deploy, create a new user (e.g., "deploy") and set it up so that your team can all log in as this user. Make sure this user also has read access to your source code repository.
42
+ * Avoid sudo if at all possible. set(:use_sudo, false), and then make sure that the deploy user has sufficient permissions to start and stop the mongrels, write to the necessary directories, etc.
43
+ * Disable the "group_writable" setting: set(:group_writable, false). This is only necessary when you have multiple users deploying.
44
+ * Don't include Rails (or other large libraries) in your application. Yes, it is convenient to include them, but they bloat your app and make checkouts and copies much slower. You have to balance convenience in development versus speed of deployment. Find a compromise that works for you.
45
+
46
+ == License
47
+
48
+ This code is released under the MIT license, and is copyright (c) 2008 by 37signals, LLC. Please see the accompanying LICENSE file for the full text of the license.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/TODO.TXT ADDED
@@ -0,0 +1,17 @@
1
+ - minimal_output integrated with hooks like deploy hooks, but then for output
2
+ - heroku style output
3
+ - mailer (mailing of notifications; mailing of actual deploy output)
4
+
5
+ --
6
+
7
+ - add bundle_path and bundle_without to deploy.yml + configuration questions
8
+ - make prepare tasks standard part of deploygen, turn it on/off in deploy.yml
9
+
10
+ --
11
+
12
+ - add configuration (enabling) of smart deploys
13
+ - extend dploy script to enable auto-detection of current stage (check current git branch, find stage which has that branch configured for deployment)
14
+
15
+ --
16
+
17
+ - add process launcher to system wide scripts, which outputs output line-by-line
data/bin/dploy ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2009-2012 by Ewout Vonk. All rights reserved.
4
+
5
+ abort "Please run this command from the Rails.root" unless File.file?('config/routes.rb')
6
+
7
+ if ENV['BUNDLE_GEMFILE'].nil? || ENV['BUNDLE_BIN_PATH'].nil?
8
+ system([ 'bundle', 'exec', File.basename($0), ARGV.first ].compact.join(' '))
9
+ end
10
+
11
+ def determine_stage
12
+ stage = ARGV.first || 'staging'
13
+ end
14
+
15
+ system("cap #{determine_stage} deploy:smart")
data/bin/dploygen ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2009-2012 by Ewout Vonk. All rights reserved.
4
+
5
+ abort "Please run this command from the Rails.root" unless File.file?('config/routes.rb')
6
+
7
+ if ENV['BUNDLE_GEMFILE'].nil? || ENV['BUNDLE_BIN_PATH'].nil?
8
+ system([ 'bundle', 'exec', File.basename($0) ].compact.join(' '))
9
+ end
10
+
11
+ require 'edployscripts'
12
+
13
+ def scripts(match_glob = "*", ignore_globs = [])
14
+ Dir[File.join(::RAILS_ROOT, 'config', 'edploy', 'scripts', 'edploygen', match_glob)].sort.each do |script_file|
15
+ script_name = File.basename(script_file)
16
+ next if ignore_globs.any? { |glob| File.fnmatch?(glob, script_name) }
17
+ script script_name
18
+ end
19
+ end
20
+
21
+ def script(script_name)
22
+ cmd = File.join(::RAILS_ROOT, 'config', 'edploy', 'scripts', 'edploygen', script_name.to_s)
23
+ system(cmd) or abort "error while running `#{cmd}'"
24
+ end
25
+
26
+ begin
27
+ scripts "*.pre"
28
+ Edploy::Git.stash :silent => true
29
+ scripts "*", %w(*.pre *.post)
30
+ Edploy::Git.commit :message => 'edploygen', :silent => true
31
+ Edploy::Git.push :silent => true
32
+ scripts "*.post"
33
+ rescue SystemExit => e
34
+ Edploy::Git.reset :hard => true
35
+ Edploy::Git.stash :pop, :silent => true
36
+ exit(1)
37
+ rescue Exception => e
38
+ raise e
39
+ end
data/bin/dployify ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2009-2012 by Ewout Vonk. All rights reserved.
4
+
5
+ abort "Please run this command from the Rails.root" unless File.file?('config/routes.rb')
6
+
7
+ if ENV['BUNDLE_GEMFILE'].nil? || ENV['BUNDLE_BIN_PATH'].nil?
8
+ system([ 'bundle', 'exec', File.basename($0) ].compact.join(' '))
9
+ end
10
+
11
+ require 'open3'
12
+ require 'edployify'
13
+
14
+ RAILS_ROOT = Dir.getwd
15
+
16
+ if ARGV.include?('prefs')
17
+ Edployify::Preferences.configure
18
+ else
19
+ Edployify::Project.before_capify_clean
20
+ Open3.popen3("capify .") do
21
+ puts "Running `capify .'"
22
+ end
23
+ Edployify::Project.after_capify_clean
24
+ Edployify::Template.make_dirs
25
+ Edployify::Configuration.configure
26
+ Edployify::Template.generate_templates(Edployify::Configuration.get_binding)
27
+ puts "[done] edployified!"
28
+ end
29
+
data/edploy.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "edploy"
6
+ s.version = "2.0.0"
7
+ s.authors = ["Ewout Vonk"]
8
+ s.email = ["dev@ewout.to"]
9
+ s.homepage = "https://github.com/ewoutvonk/edploy"
10
+ s.summary = %q{A gem which allows for fast, easy and efficient deploys with capistrano}
11
+ s.description = %q{A gem which allows for fast, easy and efficient deploys with capistrano}
12
+
13
+ s.rubyforge_project = "edploy"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_runtime_dependency "capistrano"
21
+ end
@@ -0,0 +1,90 @@
1
+ # Copyright (c) 2009-2011 by Ewout Vonk. All rights reserved.
2
+ # Copyright (c) 2009 9thBit LLC (http://www.9thbit.net)
3
+ # Copyright (c) 2007-8 Sagebit, LLC (http://www.sagebit.com)
4
+
5
+ # prevent loading when called by Bundler, only load when called by capistrano
6
+ if caller.any? { |callstack_line| callstack_line =~ /^Capfile:/ }
7
+ unless Capistrano::Configuration.respond_to?(:instance)
8
+ abort "capistrano-mailer requires Capistrano 2"
9
+ end
10
+
11
+ require 'action_mailer' unless defined?(ActionMailer)
12
+
13
+ module Capistrano
14
+ module Configuration
15
+
16
+ class ActionMailer < ActionMailer::Base
17
+ delivery_method = :smtp
18
+
19
+ smtp_settings = {
20
+ :address => 'localhost',
21
+ :port => 25,
22
+ :enable_starttls_auto => false
23
+ }
24
+
25
+ default :charset => 'utf-8'
26
+
27
+ def notify(textbody, options, mail_attachments)
28
+ mail_attachments.each do |filename, contents|
29
+ if File.exists?(filename.to_s)
30
+ attachments[File.basename(filename.to_s)] = File.read(filename.to_s)
31
+ elsif File.exists?(contents.to_s)
32
+ attachments[File.basename(contents.to_s)] = File.read(contents.to_s)
33
+ else
34
+ attachments[File.basename(filename.to_s)] = contents
35
+ end
36
+ end
37
+ mail(options) do |format|
38
+ format.text { render :text => textbody }
39
+ end
40
+ end
41
+ end
42
+
43
+ class Mailer
44
+
45
+ def send(sender, recipients, subject, text_body, cc = nil, bcc = nil, attachments = {})
46
+ configure
47
+ options = {
48
+ :from => sender,
49
+ :to => recipients,
50
+ :subject => subject,
51
+ :cc => cc,
52
+ :bcc => bcc
53
+ }
54
+ Capistrano::Configuration::ActionMailer.notify(textbody, options, attachments).deliver
55
+ end
56
+
57
+ private
58
+
59
+ def configure
60
+ return if @configured
61
+ if (fetch(:mailer_address, nil) || fetch(:mailer_port, nil) || fetch(:mailer_domain, nil))
62
+ Capistrano::Configuration::ActionMailer.delivery_method = :smtp
63
+ Capistrano::Configuration::ActionMailer.smtp_settings = {
64
+ :address => fetch(:mailer_address, 'localhost'),
65
+ :port => fetch(:mailer_port, 25),
66
+ :domain => fetch(:mailer_domain, nil), # example: "default.com"
67
+ :user_name => fetch(:mailer_user_name, nil), # example: "releases@example.com"
68
+ :password => fetch(:mailer_password, nil), # example: "mypassword"
69
+ :authentication => fetch(:mailer_authentication, nil), # example: :login
70
+ :openssl_verify_mode => fetch(:mailer_openssl_verify_mode, nil),
71
+ :enable_starttls_auto => fetch(:mailer_enable_starttls_auto, false)
72
+ }
73
+ elsif (location = fetch(:mailer_location, nil))
74
+ Capistrano::Configuration::ActionMailer.delivery_method = :sendmail
75
+ Capistrano::Configuration::ActionMailer.sendmail_settings = {
76
+ :location => location,
77
+ :arguments => fetch(:mailer_arguments, nil)
78
+ }
79
+ end
80
+ Capistrano::Configuration::ActionMailer.default :charset => fetch(:mailer_default_charset, 'utf-8')
81
+ @configured = true
82
+ end
83
+
84
+ end
85
+ end
86
+ end
87
+
88
+ Capistrano.plugin :mailer, Capistrano::Configuration::Mailer
89
+
90
+ end
@@ -0,0 +1,59 @@
1
+ # ---------------------------------------------------------------------------
2
+ # This file is distributed under the terms of the MIT license by Jamis Buck,
3
+ # and is copyright (c) 2006 by the same. See the MIT-LICENSE file distributed
4
+ # with this file for the complete text of the license.
5
+ # ---------------------------------------------------------------------------
6
+ require 'fileutils'
7
+ location = File.join(rails_root, 'config', 'edploy', 'stages')
8
+
9
+ unless exists?(:stages)
10
+ set :stages, Dir["#{location}/*.rb"].map { |f| File.basename(f, ".rb") }
11
+ end
12
+
13
+ stages.each do |name|
14
+ desc "Set the target stage to `#{name}'."
15
+ task(name) do
16
+ set :stage, name.to_sym
17
+ load "#{location}/#{stage}.rb"
18
+ end
19
+ end
20
+
21
+ on :load do
22
+ if stages.include?(ARGV.first)
23
+ # Execute the specified stage so that recipes required in stage can contribute to task list
24
+ find_and_execute_task(ARGV.first) if ARGV.any?{ |option| option =~ /-T|--tasks|-e|--explain/ }
25
+ else
26
+ # Execute the default stage so that recipes required in stage can contribute tasks
27
+ find_and_execute_task(default_stage) if exists?(:default_stage)
28
+ end
29
+ end
30
+
31
+ namespace :multistage do
32
+ desc "[internal] Ensure that a stage has been selected."
33
+ task :ensure do
34
+ if !exists?(:stage)
35
+ if exists?(:default_stage)
36
+ logger.important "Defaulting to `#{default_stage}'"
37
+ find_and_execute_task(default_stage)
38
+ else
39
+ abort "No stage specified. Please specify one of: #{stages.join(', ')} (e.g. `cap #{stages.first} #{ARGV.last}')"
40
+ end
41
+ end
42
+ end
43
+
44
+ desc "Stub out the staging config files."
45
+ task :prepare do
46
+ FileUtils.mkdir_p(location)
47
+ stages.each do |name|
48
+ file = File.join(location, name + ".rb")
49
+ unless File.exists?(file)
50
+ File.open(file, "w") do |f|
51
+ f.puts "# #{name.upcase}-specific deployment configuration"
52
+ f.puts "# please put general deployment config in config/deploy.rb"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ on :start, "multistage:ensure", :except => stages + ['multistage:prepare']
@@ -0,0 +1,97 @@
1
+ # Copyright (c) 2009-2011 by Ewout Vonk. All rights reserved.
2
+
3
+ # prevent loading when called by Bundler, only load when called by capistrano
4
+ if caller.any? { |callstack_line| callstack_line =~ /^Capfile:/ }
5
+ unless Capistrano::Configuration.respond_to?(:instance)
6
+ abort "capistrano-catch-output requires Capistrano 2"
7
+ end
8
+
9
+ require 'stringio'
10
+
11
+ module Capistrano
12
+ module OutputCatcher
13
+ class TeeIO
14
+
15
+ attr_accessor :sniffed_io_stream, :listening_io_stream
16
+
17
+ def initialize(sniffed_io_stream, listening_io_stream)
18
+ self.sniffed_io_stream = sniffed_io_stream
19
+ self.listening_io_stream = listening_io_stream
20
+ end
21
+
22
+ def distribute(method_name, *args, &block)
23
+ [ listening_io_stream, sniffed_io_stream ].each do |io_stream|
24
+ io_stream.send(method_name, *args, &block)
25
+ end
26
+ end
27
+
28
+ def method_missing(method_name, *args, &block)
29
+ distribute(method_name, *args, &block)
30
+ end
31
+
32
+ end
33
+
34
+ class OutputChannels
35
+
36
+ attr_accessor :out, :err
37
+
38
+ def initialize(out, err)
39
+ self.out = out
40
+ self.err = err
41
+ end
42
+
43
+ end
44
+
45
+ module Base
46
+
47
+ def capture_output(out = StringIO.new, err = nil)
48
+ create_capture_channels(out, err)
49
+ reroute_original_channels
50
+ override_output_channels(out, err)
51
+ end
52
+
53
+ def tee_output(out = StringIO.new, err = nil)
54
+ create_capture_channels(out, err)
55
+ reroute_original_channels
56
+ override_output_channels(TeeIO.new($std.out, out), TeeIO.new($std.err, err))
57
+ end
58
+
59
+ def end_capture
60
+ out_output = $capstd.out.string
61
+ err_output = $capstd.err.string
62
+ $capoutput = [ out_output, err_output ]
63
+ end
64
+
65
+ private
66
+
67
+ def override_output_channels(out, err)
68
+ logger.instance_variable_set(:@device, (logger.device == $std.err) ? err : out)
69
+ $stdout = out
70
+ $stderr = err
71
+ end
72
+
73
+ def create_capture_channels(out = StringIO.new, err = nil)
74
+ err ||= out
75
+ $capstd = OutputChannels.new(out, err)
76
+ end
77
+
78
+ def reroute_original_channels
79
+ $std = OutputChannels.new($stdout, $stderr)
80
+ end
81
+
82
+ end
83
+ end
84
+ end
85
+
86
+ Capistrano.plugin :output_catcher, Capistrano::OutputCatcher::Base
87
+
88
+ Capistrano::Configuration.instance(:must_exist).load do
89
+ trap("EXIT") do
90
+ output_catcher.end_capture
91
+ if defined?(capistrano_output_handler) == "method"
92
+ capistrano_output_handler
93
+ end
94
+ end
95
+ end
96
+
97
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright (c) 2009-2011 by Ewout Vonk. All rights reserved.
2
+
3
+ # prevent loading when called by Bundler, only load when called by capistrano
4
+ if caller.any? { |callstack_line| callstack_line =~ /^Capfile:/ }
5
+ unless Capistrano::Configuration.respond_to?(:instance)
6
+ abort "capistrano-minimal-output requires Capistrano 2"
7
+ end
8
+
9
+ require "capistrano-catch-output"
10
+ require "capistrano-mailer"
11
+
12
+ Capistrano::Configuration.instance(:must_exist).load do
13
+
14
+ output_catcher.capture_output
15
+
16
+ task :capistrano_output_handler do
17
+ email_body = $capistrano_out.string
18
+ email_subject = "capistrano output"
19
+ mailer.send(fetch(:mail_sender), fetch(:mail_recipients), email_subject, email_body)
20
+ end
21
+
22
+ namespace :capistrano_catch_output do
23
+
24
+ namespace :handlers do
25
+
26
+ namespace :on do
27
+ task :bundle_install do
28
+ puts "-----> Gemfile detected, running Bundler version X.Y.Z"
29
+ end
30
+ end
31
+
32
+ namespace :before do
33
+ task :bundle_install do
34
+ output_catcher.tee_output
35
+ end
36
+ end
37
+
38
+ namespace :after do
39
+ task :bundle_install do
40
+ output_catcher.capture_output
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+ before 'bundle:install', 'capistrano_catch_output:handlers:before:bundle_install'
49
+ after 'bundle:install', 'capistrano_catch_output:handlers:after:bundle_install'
50
+ on 'bundle:install', 'capistrano_catch_output:handlers:on:bundle_install'
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,44 @@
1
+ # ---------------------------------------------------------------------------
2
+ # This implements a specialization of the standard Capistrano RemoteCache
3
+ # deployment strategy. The most significant difference between this strategy
4
+ # and the RemoteCache is the way the cache is copied to the final release
5
+ # directory: it uses the bundled "copy.rb" script to use hard links to the
6
+ # files instead of actually copying, so the copy stage is much, much faster.
7
+ # ---------------------------------------------------------------------------
8
+ # This file is distributed under the terms of the MIT license by 37signals,
9
+ # LLC, and is copyright (c) 2008 by the same. See the MIT-LICENSE file distributed
10
+ # with this file for the complete text of the license.
11
+ # ---------------------------------------------------------------------------
12
+ require 'capistrano/recipes/deploy/strategy/remote_cache'
13
+
14
+ class Capistrano::Deploy::Strategy::FastRemoteCache < Capistrano::Deploy::Strategy::RemoteCache
15
+ def check!
16
+ super.check do |d|
17
+ d.remote.command(configuration.fetch(:ruby, "ruby"))
18
+ d.remote.directory(bin_path)
19
+ d.remote.file(File.join(bin_path, "copy.rb"))
20
+ end
21
+ end
22
+
23
+ def setup!
24
+ run "mkdir -p #{bin_path}"
25
+ upload(File.join(File.dirname(__FILE__), "utilities", "copy.rb"), File.join(bin_path, "copy.rb"))
26
+ end
27
+
28
+ def prepare!
29
+ update_repository_cache
30
+ end
31
+
32
+ private
33
+
34
+ def bin_path
35
+ @bin_path ||= File.join(configuration[:shared_path], "bin")
36
+ end
37
+
38
+ def copy_repository_cache
39
+ logger.trace "copying the cached version to #{configuration[:release_path]}"
40
+ ruby = configuration.fetch(:ruby, "ruby")
41
+ excludes = Array(configuration[:copy_exclude]).join(" ")
42
+ run "#{ruby} #{File.join(bin_path, 'copy.rb')} #{repository_cache} #{configuration[:release_path]} #{excludes} && #{mark}"
43
+ end
44
+ end