factorylabs-fdlcap 0.1.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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Factory Design Labs
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
File without changes
data/README.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ = fdlcap
2
+
3
+ Description goes here.
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2009 Gabe Varela. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "fdlcap"
8
+ gem.summary = %Q{a set of capistrano recipies we use regularly at Factory Design Labs}
9
+ gem.email = "interactive@factorylabs.com"
10
+ gem.homepage = "http://github.com/factorylabs/fdlcap"
11
+ gem.authors = ["Factory Design Labs"]
12
+ gem.add_dependency('engineyard-eycap', '>= 0.4.7')
13
+ gem.add_dependency('zilkey-auto_tagger', '>= 0.0.9')
14
+ gem.add_dependency('capistrano', '>= 2.5.5')
15
+ gem.add_dependency('capistrano-ext', '>= 1.2.1')
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/*_test.rb'
27
+ test.verbose = true
28
+ end
29
+
30
+ begin
31
+ require 'rcov/rcovtask'
32
+ Rcov::RcovTask.new do |test|
33
+ test.libs << 'test'
34
+ test.pattern = 'test/**/*_test.rb'
35
+ test.verbose = true
36
+ end
37
+ rescue LoadError
38
+ task :rcov do
39
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
40
+ end
41
+ end
42
+
43
+ begin
44
+ require 'cucumber/rake/task'
45
+ Cucumber::Rake::Task.new(:features)
46
+ rescue LoadError
47
+ task :features do
48
+ abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
49
+ end
50
+ end
51
+
52
+ task :default => :test
53
+
54
+ require 'rake/rdoctask'
55
+ Rake::RDocTask.new do |rdoc|
56
+ if File.exist?('VERSION.yml')
57
+ config = YAML.load(File.read('VERSION.yml'))
58
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
59
+ else
60
+ version = ""
61
+ end
62
+
63
+ rdoc.rdoc_dir = 'rdoc'
64
+ rdoc.title = "fdlcap #{version}"
65
+ rdoc.rdoc_files.include('README*')
66
+ rdoc.rdoc_files.include('lib/**/*.rb')
67
+ end
68
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/fdlcap ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ path = ARGV[0]
4
+ File.mkdir_p File.join(path, 'deploy')
data/fdlcap.gemspec ADDED
@@ -0,0 +1,85 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{fdlcap}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Factory Design Labs"]
9
+ s.date = %q{2009-06-25}
10
+ s.default_executable = %q{fdlcap}
11
+ s.email = %q{interactive@factorylabs.com}
12
+ s.executables = ["fdlcap"]
13
+ s.extra_rdoc_files = [
14
+ "LICENSE",
15
+ "README",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "LICENSE",
20
+ "README",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "bin/fdlcap",
25
+ "fdlcap.gemspec",
26
+ "features/fdlcap.feature",
27
+ "features/step_definitions/fdlcap_steps.rb",
28
+ "features/support/env.rb",
29
+ "lib/fdlcap.rb",
30
+ "lib/fdlcap/autotagger.rb",
31
+ "lib/fdlcap/craken.rb",
32
+ "lib/fdlcap/database.rb",
33
+ "lib/fdlcap/delayed_job.rb",
34
+ "lib/fdlcap/deploy.rb",
35
+ "lib/fdlcap/geminstaller.rb",
36
+ "lib/fdlcap/newrelic.rb",
37
+ "lib/fdlcap/nginx.rb",
38
+ "lib/fdlcap/performance.rb",
39
+ "lib/fdlcap/rake.rb",
40
+ "lib/fdlcap/recipes.rb",
41
+ "lib/fdlcap/rsync.rb",
42
+ "lib/fdlcap/sass.rb",
43
+ "lib/fdlcap/slice.rb",
44
+ "lib/fdlcap/ssh.rb",
45
+ "lib/fdlcap/symlinks.rb",
46
+ "lib/fdlcap/templates/nginx.auth.conf.erb",
47
+ "lib/fdlcap/templates/nginx.conf.erb",
48
+ "lib/fdlcap/templates/nginx.vhost.conf.erb",
49
+ "lib/fdlcap/thin.rb",
50
+ "lib/fdlcap/thinking_sphinx.rb",
51
+ "test/fdlcap_test.rb",
52
+ "test/test_helper.rb"
53
+ ]
54
+ s.homepage = %q{http://github.com/factorylabs/fdlcap}
55
+ s.rdoc_options = ["--charset=UTF-8"]
56
+ s.require_paths = ["lib"]
57
+ s.rubygems_version = %q{1.3.4}
58
+ s.summary = %q{a set of capistrano recipies we use regularly at Factory Design Labs}
59
+ s.test_files = [
60
+ "test/fdlcap_test.rb",
61
+ "test/test_helper.rb"
62
+ ]
63
+
64
+ if s.respond_to? :specification_version then
65
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
66
+ s.specification_version = 3
67
+
68
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
69
+ s.add_runtime_dependency(%q<engineyard-eycap>, [">= 0.4.7"])
70
+ s.add_runtime_dependency(%q<zilkey-auto_tagger>, [">= 0.0.9"])
71
+ s.add_runtime_dependency(%q<capistrano>, [">= 2.5.5"])
72
+ s.add_runtime_dependency(%q<capistrano-ext>, [">= 1.2.1"])
73
+ else
74
+ s.add_dependency(%q<engineyard-eycap>, [">= 0.4.7"])
75
+ s.add_dependency(%q<zilkey-auto_tagger>, [">= 0.0.9"])
76
+ s.add_dependency(%q<capistrano>, [">= 2.5.5"])
77
+ s.add_dependency(%q<capistrano-ext>, [">= 1.2.1"])
78
+ end
79
+ else
80
+ s.add_dependency(%q<engineyard-eycap>, [">= 0.4.7"])
81
+ s.add_dependency(%q<zilkey-auto_tagger>, [">= 0.0.9"])
82
+ s.add_dependency(%q<capistrano>, [">= 2.5.5"])
83
+ s.add_dependency(%q<capistrano-ext>, [">= 1.2.1"])
84
+ end
85
+ end
@@ -0,0 +1,9 @@
1
+ Feature: something something
2
+ In order to something something
3
+ A user something something
4
+ something something something
5
+
6
+ Scenario: something something
7
+ Given inspiration
8
+ When I create a sweet new gem
9
+ Then everyone should see how awesome I am
File without changes
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'fdlcap'
3
+
4
+ require 'test/unit/assertions'
5
+
6
+ World(Test::Unit::Assertions)
data/lib/fdlcap.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Fdlcap
2
+
3
+ end
@@ -0,0 +1,9 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ # Run autotagger to get the right release
3
+ if exists?(:use_release_tagger)
4
+ before "deploy:update_code", "release_tagger:set_branch"
5
+ before "deploy:cleanup", "release_tagger:create_tag"
6
+ before "deploy:cleanup", "release_tagger:write_tag_to_shared"
7
+ before "deploy:cleanup", "release_tagger:print_latest_tags"
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ # Run craken to get cron tasks installed
3
+ if exists?(:use_craken)
4
+ after "deploy:update", "craken:install"
5
+ end
6
+ end
@@ -0,0 +1,67 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :database do
3
+ desc "Push db remotely"
4
+ task :push_db_remotely, :roles => :db do
5
+
6
+ default_character_set = Object.const_defined?(:DEFAULT_CHARACTER_SET) ? Object::DEFAULT_CHARACTER_SET : "utf8"
7
+
8
+ local_env = ENV['LOCAL_ENV'] || "development"
9
+
10
+ all_db_info = YAML.load(File.read("config/database.yml"))
11
+ local_db_info = all_db_info[local_env]
12
+ remote_db_info = all_db_info[rails_env.to_s]
13
+ raise "Missing database.yml entry for #{local_env}" unless local_db_info
14
+ raise "Missing database.yml entry for #{rails_env.to_s}" unless remote_db_info
15
+
16
+
17
+ puts %{
18
+
19
+ ! WARNING !: The remote database '#{remote_db_info["database"]}'
20
+ will be replaced with the contents of the local database '#{local_db_info["database"]}'.
21
+ A dump of the remote db will be placed in your remote home directory just prior
22
+ to it being replaced.
23
+
24
+ 1) current REMOTE_DB ===> backed up to dump file, in ~/
25
+ 2) LOCAL_DB ===> REMOTE_DB ...old REMOTE_DB contents are overwritten!!!
26
+
27
+ Even so, this is a very significant and potentially destructive operation. Please step
28
+ back and contemplate what you're about to do.
29
+
30
+ If you're really sure you want to continue, type "REPLACE #{remote_db_info["database"].upcase}":
31
+ }
32
+
33
+ if ($stdin.gets.strip != "REPLACE #{remote_db_info["database"].upcase}")
34
+ puts "No action taken, exiting"
35
+ exit(1)
36
+ else
37
+ puts "You confirmed that you want to continue, here we go"
38
+ end
39
+
40
+ dump_file_name = "#{local_db_info["database"]}.sql"
41
+ local_dump_file_gz_path = "/tmp/#{dump_file_name}.gz"
42
+
43
+ execute "time mysqldump -e -q --single-transaction --default_character_set=#{default_character_set} \
44
+ -u #{local_db_info["username"]} --password=#{local_db_info["password"]} \
45
+ --database #{local_db_info["database"]} | gzip > #{local_dump_file_gz_path}"
46
+
47
+ upload "#{local_dump_file_gz_path}", "#{dump_file_name}.gz", :via => :scp
48
+
49
+ execute "echo ^G^G^G^G^G"
50
+
51
+ run "gzip -df ~/#{dump_file_name}.gz"
52
+ run "perl -pi -e 's|#{local_db_info["database"]}|#{remote_db_info["database"]}|g' ~/#{dump_file_name}"
53
+
54
+ run "time mysqldump -e -q --single-transaction --default_character_set=#{default_character_set} \
55
+ -u #{remote_db_info["username"]} --password=#{remote_db_info["password"]} \
56
+ --database #{remote_db_info["database"]} | gzip > ~/#{remote_db_info["database"]}_#{Time.now.strftime("%Y-%m-%d_%H-%M-%S")}.sql.gz"
57
+
58
+ remote_host = remote_db_info["host"] || "localhost"
59
+
60
+ run "mysqladmin -u #{remote_db_info["username"]} --password=#{remote_db_info["password"]} -h #{remote_host} drop #{remote_db_info["database"]} -f"
61
+ run "mysqladmin -u #{remote_db_info["username"]} --password=#{remote_db_info["password"]} -h #{remote_host} create #{remote_db_info["database"]} --default_character_set=#{default_character_set}"
62
+ run "time mysql -u #{remote_db_info["username"]} --password=#{remote_db_info["password"]} -h #{remote_host} --database #{remote_db_info["database"]} --default_character_set=#{default_character_set} < ~/#{dump_file_name}"
63
+ run "rm ~/#{dump_file_name}"
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,16 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :delayed_job do
3
+ desc "Start delayed_job"
4
+ task :start, :only => {:delayed_job => true} do
5
+ sudo "/usr/bin/monit start all -g dj_#{application}"
6
+ end
7
+ desc "Stop delayed_job"
8
+ task :stop, :only => {:delayed_job => true} do
9
+ sudo "/usr/bin/monit stop all -g dj_#{application}"
10
+ end
11
+ desc "Restart delayed_job"
12
+ task :restart, :only => {:delayed_job => true} do
13
+ sudo "/usr/bin/monit restart all -g dj_#{application}"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :web do
4
+ task :disable, :roles => :web, :except => { :no_release => true } do
5
+ on_rollback { run "rm #{shared_path}/system/maintenance.html" }
6
+ run "cp #{current_path}/public/maintenance.html #{shared_path}/system/maintenance.html"
7
+ end
8
+ end
9
+
10
+ namespace :deploy do
11
+ desc "Pull files from a remote server"
12
+ task :download_file, :roles => :app, :except => { :no_release => true } do
13
+ ENV['FILES'].split(',').each do |file|
14
+ get "#{current_path}/#{file}", File.basename(file)
15
+ end
16
+ end
17
+ end
18
+
19
+ # Clean up old releases
20
+ if exists?(:perform_cleanup)
21
+ after "deploy", "deploy:cleanup"
22
+ after "deploy:migrations" , "deploy:cleanup"
23
+ after "deploy:long" , "deploy:cleanup"
24
+ end
25
+
26
+ end
@@ -0,0 +1,26 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :geminstaller do
3
+ desc "Run geminstaller"
4
+ task :run, :only => { :geminstaller => true } do
5
+ sudo "/usr/bin/geminstaller -c #{release_path}/config/geminstaller.yml --geminstaller-output=all --rubygems-output=all"
6
+ end
7
+
8
+ desc "Install geminstaller"
9
+ task :install, :only => { :geminstaller => true } do
10
+ sudo "gem install geminstaller"
11
+ sudo "gem source -a http://gems.github.com"
12
+ end
13
+ end
14
+
15
+ #
16
+ # Configure Callbacks
17
+ #
18
+ # Run geminstaller to make sure gems are installed.
19
+ if exists?(:use_geminstaller)
20
+ after "deploy:setup", "geminstaller:install"
21
+ after "geminstaller:install", "geminstaller:run"
22
+ after "deploy:symlink", "geminstaller:run"
23
+ after "geminstaller:run", "deploy:migrate"
24
+ end
25
+
26
+ end
@@ -0,0 +1,6 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ # Notify newrelic of the deploy
3
+ if exists?(:use_newrelic)
4
+ before "deploy:cleanup", "newrelic:notice_deployment"
5
+ end
6
+ end
@@ -0,0 +1,125 @@
1
+
2
+ #global vars
3
+ set(:can_configure_nginx, true)
4
+ set(:nginx_user, 'nginx')
5
+ set(:nginx_processes, 4)
6
+ set(:nginx_gzip_on, true)
7
+ set(:nginx_gzip_xml_on, false)
8
+
9
+ # app specific vars
10
+ set(:nginx_server_names, "_")
11
+ set(:nginx_far_future, false)
12
+ set(:nginx_default_app, true)
13
+
14
+ #http auth vars
15
+ set(:nginx_auth_ip_masks, ['192.168.0.0/254'])
16
+ set(:nginx_http_auth_app, false)
17
+ set(:nginx_auth_locations, [])
18
+ set(:nginx_http_auth_users, [])
19
+
20
+ namespace :nginx do
21
+
22
+ %w( start stop restart reload ).each do |cmd|
23
+ desc "#{cmd} your nginx servers"
24
+ task "#{cmd}".to_sym, :roles => :web do
25
+ default_run_options[:pty] = true
26
+ sudo "/etc/init.d/nginx #{cmd}"
27
+ end
28
+ end
29
+
30
+ desc "Setup Nginx vhost config"
31
+ task :vhost, :roles => :web do
32
+ result = render_erb_template(File.dirname(__FILE__) + "/templates/nginx.vhost.conf.erb")
33
+ put result, "/tmp/nginx.vhost.conf"
34
+ sudo "mkdir -p /etc/nginx/vhosts"
35
+ sudo "cp /tmp/nginx.vhost.conf /etc/nginx/vhosts/#{application}.conf"
36
+ inform "You must edit nginx.conf to include the vhost config file."
37
+ end
38
+
39
+ desc "Setup Nginx vhost auth config"
40
+ task :vhost_auth, :roles => :web do
41
+ result = render_erb_template(File.dirname(__FILE__) + "/templates/nginx.auth.conf.erb")
42
+ put result, "/tmp/nginx.auth.conf"
43
+ sudo "mkdir -p /etc/nginx/vhosts"
44
+ sudo "cp /tmp/nginx.vhost.conf /etc/nginx/vhosts/#{application}.auth.conf"
45
+ end
46
+
47
+ desc "Setup htpasswd file for nginx auth"
48
+ task :create_htpasswd, :roles => :web do
49
+ sudo "mkdir -p /etc/nginx/conf"
50
+ for user in nginx_http_auth_users
51
+ run "cd /etc/nginx/conf && htpasswd -b htpasswd #{user['name']} #{user['password']}"
52
+ # run <<-CMD
53
+ # cd /etc/nginx/conf;
54
+ # if [ ! -e /etc/nginx/conf/htpasswd ] ; then
55
+ # htpasswd -b -c htpasswd #{user['name']} #{user['password']};
56
+ # else
57
+ # htpasswd -b htpasswd #{user['name']} #{user['password']};
58
+ # fi
59
+ # CMD
60
+ end
61
+ end
62
+
63
+ desc "Setup Nginx.config"
64
+ task :conf, :roles => :web do
65
+ if can_configure_nginx
66
+
67
+ result = render_erb_template(File.dirname(__FILE__) + "/templates/nginx.conf.erb")
68
+ put result, "/tmp/nginx.conf"
69
+ sudo "cp /tmp/nginx.conf /etc/nginx/nginx.conf"
70
+
71
+ else
72
+ inform "Nginx configuration tasks have been disabled. Most likely you are deploying to engineyard which has it's own nginx conf setup."
73
+ end
74
+ end
75
+
76
+ desc "Setup Nginx vhost config and nginx.conf"
77
+ task :configure, :roles => :web do
78
+ if can_configure_nginx
79
+
80
+ conf
81
+ vhost
82
+ vhost_auth if nginx_auth_locations.length > 0 || nginx_http_auth_app
83
+ create_htpasswd if nginx_http_auth_users.length > 0
84
+
85
+ else
86
+ inform "Nginx configuration tasks have been disabled. Most likely you are deploying to engineyard which has it's own nginx conf setup."
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ class Capistrano::Configuration
93
+
94
+ ##
95
+ # Print an informative message with asterisks.
96
+
97
+ def inform(message)
98
+ puts "#{'*' * (message.length + 4)}"
99
+ puts "* #{message} *"
100
+ puts "#{'*' * (message.length + 4)}"
101
+ end
102
+
103
+ ##
104
+ # Read a file and evaluate it as an ERB template.
105
+ # Path is relative to this file's directory.
106
+
107
+ def render_erb_template(filename)
108
+ template = File.read(filename)
109
+ result = ERB.new(template).result(binding)
110
+ end
111
+
112
+ ##
113
+ # Run a command and return the result as a string.
114
+ #
115
+ # TODO May not work properly on multiple servers.
116
+
117
+ def run_and_return(cmd)
118
+ output = []
119
+ run cmd do |ch, st, data|
120
+ output << data
121
+ end
122
+ return output.to_s
123
+ end
124
+
125
+ end
@@ -0,0 +1,38 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :autoperf do
3
+ desc "get nginx log for load test"
4
+ task :fetch_log, :roles => :app do
5
+ # Grab the last 1000 requests from production Nginx log, and extract the request path (ex: /index)
6
+ run "tail -n 1000 /var/log/nginx/#{application}.access.log | awk '{print $7}' > /tmp/requests.log"
7
+
8
+ # Replace newlines with null terminator (httperf format)
9
+ run 'tr "\n" "\0" < /tmp/requests.log > /tmp/requests_httperf.log'
10
+
11
+ download "/tmp/requests_httperf.log", "config/autoperf/requests_httperf.log", :via => :scp
12
+
13
+ run "rm /tmp/requests_httperf.log"
14
+ end
15
+
16
+ task :run_test, :roles => :app do
17
+ run "cd #{current_path} && script/autoperf -c config/autoperf/primary.conf" do |channel, stream, data|
18
+ puts data if stream == :out
19
+ if stream == :err
20
+ puts "[Error: #{channel[:host]}] #{data}"
21
+ break
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ namespace :autobench do
28
+
29
+ task :test_search, :roles => :app do
30
+ url = "/vehicles/search?search[zip]=06108&search[radius]=10+Miles&search[view_type]=block&search[per_page]=10&search[year_from]=From+Year&search[year_to]=To+Year&search[model]=Model&search[price]=Price&search[color]=Color&search[mileage]=Mileage&commit=Search"
31
+ run "/usr/local/bin/autobench --single_host --host1=audivehiclesearch.com --uri1=#{url} --file=/tmp/test_search.bench.txt --low_rate=1 --high_rate=20 --rate_step=2 --num_call=2 --num_conn=200"
32
+ download "/tmp/test_search.bench.txt", "autobench/test_search.bench.txt", :via => :scp
33
+ run "rm /tmp/test_search.bench.txt"
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,19 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ desc "Execute an arbitrary rake task on slices with a specified role (ROLES=x,y,z TASK=p)"
3
+ task :rake do
4
+ task = ENV['TASK']
5
+ run "cd #{current_path} && rake #{task} RAILS_ENV=#{rails_env}"
6
+ end
7
+
8
+ desc "Execute an arbitrary runner command on slices with a specified role (ROLES=x,y,z CMD=p)"
9
+ task :runner do
10
+ cmd = ENV['CMD']
11
+ run "cd #{current_path} && script/runner -e #{rails_env} '#{cmd}'"
12
+ end
13
+
14
+ desc "Execute an arbitrary UNIX command on slices with a specified role (ROLES=x,y,z CMD=p)"
15
+ task :command do
16
+ cmd = ENV['CMD']
17
+ run "cd #{current_path} && #{cmd}"
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ # Set up configuration defaults
2
+ Capistrano::Configuration.instance(:must_exist).load do
3
+ unless exists?(:stages)
4
+ set :stages, [ :staging, :production ]
5
+ end
6
+
7
+ unless exists?(:use_release_tagger) && exists?(:autotagger_stages)
8
+ set :autotagger_stages, [ :ci, :staging, :production ]
9
+ end
10
+
11
+ unless exists?(:default_stage)
12
+ set :default_stage, :staging
13
+ end
14
+ end
15
+
16
+ # Load fdlcap dependencies
17
+ require 'release_tagger'
18
+ require 'capistrano/ext/multistage'
19
+ require 'eycap/recipes'
20
+
21
+ # Load up custom recipes and callbacks
22
+ require 'fdlcap/recipes/autotagger'
23
+ require 'fdlcap/recipes/craken'
24
+ require 'fdlcap/recipes/database'
25
+ require 'fdlcap/recipes/delayed_job'
26
+ require 'fdlcap/recipes/deploy'
27
+ require 'fdlcap/recipes/geminstaller'
28
+ require 'fdlcap/recipes/newrelic'
29
+ require 'fdlcap/recipes/performance'
30
+ require 'fdlcap/recipes/rake'
31
+ require 'fdlcap/recipes/rsync'
32
+ require 'fdlcap/recipes/sass'
33
+ require 'fdlcap/recipes/ssh'
34
+ require 'fdlcap/recipes/slice'
35
+ require 'fdlcap/recipes/thinking_sphinx'
@@ -0,0 +1,40 @@
1
+ class Capistrano::Configuration
2
+ def execute(command, failure_message = "Command failed")
3
+ puts "Executing: #{command}"
4
+ system(command) || raise(failure_message)
5
+ end
6
+ end
7
+
8
+ Capistrano::Configuration.instance(:must_exist).load do
9
+ namespace :rsync do
10
+ desc <<-DESC
11
+ use rsync to sync assets locally or between servers
12
+ DESC
13
+ task :pull_shared , :roles => :app do
14
+ servers = find_servers :roles => :app, :except => { :no_release => true }
15
+ server = servers.first
16
+ if server
17
+ symlink_dirs.each do |share|
18
+ execute( "rsync -P -a -h -e 'ssh -p #{server.port || 22}' #{user}@#{server.host}:#{shared_path}/#{share}/* #{share}", "unable to run rsync files")
19
+ end
20
+ else
21
+ puts 'no server found'
22
+ end
23
+ end
24
+
25
+ desc <<-DESC
26
+ use rsync to sync assets locally or between servers
27
+ DESC
28
+ task :push_shared , :roles => :app do
29
+ servers = find_servers :roles => :app, :except => { :no_release => true }
30
+ server = servers.first
31
+ if server
32
+ symlink_dirs.each do |share|
33
+ execute( "rsync -P -a -h -e 'ssh -p #{server.port || 22}' #{share}/* #{user}@#{server.host}:#{shared_path}/#{share}/", "unable to run rsync files")
34
+ end
35
+ else
36
+ puts 'no server found'
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :sass do
3
+ desc 'Updates the stylesheets generated by Sass'
4
+ task :update, :roles => :app do
5
+ invoke_command "cd #{latest_release}; RAILS_ENV=#{rails_env} rake sass:update"
6
+ end
7
+ end
8
+
9
+ # Generate all the stylesheets manually (from their Sass templates) before each restart.
10
+ if exists?(:use_sass)
11
+ before 'deploy:restart', 'sass:update'
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :slice do
4
+
5
+ desc "Copy the maintenance page from the public directory to the shared directory"
6
+ task :copy_maintenance_page, :roles => :app do
7
+ upload "public/maintenance.html","#{shared_path}/system/maintenance.html.custom", :via => :scp
8
+ end
9
+
10
+ desc "Tail the Rails import log for this environment"
11
+ task :tail_import_logs, :roles => :utility do
12
+ run "tail -f #{shared_path}/log/import-#{rails_env}.log" do |channel, stream, data|
13
+ puts # for an extra line break before the host name
14
+ puts "#{channel[:server]} -> #{data}"
15
+ break if stream == :err
16
+ end
17
+ end
18
+
19
+ desc "Tail the Rails log for this environment"
20
+ task :tail_logs, :roles => :utility do
21
+ run "tail -f #{shared_path}/log/#{rails_env}.log" do |channel, stream, data|
22
+ puts # for an extra line break before the host name
23
+ puts "#{channel[:server]} -> #{data}"
24
+ break if stream == :err
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ # Deploy the custom maintenance page
31
+ if exists?(:use_custom_maintenance_page)
32
+ before "deploy:web:disable", "slice:copy_maintenance_page"
33
+ end
34
+
35
+ end
data/lib/fdlcap/ssh.rb ADDED
@@ -0,0 +1,30 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ task :ssh do
3
+ role = (ENV['ROLE'] || :app).to_sym
4
+ servers = find_servers :roles => role
5
+ server = servers.first
6
+ if server
7
+ `echo '#{password}' | /usr/bin/pbcopy`
8
+ exec "/usr/bin/ssh #{user}@#{server.host} -p #{server.port || 22} "
9
+ end
10
+ end
11
+
12
+ #namespace :ssh do
13
+ task :tunnel do
14
+ remote_port = ENV['REMOTE_PORT'] || 80
15
+ local_port = ENV['LOCAL_PORT'] || 2000
16
+ role = (ENV['ROLE'] || :app).to_sym
17
+
18
+ servers = find_servers :roles => role
19
+ server = servers.first
20
+ if server
21
+ puts "Opening a tunnel from port #{local_port} locally to port #{remote_port} on #{server.host}"
22
+ Net::SSH.start(server.host, user, :password => password, :port => server.port) do |ssh|
23
+ ssh.forward.local(local_port, "127.0.0.1", remote_port)
24
+ ssh.loop { true }
25
+ end
26
+ end
27
+ end
28
+ #end
29
+
30
+ end
@@ -0,0 +1,38 @@
1
+ after "deploy:update_code", "symlinks:create"
2
+
3
+ set(:symlink_dirs, [])
4
+ set(:symlink_absolute_dirs, [])
5
+
6
+ namespace :symlinks do
7
+
8
+ desc <<-DESC
9
+ fix symlinks to shared directory
10
+ DESC
11
+ task :fix, :roles => [:app, :web] do
12
+ # for folders stored under public
13
+ symlink_dirs.each do |share|
14
+ run "rm -rf #{current_path}/#{share}"
15
+ run "mkdir -p #{shared_path}/#{share}"
16
+ run "ln -nfs #{shared_path}/#{share} #{current_path}/#{share}"
17
+ end
18
+ end
19
+
20
+ desc <<-DESC
21
+ create symlinks to shared directory
22
+ DESC
23
+ task :create, :roles => [:app, :web] do
24
+ # for folders stored under public
25
+ symlink_dirs.each do |share|
26
+ run "rm -rf #{release_path}/#{share}"
27
+ run "mkdir -p #{shared_path}/#{share}"
28
+ run "ln -nfs #{shared_path}/#{share} #{release_path}/#{share}"
29
+ end
30
+
31
+ symlink_absolute_dirs.each do |share|
32
+ run "rm -rf #{share[:symlink]}"
33
+ run "mkdir -p #{share[:source]}"
34
+ run "ln -nfs #{share[:source]} #{share[:symlink]}"
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,9 @@
1
+ satisfy_any on;
2
+
3
+ <% for allow in nginx_auth_ip_masks -%>
4
+ <%= "allow #{allow};" %>
5
+ <% end -%>
6
+ deny all;
7
+
8
+ auth_basic "Restricted";
9
+ auth_basic_user_file /etc/nginx/conf/htpasswd;
@@ -0,0 +1,57 @@
1
+ # taken mostly from "The Rails Way" page 663
2
+
3
+ # user and group to run as
4
+ user <%= nginx_user %>;
5
+ # number of nginx workers
6
+ worker_processes <%= nginx_processes %>;
7
+ # pid of nginx master process
8
+ pid /var/run/nginx.pid;
9
+
10
+ error_log /var/log/nginx/default.error.log debug;
11
+ #error_log /var/log/nginx/error.log notice;
12
+ #error_log /var/log/nginx/error.log info;
13
+
14
+ # number of worker connections. 1024 is a good default
15
+ events {
16
+ worker_connections 1024;
17
+ use epoll; # linux only!
18
+ }
19
+
20
+
21
+ http {
22
+ # pull in mime-types. You can break out your config
23
+ # into as many include's as you want.
24
+ include /etc/nginx/mime.types;
25
+ # set a default type for the rare situation that nothing matches.
26
+ default_type application/octet-stream;
27
+ # configure log format
28
+ log_format main '$remote_addr - $remote_user [$time_local] $request '
29
+ '"$status" $body_bytes_sent "$http_referer" '
30
+ '"$http_user_agent" "$http_x_forwarded_for"';
31
+
32
+ # no sendfile on OS X
33
+ sendfile on;
34
+ tcp_nopush on;
35
+ tcp_nodelay on;
36
+
37
+ #keepalive_timeout 0;
38
+ keepalive_timeout 65;
39
+
40
+ <% if nginx_gzip_on %>
41
+ gzip on;
42
+ gzip_http_version 1.0;
43
+ gzip_comp_level 2;
44
+ gzip_proxied any;
45
+
46
+ <% if nginx_gzip_xml_on %>
47
+ # IE 6 doesn't pass compressed xml to flash. So if no flash xml consumption on site can add
48
+ # text/xml application/xml application/xml+rss
49
+ <% end %>
50
+ gzip_types text/plain text/html text/css application/x-javascript text/javascript;
51
+ <% end %>
52
+
53
+ access_log /var/log/nginx/nginx.default.access.log main;
54
+ error_log /var/log/nginx/nginx.default.error.log info;
55
+
56
+ include /etc/nginx/vhosts/*.conf;
57
+ }
@@ -0,0 +1,85 @@
1
+ # location of mongrel servers to proxy too
2
+ upstream mongrel_<%= application.gsub('.', '_') %> {
3
+ <% mongrel_port.upto(mongrel_port + mongrel_servers) do |port| %>
4
+ server 127.0.0.1:<%= port %>;
5
+ <% end %>
6
+ }
7
+
8
+ server {
9
+ # port to listen on. Can also be set to an IP:PORT
10
+ listen 80 <%= "default" if nginx_default_app %>;
11
+ # set max size for file uploads to 50mb
12
+ client_max_body_size 50M;
13
+ # sets the domain[s] that this vhost server requests for
14
+ # if two apps are on this box remove the ip and setup your hosts file
15
+ server_name <%= nginx_server_names %>;
16
+ # doc root
17
+ root <%= current_path %>/public;
18
+ # vhost specific logs
19
+ access_log <%= shared_path %>/log/<%= application %>.access.log main;
20
+ error_log <%= shared_path %>/log/<%= application %>.error.log notice;
21
+
22
+ # this rewrites all the requests to the maintenance.thml page if it exists in the doc root.
23
+ # this is for capistrano's disable web task
24
+ if (-f $document_root/system/maintenance.html) {
25
+ rewrite ^(.*)$ /system/maintenance.html last;
26
+ break;
27
+ }
28
+ # block access to paths containing .svn
29
+ location ~* ^.*\.svn.*$ {
30
+ internal;
31
+ }
32
+
33
+ location / {
34
+
35
+ <%= "include /etc/nginx/vhosts/#{application}.auth.conf" if nginx_http_auth_app %>
36
+
37
+ index index.html index.htm;
38
+ # forward the user's IP address to Rails
39
+ proxy_set_header X-Real-IP $remote_addr;
40
+ # needed for HTTPS must add an additional server block to configure it.
41
+ # see "The Rails Way" page 665 for more info
42
+ proxy_set_header X-FORWARD_PROTO https;
43
+ # Forward information about the client and host
44
+ # Otherwise our Rails app wouldn't have access to it
45
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
46
+ proxy_set_header Host $http_host;
47
+ proxy_redirect false;
48
+ proxy_max_temp_file_size 0;
49
+
50
+ # use this as a reference for a full production deployment
51
+ # do not use on a dev box. this adds far futures expires.
52
+ <%= "#" if nginx_far_future %> location ~ ^/(images|javascripts|stylesheets)/ {
53
+ <%= "#" if nginx_far_future %> expires 10y;
54
+ <%= "#" if nginx_far_future %> }
55
+
56
+ # if file exists break execution and serve up file for example files in images, javascripts, and stylesheets
57
+ if (-f $request_filename) {
58
+ break;
59
+ }
60
+ # Rails page caching, if file path plus index.html exists break execution and serve up file
61
+ if (-f $request_filename/index.html) {
62
+ rewrite (.*) $1/index.html break;
63
+ }
64
+ # Rails page caching, if file.html exists break execution and serve up file
65
+ if (-f $request_filename.html) {
66
+ rewrite (.*) $1.html break;
67
+ }
68
+ # if file does not exist forward to mongrel
69
+ if (!-f $request_filename) {
70
+ proxy_pass http://mongrel_<%= application.gsub('.', '_') %>;
71
+ break;
72
+ }
73
+ }
74
+ <% for location in nginx_auth_locations %>
75
+ location <%= location %> {
76
+ <%= "include /etc/nginx/vhosts/#{application}.auth.conf" %>
77
+ }
78
+ <% end %>
79
+ # must be an error so point to error page.
80
+ error_page 500 502 503 504 /500.html;
81
+ location = /500.html {
82
+ root <%= current_path %>/public;
83
+ }
84
+
85
+ }
@@ -0,0 +1,112 @@
1
+ set :thin_servers, 2
2
+ set :thin_port, 8000
3
+ set :thin_address, "127.0.0.1"
4
+ set :thin_environment, "production"
5
+ set :thin_conf, nil
6
+ set :thin_user, nil
7
+ set :thin_group, nil
8
+ set :thin_prefix, nil
9
+ set :thin_pid_file, nil
10
+ set :thin_log_file, nil
11
+ set :thin_config_script, nil
12
+
13
+ namespace :thin do
14
+ desc <<-DESC
15
+ Install Thin script on the app server. This uses the :use_sudo variable to determine whether to use sudo or not. By default, :use_sudo is
16
+ set to true.
17
+ DESC
18
+ task :install , :roles => :app do
19
+ send(run_method, "gem install thin")
20
+ send(run_method, "thin install")
21
+ end
22
+
23
+ desc <<-DESC
24
+ Configure thin processes on the app server. This uses the :use_sudo
25
+ variable to determine whether to use sudo or not. By default, :use_sudo is
26
+ set to true.
27
+ DESC
28
+ task :configure, :roles => :app do
29
+ set_conf
30
+
31
+ argv = []
32
+ argv << "thin"
33
+ argv << "-s #{thin_servers.to_s}"
34
+ argv << "-p #{thin_port.to_s}"
35
+ argv << "-e #{thin_environment}"
36
+ argv << "-a #{thin_address}"
37
+ argv << "-c #{current_path}"
38
+ argv << "-C #{thin_conf}"
39
+ argv << "-P #{thin_pid_file}" if thin_pid_file
40
+ argv << "-l #{thin_log_file}" if thin_log_file
41
+ argv << "--user #{thin_user}" if thin_user
42
+ argv << "--group #{thin_group}" if thin_group
43
+ argv << "--prefix #{thin_prefix}" if thin_prefix
44
+ argv << "config"
45
+ cmd = argv.join " "
46
+ send(run_method, cmd)
47
+ end
48
+
49
+ task :setup, :roles => :app do
50
+ thin.install
51
+ thin.configure
52
+ end
53
+
54
+ desc <<-DESC
55
+ Start Thin processes on the app server. This uses the :use_sudo variable to determine whether to use sudo or not. By default, :use_sudo is
56
+ set to true.
57
+ DESC
58
+ task :start , :roles => :app do
59
+ set_conf
60
+ cmd = "thin start -C #{thin_conf}"
61
+ send(run_method, cmd)
62
+ end
63
+
64
+ desc <<-DESC
65
+ Restart the Thin processes on the app server by starting and stopping the cluster. This uses the :use_sudo
66
+ variable to determine whether to use sudo or not. By default, :use_sudo is set to true.
67
+ DESC
68
+ task :restart , :roles => :app do
69
+ set_conf
70
+ cmd = "thin restart -C #{thin_conf}"
71
+ send(run_method, cmd)
72
+ end
73
+
74
+ desc <<-DESC
75
+ Stop the Thin processes on the app server. This uses the :use_sudo
76
+ variable to determine whether to use sudo or not. By default, :use_sudo is
77
+ set to true.
78
+ DESC
79
+ task :stop , :roles => :app do
80
+ set_conf
81
+ cmd = "thin stop -C #{thin_conf}"
82
+ send(run_method, cmd)
83
+ end
84
+
85
+
86
+ def set_conf
87
+ set :thin_conf, "/etc/thin/#{application}.yml" unless thin_conf
88
+ end
89
+ end
90
+
91
+ namespace :deploy do
92
+ desc <<-DESC
93
+ Restart the Thin processes on the app server by calling thin:restart.
94
+ DESC
95
+ task :restart, :roles => :app do
96
+ thin.restart
97
+ end
98
+
99
+ desc <<-DESC
100
+ Start the Thin processes on the app server by calling thin:start.
101
+ DESC
102
+ task :start, :roles => :app do
103
+ thin.start
104
+ end
105
+
106
+ desc <<-DESC
107
+ Stop the Thin processes on the app server by calling thin:stop.
108
+ DESC
109
+ task :stop, :roles => :app do
110
+ thin.stop
111
+ end
112
+ end
@@ -0,0 +1,9 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ # Make sphinx happy
3
+ if exists?(:use_thinking_sphinx)
4
+ after "deploy:update_code", "deploy:symlink_configs"
5
+ after "deploy:symlink_configs", "thinking_sphinx:symlink"
6
+ after "thinking_sphinx:symlink", "sphinx:configure"
7
+ after "deploy:update", "sphinx:reindex"
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class FdlcapTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'fdlcap'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: factorylabs-fdlcap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Factory Design Labs
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-25 00:00:00 -07:00
13
+ default_executable: fdlcap
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: engineyard-eycap
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.4.7
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: zilkey-auto_tagger
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.9
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: capistrano
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.5.5
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: capistrano-ext
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.2.1
54
+ version:
55
+ description:
56
+ email: interactive@factorylabs.com
57
+ executables:
58
+ - fdlcap
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - LICENSE
63
+ - README
64
+ - README.rdoc
65
+ files:
66
+ - LICENSE
67
+ - README
68
+ - README.rdoc
69
+ - Rakefile
70
+ - VERSION
71
+ - bin/fdlcap
72
+ - fdlcap.gemspec
73
+ - features/fdlcap.feature
74
+ - features/step_definitions/fdlcap_steps.rb
75
+ - features/support/env.rb
76
+ - lib/fdlcap.rb
77
+ - lib/fdlcap/autotagger.rb
78
+ - lib/fdlcap/craken.rb
79
+ - lib/fdlcap/database.rb
80
+ - lib/fdlcap/delayed_job.rb
81
+ - lib/fdlcap/deploy.rb
82
+ - lib/fdlcap/geminstaller.rb
83
+ - lib/fdlcap/newrelic.rb
84
+ - lib/fdlcap/nginx.rb
85
+ - lib/fdlcap/performance.rb
86
+ - lib/fdlcap/rake.rb
87
+ - lib/fdlcap/recipes.rb
88
+ - lib/fdlcap/rsync.rb
89
+ - lib/fdlcap/sass.rb
90
+ - lib/fdlcap/slice.rb
91
+ - lib/fdlcap/ssh.rb
92
+ - lib/fdlcap/symlinks.rb
93
+ - lib/fdlcap/templates/nginx.auth.conf.erb
94
+ - lib/fdlcap/templates/nginx.conf.erb
95
+ - lib/fdlcap/templates/nginx.vhost.conf.erb
96
+ - lib/fdlcap/thin.rb
97
+ - lib/fdlcap/thinking_sphinx.rb
98
+ - test/fdlcap_test.rb
99
+ - test/test_helper.rb
100
+ has_rdoc: false
101
+ homepage: http://github.com/factorylabs/fdlcap
102
+ post_install_message:
103
+ rdoc_options:
104
+ - --charset=UTF-8
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: "0"
112
+ version:
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: "0"
118
+ version:
119
+ requirements: []
120
+
121
+ rubyforge_project:
122
+ rubygems_version: 1.2.0
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: a set of capistrano recipies we use regularly at Factory Design Labs
126
+ test_files:
127
+ - test/fdlcap_test.rb
128
+ - test/test_helper.rb