yad 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ class String
2
+ # Turns a lower_case_underscored_name into an UpperCaseCamelCaseName
3
+ def classify
4
+ self.gsub("_", " ").gsub(/\b('?[a-z])/) { $1.capitalize }.gsub(" ", "")
5
+ end
6
+ end
@@ -0,0 +1,46 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'rake'
6
+ require 'open4'
7
+ require 'yaml'
8
+
9
+ require "ext/rake/remote_task"
10
+ require "ext/rake"
11
+ require "ext/string"
12
+
13
+ require "yad/core"
14
+ Yad::Core.define_tasks
15
+
16
+ require "yad/web/apache"
17
+
18
+ require "yad/maintenance/shared_system"
19
+
20
+ require "yad/app/passenger"
21
+
22
+ require "yad/framework/rails"
23
+
24
+ require "yad/db/rails"
25
+
26
+ require "yad/scm/git"
27
+
28
+ module Yad
29
+ # :stopdoc:
30
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
31
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
32
+
33
+ VERSION = if File.exist?(File.join(PATH, 'VERSION.yml'))
34
+ config = YAML.load_file(File.join(PATH, 'VERSION.yml'))
35
+ "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
36
+ else
37
+ "0.0.0"
38
+ end
39
+ # :startdoc:
40
+
41
+ # Returns the version string for the library.
42
+ def self.version
43
+ VERSION
44
+ end
45
+
46
+ end
@@ -0,0 +1,28 @@
1
+ module Yad
2
+ module App
3
+ class Passenger
4
+ def self.build_start_command(release_directory)
5
+ "touch #{release_directory}/tmp/restart.txt"
6
+ end
7
+
8
+ def self.define_tasks
9
+ return if @tasks_already_defined
10
+ @tasks_already_defined = true
11
+ namespace :yad do
12
+ namespace :app do
13
+
14
+ desc "Starts the application server"
15
+ remote_task :start, :roles => :app do
16
+ cmd = Yad::App::Passenger.build_start_command(current_path)
17
+ run(cmd)
18
+ puts("Passenger app restarted on #{target_host}")
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+
25
+ end # class Passenger
26
+
27
+ end # module App
28
+ end # module Yad
@@ -0,0 +1,199 @@
1
+ module Yad
2
+ class Core
3
+ def self.build_setup_command(deployment_directory, options = {})
4
+ default_options = { :umask => '02',
5
+ :shared_subdirectories => [] }
6
+
7
+ options = default_options.merge(options)
8
+ dirs = [File.join(deployment_directory, "releases"),
9
+ File.join(deployment_directory, "scm"),
10
+ File.join(deployment_directory, "shared"),
11
+ File.join(deployment_directory, "shared", "config")
12
+ ]
13
+ options[:shared_subdirectories].each do |subdirectory|
14
+ dirs << File.join(deployment_directory, "shared", subdirectory) unless subdirectory == 'config'
15
+ end
16
+ "umask #{options[:umask]} && mkdir -p #{dirs.join(' ')}"
17
+ end
18
+
19
+ def self.build_update_source_code_command(checkout_command, export_command, new_release_directory)
20
+ [checkout_command,
21
+ export_command,
22
+ "chmod -R g+w #{new_release_directory}"
23
+ ].join(" && ")
24
+ end
25
+
26
+ def self.build_remove_directory_command(directory_to_remove)
27
+ "rm -rf #{directory_to_remove}"
28
+ end
29
+
30
+ def self.build_files_array(delimited_file_names)
31
+ return [] unless delimited_file_names
32
+ files = delimited_file_names.split(",").map { |f| f.strip }.flatten
33
+ files = files.reject { |f| File.directory?(f) || File.basename(f)[0] == ?. }
34
+ files
35
+ end
36
+
37
+ def self.build_update_symlink_command(current_release_symlink, new_release_directory)
38
+ "rm -f #{current_release_symlink} && ln -s #{new_release_directory} #{current_release_symlink}"
39
+ end
40
+
41
+ def self.build_revision_log_command(timestamp, inline_revision_identifier_command, new_release_directory, deployment_directory)
42
+ "echo #{timestamp} $USER #{inline_revision_identifier_command} #{File.basename(new_release_directory)} >> #{deployment_directory}/revisions.log"
43
+ end
44
+
45
+ def self.build_cleanup_command(max_release_count, releases_directory, all_releases)
46
+ if all_releases.length <= max_release_count
47
+ "echo keeping all releases"
48
+ else
49
+ releases_to_remove = (all_releases - all_releases.last(max_release_count)).map { |release| File.join(releases_directory, release) }.join(" ")
50
+ "rm -rf #{releases_to_remove}"
51
+ end
52
+ end
53
+
54
+ def self.build_rollback_command(current_release_symlink, previous_release_directory, latest_release_directory)
55
+ if previous_release_directory.nil? || previous_release_directory == latest_release_directory || latest_release_directory.nil?
56
+ "echo no previous release for rollback"
57
+ else
58
+ "rm -f #{current_release_symlink}; ln -s #{previous_release_directory} #{current_release_symlink} && rm -rf #{latest_release_directory}"
59
+ end
60
+ end
61
+
62
+ def self.define_tasks
63
+ return if @tasks_already_defined
64
+ @tasks_already_defined = true
65
+ namespace :yad do
66
+
67
+ desc "Prepares one or more servers for deployment"
68
+ remote_task :setup do
69
+ Rake::Task['yad:core:setup_deployment'].invoke
70
+ Rake::Task.invoke_if_defined('yad:framework:setup', :framework)
71
+ end
72
+
73
+ desc "Copies files to the shared/config directory using FILES=a,b,c (e.g. rake vlad:upload_config_files FILES=config/database.yml,config/maintenance.html)"
74
+ remote_task :upload_config_files do
75
+ files = Yad::Core.build_files_array(ENV["FILES"])
76
+ if files.empty?
77
+ puts("Please specify at least one file to upload (via the FILES environment variable)")
78
+ else
79
+ files.each do |file|
80
+ rsync(file, "#{target_host}:#{File.join(shared_config_path, File.basename(file))}")
81
+ end
82
+ puts("uploaded #{files.inspect} to #{target_host}")
83
+ end
84
+ end
85
+
86
+ desc "Creates the database for the application"
87
+ remote_task :create_db, :roles => :app do
88
+ Rake::Task.invoke_if_defined('yad:db:create', :db, "Please specify the database delegate via the :db variable")
89
+ end
90
+
91
+ desc "Updates the application servers to the latest version"
92
+ remote_task :update, :roles => :app do
93
+ Rake::Task.invoke_if_defined('yad:scm:update', :scm)
94
+ Rake::Task.invoke_if_defined('yad:framework:update', :framework)
95
+ Rake::Task['yad:core:update_symlink'].invoke
96
+ end
97
+
98
+ desc "Runs migrations for the database for the application"
99
+ remote_task :migrate_db, :roles => :app do
100
+ Rake::Task.invoke_if_defined('yad:db:migrate', :db, "Please specify the database delegate via the :db variable")
101
+ end
102
+
103
+ desc "Starts the application server"
104
+ remote_task :start_app, :roles => :app do
105
+ Rake::Task.invoke_if_defined('yad:app:start', :app, "Please specify the app delegate via the :app variable")
106
+ end
107
+
108
+ desc "Starts the web server"
109
+ remote_task :start_web, :roles => :web do
110
+ Rake::Task.invoke_if_defined('yad:web:start', :web, "Please specify the web delegate via the :web variable")
111
+ end
112
+
113
+ "Stops the web server"
114
+ remote_task :stop_web, :roles => :web do
115
+ Rake::Task.invoke_if_defined('yad:web:stop', :web, "Please specify the web delegate via the :web variable")
116
+ end
117
+
118
+ desc "Stops the application server"
119
+ remote_task :stop_app, :roles => :app do
120
+ Rake::Task.invoke_if_defined('yad:app:stop', :app, "Please specify the app delegate via the :app variable")
121
+ end
122
+
123
+ desc "Turns on the maintenance page for the application"
124
+ remote_task :turn_on_maintenance, :roles => :web do
125
+ Rake::Task.invoke_if_defined('yad:maintenance:turn_on', :maintenance, "Please specify the maintenance delegate via the :maintenance variable")
126
+ end
127
+
128
+ desc "Turns off the maintenance page for the application"
129
+ remote_task :turn_off_maintenance, :roles => :web do
130
+ Rake::Task.invoke_if_defined('yad:maintenance:turn_off', :maintenance, "Please specify the maintenance delegate via the :maintenance variable")
131
+ end
132
+
133
+ desc "Rolls back to the previous release, but DOES NOT restart the application"
134
+ remote_task :rollback do
135
+ cmd = Yad::Core.build_rollback_command(current_path, previous_release, latest_release)
136
+ if cmd.length == 0
137
+ puts("could not rollback the code because there is no previous release")
138
+ else
139
+ run(cmd)
140
+ puts("rolled back to #{File.basename(previous_release)} on #{target_host}")
141
+ end
142
+ end
143
+
144
+ desc "Cleans up old releases"
145
+ remote_task :cleanup do
146
+ cmd = Yad::Core.build_cleanup_command(keep_releases, releases_path, releases)
147
+ run(cmd)
148
+ puts("old releases cleaned up on #{target_host}")
149
+ end
150
+
151
+ remote_task :invoke do
152
+ # TODO:
153
+ end
154
+
155
+ namespace :core do
156
+
157
+ remote_task :setup_deployment, :roles => :app do
158
+ options = Rake::RemoteTask.get_options_hash(:umask, :shared_subdirectories)
159
+ cmd = Yad::Core.build_setup_command(deploy_to, options)
160
+ run(cmd)
161
+ puts("Yad set up on #{target_host}")
162
+ end
163
+
164
+ remote_task :update_symlink, :roles => :app do
165
+ begin
166
+ symlinked = false
167
+ cmd = Yad::Core.build_update_symlink_command(current_path, release_path)
168
+ run(cmd)
169
+ puts("'current' symlink updated on #{target_host}")
170
+ symlinked = true
171
+ scm_value = Rake::RemoteTask.fetch(:scm, false)
172
+ if scm_value
173
+ scm_class = eval("Yad::Scm::#{scm_value.to_s.classify}")
174
+ options = Rake::RemoteTask.get_options_hash(:revision)
175
+ inline_command = scm_class.build_inline_revision_identifier_command(scm_path, options)
176
+ else
177
+ inline_command = 'none'
178
+ end
179
+ cmd = Yad::Core.build_revision_log_command(Time.now.utc.strftime("%Y%m%d%H%M.%S"), inline_command, release_path, deploy_to)
180
+ run(cmd)
181
+ rescue => e
182
+ if releases.length > 1 && symlinked then
183
+ cmd = Yad::Core.build_update_symlink_command(current_path, previous_release)
184
+ run(cmd)
185
+ end
186
+ cmd = Yad::Core.build_remove_directory_command(release_path)
187
+ run(cmd)
188
+ raise e
189
+ end
190
+ end
191
+
192
+ end
193
+
194
+ end
195
+ end
196
+
197
+ end # class Core
198
+
199
+ end # module Yad
@@ -0,0 +1,62 @@
1
+ module Yad
2
+ module Db
3
+ class Rails
4
+ def self.build_create_db_command(release_directory, options = {})
5
+ default_options = { :app_env => 'production',
6
+ :rake_cmd => 'rake'
7
+ }
8
+ options = default_options.merge(options)
9
+ "cd #{release_directory}; #{options[:rake_cmd]} RAILS_ENV=#{options[:app_env]} db:create"
10
+ end
11
+
12
+ def self.build_migrate_db_command(release_directory, options = {})
13
+ default_options = { :app_env => 'production',
14
+ :rake_cmd => 'rake',
15
+ :migrate_args => '',
16
+ }
17
+ options = default_options.merge(options)
18
+ "cd #{release_directory}; #{options[:rake_cmd]} RAILS_ENV=#{options[:app_env]} db:migrate #{options[:migrate_args]}"
19
+ end
20
+
21
+ def self.define_tasks
22
+ return if @tasks_already_defined
23
+ @tasks_already_defined = true
24
+ namespace :yad do
25
+ namespace :db do
26
+
27
+ desc "Creates the database for the application"
28
+ remote_task :create, :roles => :app do
29
+ break unless target_host == Rake::RemoteTask.hosts_for(:app).first
30
+ options = Rake::RemoteTask.get_options_hash(:app_env, :rake_cmd)
31
+ cmd = Yad::Db::Rails.build_create_db_command(current_path, options)
32
+ run(cmd)
33
+ puts("database created")
34
+ end
35
+
36
+ desc "Runs migrations on the database"
37
+ remote_task :migrate, :roles => :app do
38
+ break unless target_host == Rake::RemoteTask.hosts_for(:app).first
39
+ options = Rake::RemoteTask.get_options_hash(:app_env, :rake_cmd, :migrate_args)
40
+ target = Rake::RemoteTask.fetch(:migrate_target, false)
41
+ if target
42
+ target_directory = case target.to_sym
43
+ when :current then current_path
44
+ when :latest then latest_release
45
+ else raise ArgumentError, "unknown migration target #{target.inspect}"
46
+ end
47
+ else
48
+ target_directory = latest_release
49
+ end
50
+ cmd = Yad::Db::Rails.build_migrate_db_command(target_directory, options)
51
+ run(cmd)
52
+ puts("database migrations completed")
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+
59
+ end # class Rails
60
+
61
+ end # module Db
62
+ end # module Yad
@@ -0,0 +1,64 @@
1
+ module Yad
2
+ module Framework
3
+ class Rails
4
+ def self.build_setup_command(shared_directory, options = {})
5
+ default_options = { :umask => '02' }
6
+ options = default_options.merge(options)
7
+ dirs = [File.join(shared_directory, "log"),
8
+ File.join(shared_directory, "pids"),
9
+ File.join(shared_directory, "system")
10
+ ]
11
+ "umask #{options[:umask]} && mkdir -p #{dirs.join(' ')}"
12
+ end
13
+
14
+ def self.build_update_command(new_release_directory, shared_directory, options = {})
15
+ default_options = { :app_env => 'production',
16
+ :framework_update_db_config_via => 'none' }
17
+ options = default_options.merge(options)
18
+ commands = ["rm -rf #{new_release_directory}/log #{new_release_directory}/public/system #{new_release_directory}/tmp/pids",
19
+ "mkdir -p #{new_release_directory}/tmp",
20
+ "ln -s #{shared_directory}/log #{new_release_directory}/log",
21
+ "ln -s #{shared_directory}/pids #{new_release_directory}/tmp/pids",
22
+ "ln -s #{shared_directory}/system #{new_release_directory}/public/system"
23
+ ]
24
+
25
+ case options[:framework_update_db_config_via].to_sym
26
+ when :copy
27
+ commands << "cp -f #{new_release_directory}/config/database_#{options[:app_env]}.yml #{new_release_directory}/config/database.yml"
28
+ when :symlink
29
+ commands << "ln -nfs #{shared_directory}/config/database.yml #{new_release_directory}/config/database.yml"
30
+ end
31
+
32
+ commands.join(" && ")
33
+ end
34
+
35
+ def self.define_tasks
36
+ return if @tasks_already_defined
37
+ @tasks_already_defined = true
38
+ namespace :yad do
39
+ namespace :framework do
40
+
41
+ desc "Performs additional setup needed for the framework"
42
+ remote_task :setup, :roles => :app do
43
+ options = Rake::RemoteTask.get_options_hash(:umask)
44
+ cmd = Yad::Framework::Rails.build_setup_command(shared_path, options)
45
+ run(cmd)
46
+ puts("Rails set up on #{target_host}")
47
+ end
48
+
49
+ desc "Updates the framework configuration and working directories after a new release has been exported"
50
+ remote_task :update, :roles => :app do
51
+ options = Rake::RemoteTask.get_options_hash(:app_env, :framework_update_db_config_via)
52
+ cmd = Yad::Framework::Rails.build_update_command(release_path, shared_path, options)
53
+ run(cmd)
54
+ puts("Rails shared paths and files updated on #{target_host}")
55
+ end
56
+
57
+ end
58
+ end
59
+ end
60
+
61
+ end # class Rails
62
+
63
+ end # module Framework
64
+ end # module Yad
@@ -0,0 +1,39 @@
1
+ module Yad
2
+ module Maintenance
3
+ class SharedSystem
4
+ def self.build_turn_on_command(shared_directory, options = {})
5
+ "cp -f #{shared_directory}/config/maintenance.html #{shared_directory}/system/"
6
+ end
7
+
8
+ def self.build_turn_off_command(shared_directory, options = {})
9
+ "rm -f #{shared_directory}/system/maintenance.html"
10
+ end
11
+
12
+ def self.define_tasks
13
+ return if @tasks_already_defined
14
+ @tasks_already_defined = true
15
+ namespace :yad do
16
+ namespace :maintenance do
17
+
18
+ desc "Turns on the maintenance page for the application"
19
+ remote_task :turn_on, :roles => :web do
20
+ cmd = Yad::Maintenance::SharedSystem.build_turn_on_command(shared_path)
21
+ run(cmd)
22
+ puts("maintenance page turned on for #{target_host}")
23
+ end
24
+
25
+ desc "Turns off the maintenance page for the application"
26
+ remote_task :turn_off, :roles => :web do
27
+ cmd = Yad::Maintenance::SharedSystem.build_turn_off_command(shared_path)
28
+ run(cmd)
29
+ puts("maintenance page turned off for #{target_host}")
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+
36
+ end # class Rails
37
+
38
+ end # module Maintenance
39
+ end # module Yad