capistrano-atlas 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +215 -0
  7. data/Rakefile +5 -0
  8. data/capistrano-atlas.gemspec +32 -0
  9. data/lib/capistrano/atlas.rb +27 -0
  10. data/lib/capistrano/atlas/compatibility.rb +37 -0
  11. data/lib/capistrano/atlas/dsl.rb +157 -0
  12. data/lib/capistrano/atlas/recipe.rb +49 -0
  13. data/lib/capistrano/atlas/templates/crontab.erb +1 -0
  14. data/lib/capistrano/atlas/templates/csr_config.erb +10 -0
  15. data/lib/capistrano/atlas/templates/logrotate.erb +9 -0
  16. data/lib/capistrano/atlas/templates/maintenance.html.erb +26 -0
  17. data/lib/capistrano/atlas/templates/nginx.erb +64 -0
  18. data/lib/capistrano/atlas/templates/nginx_site.erb +97 -0
  19. data/lib/capistrano/atlas/templates/pgpass.erb +1 -0
  20. data/lib/capistrano/atlas/templates/postgresql-backup-logrotate.erb +11 -0
  21. data/lib/capistrano/atlas/templates/puma.rb.erb +22 -0
  22. data/lib/capistrano/atlas/templates/puma_init.erb +43 -0
  23. data/lib/capistrano/atlas/templates/rbenv_bashrc +4 -0
  24. data/lib/capistrano/atlas/templates/sidekiq_init.erb +100 -0
  25. data/lib/capistrano/atlas/templates/ssl_setup +43 -0
  26. data/lib/capistrano/atlas/templates/version.rb.erb +3 -0
  27. data/lib/capistrano/atlas/version.rb +5 -0
  28. data/lib/capistrano/tasks/aptitude.rake +111 -0
  29. data/lib/capistrano/tasks/bundler.rake +31 -0
  30. data/lib/capistrano/tasks/crontab.rake +14 -0
  31. data/lib/capistrano/tasks/defaults.rake +137 -0
  32. data/lib/capistrano/tasks/dotenv.rake +57 -0
  33. data/lib/capistrano/tasks/logrotate.rake +16 -0
  34. data/lib/capistrano/tasks/maintenance.rake +28 -0
  35. data/lib/capistrano/tasks/migrate.rake +29 -0
  36. data/lib/capistrano/tasks/nginx.rake +25 -0
  37. data/lib/capistrano/tasks/postgresql.rake +149 -0
  38. data/lib/capistrano/tasks/provision.rake +18 -0
  39. data/lib/capistrano/tasks/puma.rake +67 -0
  40. data/lib/capistrano/tasks/rake.rake +20 -0
  41. data/lib/capistrano/tasks/rbenv.rake +104 -0
  42. data/lib/capistrano/tasks/seed.rake +16 -0
  43. data/lib/capistrano/tasks/sidekiq.rake +42 -0
  44. data/lib/capistrano/tasks/ssl.rake +57 -0
  45. data/lib/capistrano/tasks/ufw.rake +32 -0
  46. data/lib/capistrano/tasks/user.rake +32 -0
  47. data/lib/capistrano/tasks/version.rake +34 -0
  48. metadata +161 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0fdb1cb92c6e823effad36625a49db5dccb2ea5b
4
+ data.tar.gz: 3858ea7c0f6e411411fe880d502428686cafc8a5
5
+ SHA512:
6
+ metadata.gz: e6b7c06a79714867e4c37e7fe2aa83756793b2f47467eea82f6d2d9afd25c629e58921882c0b532466a8f89b25afab8e082c6cb6af680819dc2e3691e66b4c9b
7
+ data.tar.gz: f4a9a75485061d6f79045384de70b2e020577b29ac7af225028637627eacbd1fb37ebc753366070ea30d0d26898d65a44363e83a8689da1f114468b7089c053f
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ ## [Unreleased][]
2
+
3
+ * Your contribution here!
4
+
5
+ ## [0.0.1][] (2017-11-01)
6
+
7
+ * Fork, and starting to change things for Puma and Let's Encrypt support in production.
8
+
9
+
10
+
11
+ [Unreleased]: https://github.com/mattbrictson/capistrano-atlas/compare/v0.32.0...HEAD
12
+ [0.32.0]: https://github.com/mattbrictson/capistrano-atlas/compare/v0.31.0...v0.32.0
13
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano-atlas.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 John McDowall & Matt Brictson
2
+
3
+ MIT License
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.
data/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # capistrano-atlas
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/capistrano-atlas.svg)](http://badge.fury.io/rb/capistrano-atlas)
4
+
5
+ **This is a fork of `capistrano-mb` by the excellent Matt Brictson and FiftyFive. I've changed things to use Puma and Let's Encrypt in production.**
6
+
7
+ Capistrano is great for deploying Rails applications, but what about all the prerequisites, like Nginx and PostgreSQL? Do you have a firewall configured on your VPS? Have you installed the latest OS security updates? Is HTTPS working right?
8
+
9
+ The capistrano-atlas gem adds a `cap <stage> provision` task to Capistrano that takes care of all that. Out of the box, `provision` will:
10
+
11
+ * Install the latest `postgresql`, `node.js`, and `nginx` apt packages
12
+ * Install all libraries needed to build Ruby
13
+ * Lock down your VPS using `ufw` (a simple front-end to iptables)
14
+ * Set up `logrotated` for your Rails logs
15
+ * Schedule an automatic daily backup of your Rails database
16
+ * Generate a self-signed SSL certificate if you need one
17
+ * Set up ngnix with the latest SSL practices and integrate it with Puma for your Rails app
18
+ * Create the `deployer` user and install an SSH public key
19
+ * Install `rbenv` and use `ruby-build` to compile the version of Ruby required by your app (by inspecting your `.ruby-version` file)
20
+ * And more!
21
+
22
+ The gem is named "capistrano-atlas" because it does the heavy lifting of setting up a VPS to be ready for modern Rails 5.1+ applications.
23
+
24
+ You'll notice that capistrano-atlas is opinionated and strictly uses the following stack:
25
+
26
+ * Ubuntu 14.04 LTS
27
+ * PostgreSQL
28
+ * Puma
29
+ * Nginx
30
+ * rbenv
31
+ * dotenv
32
+
33
+ In addition, capistrano-atlas changes many of Capistrano's defaults, including the deployment location, Bundler behavior, and SSH keep-alive settings. (See [defaults.rake][] for details.)
34
+
35
+ Not quite to your liking? Consider forking the project to meet your needs.
36
+
37
+
38
+ ## Quick start
39
+
40
+ Please note that this project requires **Capistrano 3.x**, which is a complete rewrite of Capistrano 2.x. The two major versions are not compatible.
41
+
42
+ ### 1. Purchase an Ubuntu 14.04 VPS
43
+
44
+ To use capistrano-atlas, you'll need a clean Ubuntu server to deploy to. The only special requirement is that your public SSH key must be installed on the server for the `root` user.
45
+
46
+ Test that you can SSH to the server as `root` without being prompted for a password. If that works, capistrano-atlas can take care of the rest. You're ready to proceed!
47
+
48
+ ### 2. .ruby-version
49
+
50
+ capistrano-atlas needs to know the version of Ruby that your app requires, so that it can install Ruby during the provisioning process. Place a `.ruby-version` file in the root of your project containing the desired version, like this:
51
+
52
+ ```
53
+ 2.2.3
54
+ ```
55
+
56
+ *If you are using `rbenv`, just run `rbenv local 2.2.3` and it will create this file for you.*
57
+
58
+ ### 3. Gemfile
59
+
60
+ capistrano-atlas makes certain assumptions about your Rails app, namely that it uses [dotenv][] to manage Rails secrets via environment variables, and that it runs on top of PostgreSQL and [Puma][]. Make sure they are specified in the Gemfile:
61
+
62
+ ```ruby
63
+ gem "dotenv-rails", ">= 2.0.0"
64
+ gem "pg", "~> 0.18"
65
+ gem "Puma"
66
+ ```
67
+
68
+ Then for the capistrano-atlas tools themselves, add these gems to the development group:
69
+
70
+ ```ruby
71
+ group :development do
72
+ gem "capistrano-bundler", :require => false
73
+ gem "capistrano-rails", :require => false
74
+ gem "capistrano", "~> 3.4.0", :require => false
75
+ gem "capistrano-atlas", :require => false
76
+ end
77
+ ```
78
+
79
+ And then execute:
80
+
81
+ ```
82
+ $ bundle
83
+ ```
84
+
85
+ ### 4. cap install
86
+
87
+ If your project doesn't yet have a `Capfile`, run `cap install` with the list of desired stages (environments). For simplicity, this installation guide will assume a single production stage:
88
+
89
+ ```
90
+ cap install STAGES=production
91
+ ```
92
+
93
+ ### 5. Capfile
94
+
95
+ Add these lines to the **bottom** of your app's `Capfile` (order is important!):
96
+
97
+ ```ruby
98
+ require "capistrano/bundler"
99
+ require "capistrano/rails"
100
+ require "capistrano/atlas"
101
+ ```
102
+
103
+ ### 6. deploy.rb
104
+
105
+ Modify `config/deploy.rb` to set the specifics of your Rails app. At the minimum, you'll need to set these two options:
106
+
107
+ ```ruby
108
+ set :application, "my_app_name"
109
+ set :repo_url, "git@github.com:username/repository.git"
110
+ ```
111
+
112
+ ### 7. production.rb
113
+
114
+ Modify `config/deploy/production.rb` to specify the IP address of your production server. In this example, I have a single 1GB VPS (e.g. at DigitalOcean) that plays all the roles:
115
+
116
+ ```ruby
117
+ server "my.production.ip",
118
+ :user => "deployer",
119
+ :roles => %w(app backup cron db web)
120
+ ```
121
+
122
+ *Note that you must include the `backup` and `cron` roles if you want to make use of capistrano-atlas's database backups and crontab features.*
123
+
124
+ ### 8. secrets.yml
125
+
126
+ By default, Rails 4.2 apps have a `config/secrets.yml` file that specifies the Rails secret key. capistrano-atlas configures dotenv to provide this secret in a `RAILS_SECRET_KEY_BASE` environment variable. You'll therefore need to modify `secrets.yml` as follows:
127
+
128
+ ```ruby
129
+ production:
130
+ secret_key_base: <%= ENV["RAILS_SECRET_KEY_BASE"] %>
131
+ ```
132
+
133
+ ### 9. Provision and deploy!
134
+
135
+ Run capistrano-atlas's `provision:14_04` task (named for Ubuntu 14.04). This will ask you a few questions, install Ruby, PostgreSQL, Nginx, etc., and set everything up. The entire process takes about 10 minutes (mostly due to compiling Ruby from source).
136
+
137
+ ```
138
+ bundle exec cap production provision:14_04
139
+ ```
140
+
141
+ Once that's done, your app is now ready to deploy!
142
+
143
+ ```
144
+ bundle exec cap production deploy
145
+ ```
146
+
147
+ ## Advanced usage
148
+
149
+ ### Choosing which recipes to auto-run
150
+
151
+ Most of the capistrano-atlas recipes are designed to run automatically as part of `cap <stage> provision`, for installing and setting up various bits of the Rails infrastructure, like nginx, Puma, and postgres. Some recipes also contribute to the `cap <stage> deploy` process.
152
+
153
+ *This auto-run behavior is fully under your control.* In your `deploy.rb`, set `:atlas_recipes` to an array of the desired recipes. If you don't want a recipe to execute as part of `deploy`/`provision`, simply omit it from the list.
154
+
155
+ The following list will suffice for most out-of-the-box Rails apps. The order of the list is not important.
156
+
157
+ ```ruby
158
+ set :atlas_recipes, %w(
159
+ aptitude
160
+ crontab
161
+ dotenv
162
+ logrotate
163
+ migrate
164
+ nginx
165
+ postgresql
166
+ rbenv
167
+ seed
168
+ ssl
169
+ ufw
170
+ Puma
171
+ user
172
+ version
173
+ )
174
+ ```
175
+
176
+ Even if you don't include a recipe in the auto-run list, you can still invoke the tasks of those recipes manually at your discretion. Run `bundle exec cap -T` to see the full list of tasks.
177
+
178
+ ### Configuration
179
+
180
+ Many of the recipes have default settings that can be overridden. Use your
181
+ `deploy.rb` file to specify these overrides. Or, you can override per stage.
182
+ Here is an example override:
183
+
184
+ set :atlas_Puma_workers, 8
185
+
186
+ For the full list of settings and their default values, refer to [defaults.rake][].
187
+
188
+
189
+ ## Further reading
190
+
191
+ Check out my [rails-template][] project, which generates Rails applications with capistrano-atlas pre-configured and ready to go.
192
+
193
+
194
+ ## History
195
+
196
+ This gem used to be called capistrano-fiftyfive, because it was initially built by [55 Minutes](http://55minutes.com) to automate its Rails deployments. I have since taken over ownership of the gem and renamed it to capistrano-atlas to avoid any confusion.
197
+
198
+ If you are upgrading from `capistrano-fiftyfive`, refer to the [CHANGELOG entry for v0.22.0](CHANGELOG.md#0220-2015-06-22) for migration instructions.
199
+
200
+ ## Contributing
201
+
202
+ 1. Fork it
203
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
204
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
205
+ 4. Push to the branch (`git push origin my-new-feature`)
206
+ 5. Create new Pull Request
207
+
208
+
209
+ [Postmark]:https://postmarkapp.com
210
+ [cast337]:http://railscasts.com/episodes/337-capistrano-recipes
211
+ [cast373]:http://railscasts.com/episodes/373-zero-downtime-deployment
212
+ [defaults.rake]:lib/capistrano/tasks/defaults.rake
213
+ [rails-template]:https://github.com/mattbrictson/rails-template/
214
+ [dotenv]:https://github.com/bkeepers/dotenv
215
+ [Puma]:http://Puma.bogomips.org/
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require "chandler/tasks"
3
+
4
+ # Add chandler as a prerequisite for `rake release`
5
+ #task "release:rubygem_push" => "chandler:push"
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "capistrano/atlas/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "capistrano-atlas"
8
+ spec.version = Capistrano::Atlas::VERSION
9
+ spec.author = "John McDowall"
10
+ spec.email = "john@kantan.io"
11
+ spec.description = \
12
+ "Does all the heavy lifting for production-ready provisioning "\
13
+ "and deployment for the full Rails 5.1 stack. Installs and "\
14
+ "configures Ruby, Nginx, Puma, PostgreSQL, dotenv, Let's Encrypt and "\
15
+ "more onto Ubuntu 14.04 LTS using Capistrano. "
16
+
17
+ spec.summary = "Additional Capistrano 3 recipes"
18
+ spec.homepage = "https://github.com/johnmcdowall/capistrano-atlas"
19
+ spec.license = "MIT"
20
+
21
+ spec.files = `git ls-files`.split($/)
22
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "capistrano", ">= 3.3.5"
27
+ spec.add_dependency "sshkit", ">= 1.6.1"
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.3"
30
+ spec.add_development_dependency "chandler"
31
+ spec.add_development_dependency "rake"
32
+ end
@@ -0,0 +1,27 @@
1
+ require "digest"
2
+ require "monitor"
3
+ require "capistrano/atlas/version"
4
+ require "capistrano/atlas/compatibility"
5
+ require "capistrano/atlas/dsl"
6
+ require "capistrano/atlas/recipe"
7
+ include Capistrano::Atlas::DSL
8
+
9
+ load File.expand_path("../tasks/provision.rake", __FILE__)
10
+ load File.expand_path("../tasks/defaults.rake", __FILE__)
11
+ load File.expand_path("../tasks/user.rake", __FILE__)
12
+ load File.expand_path("../tasks/aptitude.rake", __FILE__)
13
+ load File.expand_path("../tasks/ufw.rake", __FILE__)
14
+ load File.expand_path("../tasks/ssl.rake", __FILE__)
15
+ load File.expand_path("../tasks/dotenv.rake", __FILE__)
16
+ load File.expand_path("../tasks/postgresql.rake", __FILE__)
17
+ load File.expand_path("../tasks/nginx.rake", __FILE__)
18
+ load File.expand_path("../tasks/crontab.rake", __FILE__)
19
+ load File.expand_path("../tasks/logrotate.rake", __FILE__)
20
+ load File.expand_path("../tasks/rbenv.rake", __FILE__)
21
+ load File.expand_path("../tasks/maintenance.rake", __FILE__)
22
+ load File.expand_path("../tasks/migrate.rake", __FILE__)
23
+ load File.expand_path("../tasks/seed.rake", __FILE__)
24
+ load File.expand_path("../tasks/version.rake", __FILE__)
25
+ load File.expand_path("../tasks/rake.rake", __FILE__)
26
+ load File.expand_path("../tasks/sidekiq.rake", __FILE__)
27
+ load File.expand_path("../tasks/bundler.rake", __FILE__)
@@ -0,0 +1,37 @@
1
+ module Capistrano
2
+ module Atlas
3
+ module Compatibility
4
+ def self.check
5
+ check_capistrano_and_rake_are_loaded
6
+ check_blacklisted_capistrano_version
7
+ end
8
+
9
+ def self.check_capistrano_and_rake_are_loaded
10
+ return if defined?(Capistrano::VERSION) && defined?(Rake)
11
+
12
+ warn "capistrano/atlas must be loaded by Capistrano in order "\
13
+ "to work.\nRequire this gem by using Capistrano's Capfile, "\
14
+ "as described here:\n"\
15
+ "https://github.com/mattbrictson/capistrano-atlas#installation"
16
+ end
17
+
18
+ def self.check_blacklisted_capistrano_version
19
+ return unless defined?(Capistrano::VERSION)
20
+ return unless Capistrano::VERSION == "3.2.0"
21
+
22
+ warn "Capistrano 3.2.0 has a critical bug that prevents "\
23
+ "capistrano-atlas from working as intended:\n"\
24
+ "https://github.com/capistrano/capistrano/issues/1004"
25
+ end
26
+
27
+ # We can't really rely on anything being loaded at this point, so define
28
+ # our own basic colorizing helper.
29
+ def self.warn(message)
30
+ return $stderr.puts("WARNING: #{message}") unless $stderr.tty?
31
+ $stderr.puts("\e[0;31;49mWARNING: #{message}\e[0m")
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ Capistrano::Atlas::Compatibility.check
@@ -0,0 +1,157 @@
1
+ module Capistrano
2
+ module Atlas
3
+ module DSL
4
+
5
+ # Invoke the given task. If a task with that name is not defined,
6
+ # silently skip it.
7
+ #
8
+ def invoke_if_defined(task)
9
+ invoke(task) if Rake::Task.task_defined?(task)
10
+ end
11
+
12
+ # Used internally by capistrano-atlas to register tasks such that
13
+ # those tasks are executed conditionally based on the presence of the
14
+ # recipe name in fetch(:atlas_recipes).
15
+ #
16
+ # atlas_recipe :aptitude do
17
+ # during :provision, %w(task1 task2 ...)
18
+ # end
19
+ #
20
+ def atlas_recipe(recipe_name, &block)
21
+ Recipe.new(recipe_name).instance_exec(&block)
22
+ end
23
+
24
+ def compatibility_warning(warning)
25
+ Capistrano::Atlas::Compatibility.warn(warning)
26
+ end
27
+
28
+ # Helper for calling fetch(:application) and making the value safe for
29
+ # using in filenames, usernames, etc. Replaces non-word characters with
30
+ # underscores.
31
+ #
32
+ def application_basename
33
+ fetch(:application).to_s.gsub(/[^a-zA-Z0-9_]/, "_")
34
+ end
35
+
36
+ # Prints a question and returns truthy if the user answers "y" or "yes".
37
+ def agree(yes_or_no_question)
38
+ $stdout.print(yes_or_no_question)
39
+ $stdin.gets.to_s =~ /^y(es)?/i
40
+ end
41
+
42
+ # Like capistrano's built-in on(), but connects to the server as root.
43
+ # To use a user other than root, set :atlas_privileged_user or
44
+ # specify :privileged_user as a server property.
45
+ #
46
+ # task :reboot do
47
+ # privileged_on roles(:all) do
48
+ # execute :shutdown, "-r", "now"
49
+ # end
50
+ # end
51
+ #
52
+ def privileged_on(*args, &block)
53
+ on(*args) do |host|
54
+ if host.nil?
55
+ instance_exec(nil, nil, &block)
56
+ else
57
+ original_user = host.user
58
+
59
+ begin
60
+ host.user = host.properties.privileged_user ||
61
+ fetch(:atlas_privileged_user)
62
+ instance_exec(host, original_user, &block)
63
+ ensure
64
+ host.user = original_user
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ # Uploads the given string or file-like object to the current host
71
+ # context. Intended to be used within an on() or privileged_on() block.
72
+ # Accepts :owner and :mode options that affect the permissions of the
73
+ # remote file.
74
+ #
75
+ def put(string_or_io, remote_path, opts={})
76
+ sudo_exec = ->(*cmd) {
77
+ cmd = [:sudo] + cmd if opts[:sudo]
78
+ execute *cmd
79
+ }
80
+
81
+ tmp_path = "/tmp/#{SecureRandom.uuid}"
82
+
83
+ owner = opts[:owner]
84
+ mode = opts[:mode]
85
+
86
+ source = if string_or_io.respond_to?(:read)
87
+ string_or_io
88
+ else
89
+ StringIO.new(string_or_io.to_s)
90
+ end
91
+
92
+ sudo_exec.call :mkdir, "-p", File.dirname(remote_path)
93
+
94
+ upload!(source, tmp_path)
95
+
96
+ sudo_exec.call(:mv, "-f", tmp_path, remote_path)
97
+ sudo_exec.call(:chown, owner, remote_path) if owner
98
+ sudo_exec.call(:chmod, mode, remote_path) if mode
99
+ end
100
+
101
+
102
+ # Read the specified file from the local system, interpret it as ERb,
103
+ # and upload it to the current host context. Intended to be used with an
104
+ # on() or privileged_on() block. Accepts :owner, :mode, and :binding
105
+ # options.
106
+ #
107
+ # Templates with relative paths are first searched for in
108
+ # lib/capistrano/atlas/templates in the current project. This gives
109
+ # applications a chance to override. If an override is not found, the
110
+ # default template within the capistrano-atlas gem is used.
111
+ #
112
+ # task :create_database_yml do
113
+ # on roles(:app, :db) do
114
+ # within(shared_path) do
115
+ # template fetch(:database_yml_template_path),
116
+ # "config/database.yml",
117
+ # :mode => "600"
118
+ # end
119
+ # end
120
+ # end
121
+ #
122
+ def template(local_path, remote_path, opts={})
123
+ binding = opts[:binding] || binding
124
+
125
+ unless local_path.start_with?("/")
126
+ override_path = File.join("lib/capistrano/atlas/templates", local_path)
127
+
128
+ unless File.exist?(override_path)
129
+ override_path = File.join(
130
+ "lib/capistrano/atlas/templates",
131
+ local_path
132
+ )
133
+ if File.exist?(override_path)
134
+ compatibility_warning(
135
+ "Please move #{override_path} from lib/capistrano/atlas "\
136
+ "to lib/capistrano/atlas to ensure future compatibility with "\
137
+ "capistrano-atlas."
138
+ )
139
+ end
140
+ end
141
+
142
+ local_path = if File.exist?(override_path)
143
+ override_path
144
+ else
145
+ File.expand_path(File.join("../templates", local_path), __FILE__)
146
+ end
147
+ end
148
+
149
+ erb = File.read(local_path)
150
+ rendered_template = ERB.new(erb).result(binding)
151
+
152
+ put(rendered_template, remote_path, opts)
153
+ end
154
+ end
155
+ end
156
+ end
157
+