yad 0.0.4

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.
@@ -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