capistrano-bundle_rsync 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 230c7ac05986a116441bf2c1d1322efc1ad936b3
4
+ data.tar.gz: e9919ec57dddf809f1757f7d00feb0b27431ef5f
5
+ SHA512:
6
+ metadata.gz: 8394fcb8707bbaecf7185b2b80dc947677c58228127391b67cdb636f5c075596475e2ccf56a66972a96d7c34f5f65ed4a95c919df3fda5637e3ca8223d187162
7
+ data.tar.gz: 726fbbab18998b824396c1f266a4e2fa36e9f44ed36950ba412e08855b3c7cc933a0dc5ed8dff2d314b8433ea4b386813774f35f294f8b3c3cb8661b5f9e6dfb
@@ -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
@@ -0,0 +1,3 @@
1
+ # 0.0.2 (2014/07/08)
2
+
3
+ First version
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano-bundle_rsync.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Naotoshi Seo
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.
@@ -0,0 +1,184 @@
1
+ # Capistrano::BundleRsync for Capistrano v3
2
+
3
+ Deploy an application and bundled gems via rsync
4
+
5
+ ## What is this for?
6
+
7
+ Capistrano::BundleRsync requires to bundle gems only once on the deploy machine,
8
+ which saves you from building gems on each your production machine.
9
+
10
+ Also saves you from having to install Git and Build Tools on your production machine.
11
+
12
+ ## How it works
13
+
14
+ Capistrano::BundleRsync works as followings:
15
+
16
+ 1. Do `git clone --mirror URL .local_repo/repo` on a deploy (local) machine.
17
+ 2. Extract a branch by `git archive {branch}` to `.local_repo/release_{time}`
18
+ 4. Deploy the `release` directory to remote machines by `rsync`.
19
+ 3. Do `bundle --without development,test --path .local_repo/bundle` on a deploy (local) machine.
20
+ 5. Deploy the `bundle` directory to remote machines by `rsync`.
21
+
22
+ ## Prerequisites
23
+
24
+ The deploy machine and remote machines must be on same architectures (i386, x86\_64) because
25
+ C exntension gems are built on the deploy machine and transfered by rsync.
26
+
27
+ Requiremens on remote machines:
28
+
29
+ 1. rbenv (rvm should work, but not verified)
30
+ 2. ruby
31
+
32
+ Requirements on a deploy machine:
33
+
34
+ 1. rbenv (rvm should work, but not verified)
35
+ 2. git
36
+ 3. Build Tools required to build C exntension gems (like gcc).
37
+ 4. A ruby to execute capistrano (you may use the ruby of 5.)
38
+ 5. The same ruby used at your remote machines
39
+ 6. A ssh key to login to your remote machines via ssh (Passowrd authentication is not supported)
40
+
41
+ Notice that it is not required to have Git and Build Tools on each remote machine.
42
+
43
+ ## Configuration
44
+
45
+ Set Capistrano variables with `set name, value`.
46
+
47
+ Name | Default | Description
48
+ --------------|---------|------------
49
+ repo_url | `.` | The path or URL to a Git repository to clone from.
50
+ branch | `master` | The Git branch to checkout.
51
+ ssh_options | `{}` | Configuration of ssh :user and :keys.
52
+ bundle_rsync_local_base_path | `$(pwd)/.local_repo` | The working base directory
53
+ bundle_rsync_local_repo_path | `#{base_path}/repo"` | Path where to mirror your repository
54
+ bundle_rsync_local_release_path | `"#{base_path}/relase_#{Time.now.to_i}"` | Path where to checkout your repository
55
+ bundle_rsync_local_bundle_path | `"#{base_path}/bundle"` | Path where to bundle install gems.
56
+ bundle_rsync_local_bin_path | `"#{base_path}/bin"` | Path where to bundle install bin scripts.
57
+ bundle_rsync_config_files | `nil` | Additional files to rsync. Specified files are copied into `config` directory.
58
+ bundle_rsync_ssh_options | `ssh_options` | Configuration of ssh for rsync. Default uses the value of `ssh_options`
59
+ bundle_rsync_max_parallels | number of hosts | Number of concurrency. The default is the number of hosts to deploy.
60
+
61
+ ## Installation
62
+
63
+ Add this line to your application's Gemfile:
64
+
65
+ gem 'capistrano-bundle_rsync'
66
+
67
+ And then execute:
68
+
69
+ $ bundle
70
+
71
+ Or install it yourself as:
72
+
73
+ $ gem install capistrano-bundle_rsync
74
+
75
+ ## Usage
76
+
77
+ Add followings to your Gemfile:
78
+
79
+ ```ruby
80
+ gem 'capistrano'
81
+ gem 'capistrano-rbenv'
82
+ gem 'capistrano-bundle_rsync'
83
+ ```
84
+
85
+ Run `bundle exec cap install`.
86
+
87
+ ```bash
88
+ $ bundle
89
+ $ bundle exec cap install
90
+ ```
91
+
92
+ This creates the following files:
93
+
94
+ ```
95
+ ├── Capfile
96
+ ├── config
97
+ │ ├── deploy
98
+ │ │ ├── production.rb
99
+ │ │ └── staging.rb
100
+ │ └── deploy.rb
101
+ └── lib
102
+ └── capistrano
103
+ └── tasks
104
+ ```
105
+
106
+ To create different stages:
107
+
108
+ ```bash
109
+ $ bundle exec cap install STAGES=localhost,sandbox,qa,production
110
+ ```
111
+
112
+ Edit Capfile:
113
+
114
+ ```ruby
115
+ # Load DSL and Setup Up Stages
116
+ require 'capistrano/setup'
117
+
118
+ # Includes default deployment tasks
119
+ require 'capistrano/deploy'
120
+
121
+ # Includes tasks from other gems included in your Gemfile
122
+ require 'capistrano/rbenv'
123
+ require 'capistrano/bundle_rsync'
124
+
125
+ # Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
126
+ Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
127
+ ```
128
+
129
+ Edit `config/deploy/localhost.rb` as followings for example:
130
+
131
+ ```ruby
132
+ set :branch, ENV['BRANCH'] || 'master'
133
+ set :rbenv_type, :user
134
+ set :linked_dirs, %w(bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system tmp/run)
135
+ set :keep_releases, 5
136
+ set :scm, :bundle_rsync # Need this
137
+ set :bundle_rsync_max_parallels, ENV['PARA']
138
+ set :bundle_rsync_config_files, ['~/config/database.yml']
139
+
140
+ set :application, 'sample'
141
+ set :repo_url, "git@github.com:sonots/rails-sample.git"
142
+ set :deploy_to, "/home/sonots/sample"
143
+ set :rbenv_ruby, "2.1.2" # Required on both deploy machine and remote machines
144
+ set :ssh_options, user: 'sonots', keys: [File.expand_path('~/.ssh/id_rsa'), File.expand_path('~/.ssh/id_dsa')]
145
+
146
+ role :app, ['127.0.0.1']
147
+ ```
148
+
149
+ Deploy by following command:
150
+
151
+ ```bash
152
+ $ bundle exec cap localhost deploy
153
+ ```
154
+
155
+ ## FAQ
156
+
157
+ Q. What is difference with [capistrano-rsync](https://github.com/moll/capistrano-rsync)?
158
+
159
+ A. capistrano-bundle\_rsync does `bundle install` at the deploy machine, not on each remote machine.
160
+
161
+ ## ToDo
162
+
163
+ 1. Support rsync_options
164
+ 2. Support other SCMs than `git`.
165
+
166
+ ## ChangeLog
167
+
168
+ [CHANGELOG.md](./CHANGELOG.md)
169
+
170
+ ## Contributing
171
+
172
+ 1. Fork it
173
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
174
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
175
+ 4. Push to the branch (`git push origin my-new-feature`)
176
+ 5. Create new Pull Request
177
+
178
+ ## Copyright
179
+
180
+ See [LICENSE.txt](./LICENSE.txt) for details.
181
+
182
+ ## Special Thanks
183
+
184
+ capistrano-bundle_rsync was originally created by [@tohae](https://github.com/tohae). Thank you very much!
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "capistrano-bundle_rsync"
7
+ spec.version = "0.1.0"
8
+ spec.authors = ["sonots", "tohae"]
9
+ spec.email = ["sonots@gmail.com", "tohaechan@gmail.com"]
10
+ spec.description = %q{Deploy an application and bundled gems via rsync}
11
+ spec.summary = %q{Deploy an application and bundled gems via rsync.}
12
+ spec.homepage = "https://github.com/sonots/capistrano-bundle_rsync"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency 'capistrano', '>= 3.0.0'
21
+ spec.add_dependency 'parallel'
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ end
File without changes
@@ -0,0 +1,7 @@
1
+ module Capistrano
2
+ module BundleRsync
3
+ end
4
+ end
5
+
6
+ require 'capistrano/bundle_rsync/config'
7
+ load File.expand_path('../tasks/bundle_rsync.rake', __FILE__)
@@ -0,0 +1,78 @@
1
+ module Capistrano::BundleRsync
2
+ class Config
3
+ def self.local_base_path
4
+ @local_base_path ||= fetch(:bundle_rsync_local_base_path) || "#{Dir::pwd}/.local_repo"
5
+ end
6
+
7
+ def self.local_repo_path
8
+ @local_repo_path ||= fetch(:bundle_rsync_local_repo_path) || "#{local_base_path}/repo"
9
+ end
10
+
11
+ def self.local_release_path
12
+ @local_release_path ||= fetch(:bundle_rsync_local_release_path) || "#{local_base_path}/release_#{Time.now.to_i}"
13
+ end
14
+
15
+ def self.local_bundle_path
16
+ @local_bundle_path ||= fetch(:bundle_rsync_local_bundle_path) || "#{local_base_path}/bundle"
17
+ end
18
+
19
+ def self.local_bin_path
20
+ @local_bin_path ||= fetch(:bundle_rsync_local_bin_path) || "#{local_base_path}/bin"
21
+ end
22
+
23
+ def self.config_files
24
+ return nil unless config_files = fetch(:bundle_rsync_config_files)
25
+ config_files.is_a?(Array) ? config_files : [config_files]
26
+ end
27
+
28
+ # Build ssh command options for rsync
29
+ #
30
+ # First, search available user and keys configurations for each role:
31
+ #
32
+ # role :app, ['hostname'], {
33
+ # user: username,
34
+ # keys: File.expand_path('~/.ssh/id_rsa'),
35
+ # port: 22,
36
+ # }
37
+ #
38
+ # If not available, look :bundle_rsync_ssh_options:
39
+ #
40
+ # set :bundle_rsync_ssh_options {
41
+ # user: username,
42
+ # keys: [File.expand_path('~/.ssh/id_rsa')],
43
+ # port: 22,
44
+ # }
45
+ #
46
+ # If :bundle_rsync_ssh_options are not available also, look :ssh_options finally:
47
+ #
48
+ # set :ssh_options {
49
+ # user: username,
50
+ # keys: [File.expand_path('~/.ssh/id_rsa')],
51
+ # port: 22,
52
+ # }
53
+ #
54
+ # `keys` can be a string or an array.
55
+ # NOTE: :password is not supported.
56
+ def self.build_ssh_command(host)
57
+ user_opt, key_opt, port_opt = "", "", ""
58
+ ssh_options = fetch(:bundle_rsync_ssh_options) || fetch(:ssh_options)
59
+ if user = host.user || ssh_options[:user]
60
+ user_opt = " -l #{user}"
61
+ end
62
+ if keys = (host.keys.empty? ? ssh_options[:keys] : host.keys)
63
+ keys = keys.is_a?(Array) ? keys : [keys]
64
+ key_opt = keys.map {|key| " -i #{key}" }.join("")
65
+ end
66
+ if port = host.port || ssh_options[:port]
67
+ port_opt = " -p #{port}"
68
+ end
69
+ "ssh#{user_opt}#{key_opt}#{port_opt}"
70
+ end
71
+
72
+ # Fetch the :bundle_rsync_max_parallels,
73
+ # where the default is the number of hosts
74
+ def self.max_parallels(hosts)
75
+ fetch(:bundle_rsync_max_parallels) || hosts.size
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,125 @@
1
+ unless defined?(Capistrano::BundleRsync::TASK_LOADED) # protect multiple loads
2
+ Capistrano::BundleRsync::TASK_LOADED = true
3
+ require 'fileutils'
4
+ require 'parallel'
5
+
6
+ namespace :bundle_rsync do
7
+ def config
8
+ Capistrano::BundleRsync::Config
9
+ end
10
+
11
+ namespace :bundler do
12
+ task :install do
13
+ hosts = roles(:all)
14
+ on hosts, in: :groups, limit: config.max_parallels(hosts) do
15
+ within release_path do
16
+ execute :mkdir, '-p', '.bundle'
17
+ end
18
+ end
19
+
20
+ run_locally do
21
+ Bundler.with_clean_env do
22
+ execute :bundle, "--gemfile #{config.local_release_path}/Gemfile --deployment --quiet --path #{config.local_bundle_path} --without development test --binstubs=#{config.local_bin_path}"
23
+ end
24
+
25
+ lines = <<-EOS
26
+ ---
27
+ BUNDLE_FROZEN: '1'
28
+ BUNDLE_PATH: #{shared_path.join('bundle')}
29
+ BUNDLE_WITHOUT: development:test
30
+ BUNDLE_DISABLE_SHARED_GEMS: '1'
31
+ BUNDLE_BIN: #{shared_path.join('bin')}
32
+ EOS
33
+ bundle_config_path = "#{config.local_base_path}/bundle_config"
34
+ File.open(bundle_config_path, "w") {|file| file.print(lines) }
35
+
36
+ Parallel.each(hosts, in_processes: config.max_parallels(hosts)) do |host|
37
+ ssh = config.build_ssh_command(host)
38
+ if config_files = config.config_files
39
+ config_files.each do |config_file|
40
+ basename = File.basename(config_file)
41
+ execute :rsync, "-az --delete --rsh='#{ssh}' #{config_file} #{host}:#{release_path}/config/#{basename}"
42
+ end
43
+ end
44
+
45
+ execute :rsync, "-az --delete --rsh='#{ssh}' #{config.local_bundle_path}/ #{host}:#{shared_path}/bundle/"
46
+ execute :rsync, "-az --delete --rsh='#{ssh}' #{config.local_bin_path}/ #{host}:#{shared_path}/bin/"
47
+ execute :rsync, "-az --delete --rsh='#{ssh}' #{bundle_config_path} #{host}:#{release_path}/.bundle/config"
48
+ end
49
+
50
+ FileUtils.rm_rf(config.local_release_path)
51
+ end
52
+ end
53
+ end
54
+
55
+ desc 'Check that the repository is reachable'
56
+ task :check do
57
+ fetch(:branch)
58
+ run_locally do
59
+ exit 1 unless execute("git ls-remote #{repo_url}")
60
+ execute("mkdir -p #{config.local_base_path}")
61
+ end
62
+ end
63
+
64
+ desc 'Clone the repo to the cache'
65
+ task :clone do
66
+ run_locally do
67
+ if File.exist?("#{config.local_repo_path}/HEAD")
68
+ info t(:mirror_exists, at: config.local_repo_path)
69
+ else
70
+ execute :git, :clone, '--mirror', repo_url, config.local_repo_path
71
+ end
72
+ end
73
+ end
74
+
75
+ desc 'Update the repo mirror to reflect the origin state'
76
+ task update: :'bundle_rsync:clone' do
77
+ run_locally do
78
+ within config.local_repo_path do
79
+ execute :git, :remote, :update
80
+ end
81
+ end
82
+ end
83
+
84
+ desc 'Copy repo to releases'
85
+ task create_release: :'bundle_rsync:update' do
86
+ hosts = roles(:all)
87
+ run_locally do
88
+ execute "mkdir -p #{config.local_release_path}"
89
+
90
+ within config.local_repo_path do
91
+ execute :git, :archive, fetch(:branch), '| tar -x -C', "#{config.local_release_path}"
92
+ end
93
+
94
+ Parallel.each(hosts, in_processes: config.max_parallels(hosts)) do |host|
95
+ ssh = config.build_ssh_command(host)
96
+ execute :rsync, "-az --delete --rsh='#{ssh}' #{config.local_release_path}/ #{host}:#{release_path}/"
97
+ end
98
+ end
99
+ end
100
+
101
+ desc 'Determine the revision that will be deployed'
102
+ task :set_current_revision do
103
+ run_locally do
104
+ within config.local_repo_path do
105
+ set :current_revision, capture(:git, "rev-parse --short #{fetch(:branch)}")
106
+ end
107
+ end
108
+ end
109
+
110
+ before 'deploy:updated', 'bundle_rsync:bundler:install'
111
+ end
112
+
113
+ namespace :load do
114
+ task :defaults do
115
+ set :bundle_rsync_local_base_path, nil
116
+ set :bundle_rsync_local_repo_path, nil
117
+ set :bundle_rsync_local_release_path, nil
118
+ set :bundle_rsync_local_bundle_path, nil
119
+ set :bundle_rsync_local_bin_path, nil
120
+ set :bundle_rsync_config_files, nil
121
+ set :bundle_rsync_ssh_options, nil # Default to be ssh_options. Note: :password is not supported.
122
+ set :bundle_rsync_max_parallels, nil
123
+ end
124
+ end
125
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-bundle_rsync
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - sonots
8
+ - tohae
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-07-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 3.0.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 3.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: parallel
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.3'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.3'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ description: Deploy an application and bundled gems via rsync
71
+ email:
72
+ - sonots@gmail.com
73
+ - tohaechan@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - CHANGELOG.md
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - capistrano-bundle_rsync.gemspec
85
+ - lib/capistrano-bundle_rsync.rb
86
+ - lib/capistrano/bundle_rsync.rb
87
+ - lib/capistrano/bundle_rsync/config.rb
88
+ - lib/capistrano/tasks/bundle_rsync.rake
89
+ homepage: https://github.com/sonots/capistrano-bundle_rsync
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.2.0
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Deploy an application and bundled gems via rsync.
113
+ test_files: []