capistrano-chocopoche 0.0.2 → 0.2.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.
- checksums.yaml +6 -6
- data/Gemfile +1 -1
- data/README.md +142 -109
- data/bin/csync +5 -0
- data/capistrano-chocopoche.gemspec +8 -2
- data/lib/capistrano/chocopoche.rb +5 -0
- data/lib/capistrano/chocopoche/common.rb +36 -0
- data/lib/capistrano/chocopoche/composer.rb +36 -0
- data/lib/capistrano/chocopoche/files.rb +102 -0
- data/lib/capistrano/chocopoche/mysql.rb +190 -0
- data/lib/{capistrano-chocopoche → capistrano/chocopoche}/railsless-deploy.rb +7 -24
- data/lib/capistrano/chocopoche/sync-cli.rb +67 -0
- data/lib/capistrano/chocopoche/version.rb +5 -0
- metadata +30 -10
- data/lib/capistrano-chocopoche/common.rb +0 -16
- data/lib/capistrano-chocopoche/files.rb +0 -83
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
5
|
-
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 26cfccb5e750bc7083dfdd42dfc6320d40622ef9
|
|
4
|
+
data.tar.gz: b56877aa569af52f82ee19958ee0502bb3e78abe
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bda1db522b9277ea660c14953985a1783c79f7b8551ab2659c7975466e43f9724eb46042beee6ddd06779b8957b6770d688f55d10b7013deccd11e5541b948b2
|
|
7
|
+
data.tar.gz: db3d2a905b958f5def5288136a99faf175dcfb80a423335709aa8c93243934ceb1fc3ec0e9000642731951d1be65a31ed126bf0ea07b4cea25ad5e6fd51530db
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -2,145 +2,178 @@
|
|
|
2
2
|
|
|
3
3
|
My capistrano poche contains:
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
- a files utility to rsync directories
|
|
5
|
+
- a php composer recipe
|
|
6
|
+
- a files utility to rsync directories up and down
|
|
7
|
+
- a mysql utility to dump/import, download/upload databases
|
|
8
|
+
- a bin to help synchronizing multiple stage together: `csync`
|
|
9
|
+
- and a railsless-deploy recipe (which uses the default rails recipes -
|
|
10
|
+
it may not be a good idea to reimplement...)
|
|
7
11
|
|
|
8
12
|
## Installation
|
|
9
13
|
|
|
10
14
|
$ gem install capistrano-chocopoche
|
|
11
15
|
|
|
12
|
-
##
|
|
16
|
+
## Tasks
|
|
17
|
+
|
|
18
|
+
```shell
|
|
19
|
+
cap composer # Runs an arbitrary composer command
|
|
20
|
+
cap composer:update # Runs the composer update command
|
|
21
|
+
cap connect # Connects via SSH to the first app server, and executes a `bash --login` to stay connected
|
|
22
|
+
cap deploy # Deploys your project.
|
|
23
|
+
cap deploy:check # Test deployment dependencies.
|
|
24
|
+
cap deploy:cleanup # Clean up old releases.
|
|
25
|
+
cap deploy:create_symlink # Updates the symlink to the most recently deployed version.
|
|
26
|
+
cap deploy:pending # Displays the commits since your last deploy.
|
|
27
|
+
cap deploy:pending:diff # Displays the `diff' since your last deploy.
|
|
28
|
+
cap deploy:restart # Blank task exists as a hook into which to install your own environment specific behaviour.
|
|
29
|
+
cap deploy:rollback # Rolls back to a previous version and restarts.
|
|
30
|
+
cap deploy:rollback:code # Rolls back to the previously deployed version.
|
|
31
|
+
cap deploy:setup # Prepares one or more servers for deployment.
|
|
32
|
+
cap deploy:start # Blank task exists as a hook into which to install your own environment specific behaviour.
|
|
33
|
+
cap deploy:stop # Blank task exists as a hook into which to install your own environment specific behaviour.
|
|
34
|
+
cap deploy:symlink # Deprecated API.
|
|
35
|
+
cap deploy:update # Copies your project and updates the symlink.
|
|
36
|
+
cap deploy:update_code # Copies your project to the remote servers.
|
|
37
|
+
cap deploy:upload # Copy files to the currently deployed version.
|
|
38
|
+
cap files:create_symlinks # Creates :files_symlinks from the shared folder to the current one on the app servers.
|
|
39
|
+
cap files:download # Sync files from the first web server to the local temp directory.
|
|
40
|
+
cap files:upload # Sync files from the local temp directory to the first web server.
|
|
41
|
+
cap files:upload_files_from_templates # Creates files from templates and upload them to the app server.
|
|
42
|
+
cap invoke # Invoke a single command on the remote servers.
|
|
43
|
+
cap mysql:download # Download last remote dumps of each databases.
|
|
44
|
+
cap mysql:dump # Dump databases to remote backup folder.
|
|
45
|
+
cap mysql:import # Import last remote dumps to databases.
|
|
46
|
+
cap mysql:upload # Upload last local dump of each databases.
|
|
47
|
+
cap shell # Begin an interactive Capistrano session.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Capfile example with multistage
|
|
51
|
+
|
|
52
|
+
The [short_url](https://github.com/chocopoche/short_url) project uses that
|
|
53
|
+
library, it's a good working example. See the `Capfile` and stages config under
|
|
54
|
+
`config/deploy`.
|
|
55
|
+
|
|
56
|
+
The Capfile:
|
|
13
57
|
|
|
14
58
|
```ruby
|
|
15
59
|
# Capistrao defaults
|
|
16
60
|
load 'deploy'
|
|
17
61
|
|
|
18
|
-
# Multistage - to be loaded before the railsless-deploy
|
|
19
62
|
require 'capistrano/ext/multistage'
|
|
20
|
-
|
|
21
|
-
# Rails inhibition
|
|
22
|
-
require 'capistrano-chocopoche/railsless-deploy'
|
|
23
|
-
|
|
24
|
-
# Rsync tasks
|
|
25
|
-
require 'capistrano-chocopoche/files'
|
|
63
|
+
require 'capistrano/chocopoche'
|
|
26
64
|
|
|
27
65
|
# Base configuration
|
|
28
66
|
set :application, "my-project"
|
|
29
|
-
set :repository, "git@
|
|
67
|
+
set :repository, "git@example.com:my-project.git"
|
|
30
68
|
set :use_sudo, false
|
|
31
69
|
ssh_options[:forward_agent] = true
|
|
32
70
|
|
|
33
|
-
#
|
|
34
|
-
set :
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# #
|
|
41
|
-
# set :
|
|
42
|
-
|
|
71
|
+
# Folders to rsync with files:download
|
|
72
|
+
set :files_rsync, files_rsync + %w(web/qr)
|
|
73
|
+
|
|
74
|
+
# Symlinks to create after deploy:update_code
|
|
75
|
+
set :files_symlinks, files_symlinks + %w(web/qr)
|
|
76
|
+
|
|
77
|
+
# # Won't work with the cli command `csync` because the default stage task
|
|
78
|
+
# # will be invoked, but it should not
|
|
79
|
+
# set :default_stage, 'vm'
|
|
80
|
+
|
|
81
|
+
# Files to be generated on setup
|
|
82
|
+
set :files_tpl, [
|
|
83
|
+
{
|
|
84
|
+
:template => "config/deploy/templates/nginx.conf.erb",
|
|
85
|
+
:dest => "config/nginx.conf"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
:template => "config/deploy/templates/parameters.yml.erb",
|
|
89
|
+
:dest => "config/parameters.yml"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
43
92
|
```
|
|
44
93
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
Also the last one implements the atomic symlink as suggested in
|
|
65
|
-
[issue #346](https://github.com/capistrano/capistrano/issues/346).
|
|
66
|
-
|
|
67
|
-
## Files
|
|
68
|
-
|
|
69
|
-
The `download` and `upload` tasks use a temporary directory as pivot, so you are
|
|
70
|
-
able to sync from a stage to another.
|
|
71
|
-
|
|
72
|
-
The following scenario assumes that all commands are launched from the dev stage,
|
|
73
|
-
that you have 3 environements and that `:files_directories` and `:files_symlinks`
|
|
74
|
-
are set as in the example:
|
|
75
|
-
|
|
76
|
-
- dev: may only contains the cap recipe
|
|
77
|
-
- staging: a stage without files and symlinks
|
|
78
|
-
- prod: a stage with files and symlinks. Prod looks like:
|
|
79
|
-
|
|
80
|
-
my-project.prod/
|
|
81
|
-
├── current/
|
|
82
|
-
│ └── public/
|
|
83
|
-
│ └── upload/ => symlink to my-project/shared/public/upload/
|
|
84
|
-
└── shared/
|
|
85
|
-
└── public/
|
|
86
|
-
└── upload/ => git ignores that folder
|
|
87
|
-
├── file1.png
|
|
88
|
-
├── file2.png
|
|
89
|
-
...
|
|
90
|
-
|
|
91
|
-
### Download
|
|
92
|
-
|
|
93
|
-
Download `prod:my-project/shared/public/upload` to `dev:my-project/tmp/capistrano-chocopoche/files/public/upload`:
|
|
94
|
-
|
|
95
|
-
$ cap prod files:download
|
|
96
|
-
|
|
97
|
-
Gives:
|
|
98
|
-
|
|
99
|
-
my-project.dev/
|
|
100
|
-
├── current/
|
|
101
|
-
├── shared/
|
|
102
|
-
└── tmp/
|
|
103
|
-
└── capistrano-chocopoche/
|
|
104
|
-
└── files/
|
|
105
|
-
└── public/
|
|
106
|
-
└── upload/
|
|
107
|
-
├── file1.png
|
|
108
|
-
├── file2.png
|
|
109
|
-
...
|
|
94
|
+
A stage file in `config/deploy/[stage].rb:
|
|
95
|
+
```
|
|
96
|
+
server 'example.com', :app, :web, :db, :primary => true
|
|
97
|
+
|
|
98
|
+
def set_files_tpl_params
|
|
99
|
+
set :files_tpl_params, {
|
|
100
|
+
:server => {
|
|
101
|
+
:hostname => "#{stage}.example.com"
|
|
102
|
+
},
|
|
103
|
+
:database => {
|
|
104
|
+
:driver => "pdo_mysql",
|
|
105
|
+
:dbname => "dbname",
|
|
106
|
+
:user => "user",
|
|
107
|
+
:password => "password",
|
|
108
|
+
:host => "localhost"
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
```
|
|
110
113
|
|
|
111
|
-
|
|
114
|
+
## Capfile example without multistage
|
|
112
115
|
|
|
113
|
-
|
|
116
|
+
```ruby
|
|
117
|
+
# Capistrao defaults
|
|
118
|
+
load 'deploy'
|
|
114
119
|
|
|
115
|
-
|
|
120
|
+
require 'capistrano/chocopoche'
|
|
116
121
|
|
|
117
|
-
|
|
122
|
+
# Base configuration
|
|
123
|
+
set :application, "my-project"
|
|
124
|
+
set :repository, "git@example.com:my-project.git"
|
|
125
|
+
set :use_sudo, false
|
|
126
|
+
ssh_options[:forward_agent] = true
|
|
118
127
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
# Folders to rsync with files:download
|
|
129
|
+
set :files_rsync, files_rsync + %w(web/qr)
|
|
130
|
+
|
|
131
|
+
# Symlinks to create after deploy:update_code
|
|
132
|
+
set :files_symlinks, files_symlinks + %w(web/qr)
|
|
133
|
+
|
|
134
|
+
# Files to be generated on setup
|
|
135
|
+
set :files_tpl, [
|
|
136
|
+
{
|
|
137
|
+
:template => "config/deploy/templates/nginx.conf.erb",
|
|
138
|
+
:dest => "config/nginx.conf"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
:template => "config/deploy/templates/parameters.yml.erb",
|
|
142
|
+
:dest => "config/parameters.yml"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
server 'localhost', :app, :web, :db, :primary => true
|
|
147
|
+
|
|
148
|
+
def set_files_tpl_params
|
|
149
|
+
set :files_tpl_params, {
|
|
150
|
+
:server => {
|
|
151
|
+
:hostname => "#{stage}.example.com"
|
|
152
|
+
},
|
|
153
|
+
:database => {
|
|
154
|
+
:driver => "pdo_mysql",
|
|
155
|
+
:dbname => "dbname",
|
|
156
|
+
:user => "user",
|
|
157
|
+
:password => "password",
|
|
158
|
+
:host => "localhost"
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
```
|
|
127
163
|
|
|
128
|
-
|
|
164
|
+
## csync
|
|
129
165
|
|
|
130
|
-
|
|
166
|
+
The csync will chain capistrano commands in order to synchronise two stages.
|
|
167
|
+
Example:
|
|
131
168
|
|
|
132
|
-
$
|
|
169
|
+
$ csync mysql prod dev
|
|
133
170
|
|
|
134
|
-
|
|
171
|
+
will dump and download databases from *prod*, then upload and import them to
|
|
172
|
+
*dev*.
|
|
135
173
|
|
|
136
|
-
|
|
137
|
-
├── current/
|
|
138
|
-
│ └── public/
|
|
139
|
-
│ └── upload/ => symlink to my-project/shared/public/upload/
|
|
140
|
-
└── shared/
|
|
141
|
-
└── public/
|
|
142
|
-
└── upload/ => git ignores that folder
|
|
174
|
+
$ csync files prod dev
|
|
143
175
|
|
|
176
|
+
will rsync files from *prod* to *dev*.
|
|
144
177
|
|
|
145
178
|
## License
|
|
146
179
|
|
data/bin/csync
ADDED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'capistrano/chocopoche/version'
|
|
4
5
|
|
|
5
6
|
Gem::Specification.new do |spec|
|
|
6
7
|
spec.name = "capistrano-chocopoche"
|
|
7
|
-
spec.version =
|
|
8
|
+
spec.version = Capistrano::Chocopoche::VERSION
|
|
8
9
|
spec.authors = ["Corentin Merot"]
|
|
9
10
|
spec.email = ["cmerot@themarqueeblink.com"]
|
|
10
|
-
spec.description = %q{Capistrano recipes
|
|
11
|
+
spec.description = %q{Capistrano recipes and bin for mysql, rsync, php composer.}
|
|
11
12
|
spec.summary = %q{Chocopoche's Capistrano recipes}
|
|
12
13
|
spec.homepage = "https://github.com/chocopoche/capistrano-chocopoche"
|
|
13
14
|
spec.license = "MIT"
|
|
15
|
+
|
|
14
16
|
spec.files = `git ls-files`.split($/)
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
15
19
|
spec.require_paths = ["lib"]
|
|
16
20
|
|
|
21
|
+
spec.add_runtime_dependency "capistrano", "~> 2.14"
|
|
22
|
+
|
|
17
23
|
spec.add_development_dependency "bundler", "~> 1.3"
|
|
18
24
|
end
|
|
19
25
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
|
2
|
+
Capistrano::Configuration.instance(:must_exist) :
|
|
3
|
+
Capistrano.configuration(:must_exist)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
configuration.load do
|
|
7
|
+
|
|
8
|
+
_cset :user, Etc.getlogin
|
|
9
|
+
|
|
10
|
+
# Used to create relative symlinks in deploy.create_symlink
|
|
11
|
+
def relative_path(from_str, to_str)
|
|
12
|
+
require 'pathname'
|
|
13
|
+
Pathname.new(to_str).relative_path_from(Pathname.new(from_str)).to_s
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# https://github.com/everzet/capifony/blob/c32d2ae118584d37e9051b6eeda0674ea420f824/lib/capifony.rb
|
|
17
|
+
def prompt_with_default(var, default, &block)
|
|
18
|
+
set(var) do
|
|
19
|
+
Capistrano::CLI.ui.ask("#{var} [#{default}] : ", &block)
|
|
20
|
+
end
|
|
21
|
+
set var, default if eval("#{var.to_s}.empty?")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc <<-DESC
|
|
25
|
+
Connects via SSH to the first app server, and executes a `bash --login` \
|
|
26
|
+
to stay connected
|
|
27
|
+
DESC
|
|
28
|
+
task :connect, :roles => :app, :primary => true do
|
|
29
|
+
set :host, roles[:app].servers.first.host
|
|
30
|
+
set :port, ssh_options[:port] || roles[:web].servers.first.port || 22
|
|
31
|
+
set :user, Etc.getlogin unless exists?(:user)
|
|
32
|
+
|
|
33
|
+
cmd = "ssh -A #{user}@#{host} -p #{port} -t \"cd #{current_path};bash --login\""
|
|
34
|
+
exec(cmd)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'capistrano/chocopoche/files'
|
|
2
|
+
|
|
3
|
+
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
|
4
|
+
Capistrano::Configuration.instance(:must_exist) :
|
|
5
|
+
Capistrano.configuration(:must_exist)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
configuration.load do
|
|
9
|
+
|
|
10
|
+
set :shared_children, shared_children + %w(vendor)
|
|
11
|
+
set :files_symlinks, files_symlinks + %w(vendor)
|
|
12
|
+
|
|
13
|
+
_cset :composer_cli_options, '--dev --quiet'
|
|
14
|
+
|
|
15
|
+
namespace :composer do
|
|
16
|
+
|
|
17
|
+
desc "Runs an arbitrary composer command"
|
|
18
|
+
task :default, :roles => :app do
|
|
19
|
+
prompt_with_default(:composer_task, "update")
|
|
20
|
+
run "cd #{latest_release} && php composer.phar #{composer_cli_options} " + composer_task
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc "Runs the composer update command"
|
|
24
|
+
task :update, :roles => :app do
|
|
25
|
+
install_composer
|
|
26
|
+
run "cd #{latest_release} && php composer.phar #{composer_cli_options} update"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
desc "[internal] Installs composer"
|
|
30
|
+
task :install_composer, :roles => :app do
|
|
31
|
+
run "curl -s http://getcomposer.org/installer | php -- --install-dir=#{current_release}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# before 'deploy:finalize_update', 'composer:update'
|
|
36
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# see https://gist.github.com/111597
|
|
2
|
+
require 'etc'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'capistrano/chocopoche/common'
|
|
5
|
+
|
|
6
|
+
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
|
7
|
+
Capistrano::Configuration.instance(:must_exist) :
|
|
8
|
+
Capistrano.configuration(:must_exist)
|
|
9
|
+
|
|
10
|
+
configuration.load do
|
|
11
|
+
|
|
12
|
+
_cset :user, Etc.getlogin
|
|
13
|
+
_cset :files_rsync, []
|
|
14
|
+
_cset :files_symlinks, []
|
|
15
|
+
_cset :files_tmp_dir, 'tmp/capistrano-chocopoche/files'
|
|
16
|
+
_cset :files_tpl, []
|
|
17
|
+
_cset :files_tpl_params, {}
|
|
18
|
+
|
|
19
|
+
namespace :files do
|
|
20
|
+
|
|
21
|
+
task :set_tpl_symlinks do
|
|
22
|
+
files_tpl.each do |t|
|
|
23
|
+
set :files_symlinks, files_symlinks + [t[:dest]]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc "Creates files from templates and upload them to the app server."
|
|
28
|
+
task :upload_files_from_templates, :roles => :app do
|
|
29
|
+
|
|
30
|
+
server 'localhost', :app, :web, :db, :primary => true
|
|
31
|
+
|
|
32
|
+
set_files_tpl_params
|
|
33
|
+
|
|
34
|
+
files_tpl.each do |t|
|
|
35
|
+
params = fetch(:files_tpl_params)
|
|
36
|
+
template = File.read(t[:template])
|
|
37
|
+
buffer = ERB.new(template).result(binding)
|
|
38
|
+
parent = File.dirname("#{shared_path}/#{t[:dest]}")
|
|
39
|
+
run "mkdir -p #{parent}"
|
|
40
|
+
put buffer, "#{shared_path}/#{t[:dest]}", :mode => 0664
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc <<-DESC
|
|
45
|
+
Sync files from the first web server to the local temp directory. \
|
|
46
|
+
Files on the remote server must be somewhere in the shared directory.
|
|
47
|
+
DESC
|
|
48
|
+
task :download, :roles => :web, :only => { :primary => true }, :once => true do
|
|
49
|
+
|
|
50
|
+
host, port = host_and_port
|
|
51
|
+
|
|
52
|
+
# Sync each directory
|
|
53
|
+
files_rsync.each do |file_dir|
|
|
54
|
+
source = "#{user}@#{host}:#{shared_path}/#{file_dir}"
|
|
55
|
+
dest = File.dirname("#{files_tmp_dir}/#{file_dir}")
|
|
56
|
+
FileUtils.mkdir_p(dest)
|
|
57
|
+
system "rsync --archive --compress --copy-links --delete --stats --rsh='ssh -p #{port}' #{source} #{dest}"
|
|
58
|
+
logger.info "sync files from #{host}:#{source} to #{dest} finished"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
desc <<-DESC
|
|
64
|
+
Sync files from the local temp directory to the first web server. \
|
|
65
|
+
Files on the remote server will be copied in the shared directory.
|
|
66
|
+
DESC
|
|
67
|
+
task :upload, :roles => :web, :only => { :primary => true }, :once => true do
|
|
68
|
+
host, port = host_and_port
|
|
69
|
+
files_rsync.each do |file_dir|
|
|
70
|
+
source = "#{files_tmp_dir}/#{file_dir}"
|
|
71
|
+
dest = "#{user}@#{host}:" + File.dirname("#{shared_path}/#{file_dir}")
|
|
72
|
+
system "rsync --archive --compress --keep-dirlinks --delete --stats --rsh='ssh -p #{port}' #{source} #{dest}"
|
|
73
|
+
logger.info "sync files from #{source} to #{host}:#{dest} finished"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
desc <<-DESC
|
|
78
|
+
Creates :files_symlinks from the shared folder to the current one on the \
|
|
79
|
+
app servers. If a file or directory exists as the linkname, it will be \
|
|
80
|
+
removed.
|
|
81
|
+
DESC
|
|
82
|
+
task :create_symlinks, :roles => :app do
|
|
83
|
+
cmds = files_symlinks.collect do | l |
|
|
84
|
+
parent = File.dirname("#{latest_release}/#{l}")
|
|
85
|
+
"mkdir -p #{parent} && rm -rf #{latest_release}/#{l} && ln -nfs #{shared_path}/#{l} #{latest_release}/#{l}"
|
|
86
|
+
end
|
|
87
|
+
run cmds.join(' && ')
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
#
|
|
91
|
+
# Returns the actual host name to sync and port
|
|
92
|
+
#
|
|
93
|
+
def host_and_port
|
|
94
|
+
return roles[:web].servers.first.host, ssh_options[:port] || roles[:web].servers.first.port || 22
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
before 'deploy:finalize_update', 'files:create_symlinks'
|
|
100
|
+
before 'files:create_symlinks', 'files:set_tpl_symlinks'
|
|
101
|
+
after 'deploy:setup', 'files:upload_files_from_templates'
|
|
102
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# see https://gist.github.com/111597
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
# Converts deeply keys of a hash|array into symbols when they are strings
|
|
6
|
+
# @see http://stackoverflow.com/questions/800122/best-way-to-convert-strings-to-symbols-in-hash#answer-15815545
|
|
7
|
+
class Object
|
|
8
|
+
def deep_symbolize_keys
|
|
9
|
+
return self.inject({}){|memo,(k,v)| memo[k.to_sym] = v.deep_symbolize_keys; memo} if self.is_a? Hash
|
|
10
|
+
return self.inject([]){|memo,v | memo << v.deep_symbolize_keys; memo} if self.is_a? Array
|
|
11
|
+
return self
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
|
16
|
+
Capistrano::Configuration.instance(:must_exist) :
|
|
17
|
+
Capistrano.configuration(:must_exist)
|
|
18
|
+
|
|
19
|
+
configuration.load do
|
|
20
|
+
|
|
21
|
+
_cset :mysql_backup_dir, "backup/mysql"
|
|
22
|
+
_cset :mysql_config_file, "config/parameters.yml"
|
|
23
|
+
_cset :mysql_yaml_key, :databases
|
|
24
|
+
|
|
25
|
+
namespace :mysql do
|
|
26
|
+
|
|
27
|
+
desc "Dump databases to remote backup folder."
|
|
28
|
+
task :dump, :roles => :db, :only => { :primary => true }, :once => true do
|
|
29
|
+
fetch_databases.each do |db,config|
|
|
30
|
+
db_backup_dir = "#{deploy_to}/#{mysql_backup_dir}/#{db}"
|
|
31
|
+
run "mkdir -p #{db_backup_dir}"
|
|
32
|
+
|
|
33
|
+
if exists? :stages
|
|
34
|
+
dump_filename = "%s/%s-%s-%d.sql" % [
|
|
35
|
+
db_backup_dir,
|
|
36
|
+
fetch(:stage),
|
|
37
|
+
config[:dbname],
|
|
38
|
+
Time.now.to_i
|
|
39
|
+
]
|
|
40
|
+
else
|
|
41
|
+
dump_filename = "%s/%s-%d.sql" % [
|
|
42
|
+
db_backup_dir,
|
|
43
|
+
config[:dbname],
|
|
44
|
+
Time.now.to_i
|
|
45
|
+
]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Dumps the schema
|
|
49
|
+
cmd_schema = "mysqldump -h %s --default-character-set=utf8 --no-data -u%s -p %s > %s" % [
|
|
50
|
+
config[:host],
|
|
51
|
+
config[:user],
|
|
52
|
+
config[:dbname],
|
|
53
|
+
dump_filename
|
|
54
|
+
]
|
|
55
|
+
begin
|
|
56
|
+
run cmd_schema do |ch, stream, out|
|
|
57
|
+
ch.send_data "#{config[:password]}\n" if out =~ /^Enter password:/
|
|
58
|
+
end
|
|
59
|
+
rescue Capistrano::CommandError => e
|
|
60
|
+
abort("Connection error, you may want to check database config.")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Tables to ignore (cache, indexes, ...)
|
|
64
|
+
ignore_tables = ""
|
|
65
|
+
if config.has_key?(:capistrano) && config[:capistrano].has_key?(:ignore_tables)
|
|
66
|
+
# Retrieve tables to ignore and generate the mysqldump arguments
|
|
67
|
+
cmd_ignore_tables = "mysql -h %s --default-character-set=utf8 -u%s -p %s" % [
|
|
68
|
+
config[:host],
|
|
69
|
+
config[:user],
|
|
70
|
+
config[:dbname]
|
|
71
|
+
]
|
|
72
|
+
cmd_ignore_tables += " -BNe 'show tables;'"
|
|
73
|
+
cmd_ignore_tables += " | grep -E '^#{config[:capistrano][:ignore_tables]}$'"
|
|
74
|
+
cmd_ignore_tables += " | xargs -I {} echo --ignore-table #{config[:dbname]}.{} "
|
|
75
|
+
|
|
76
|
+
run cmd_ignore_tables do |ch, stream, out|
|
|
77
|
+
if out =~ /^Enter password:/
|
|
78
|
+
ch.send_data "#{config[:password]}\n"
|
|
79
|
+
else
|
|
80
|
+
ignore_tables += " " + out.chop if out.match(/ignore-table/)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Dumps the data
|
|
86
|
+
cmd_data = "mysqldump -h %s --default-character-set=utf8 -u%s -p %s %s >> %s" % [
|
|
87
|
+
config[:host],
|
|
88
|
+
config[:user],
|
|
89
|
+
ignore_tables,
|
|
90
|
+
config[:dbname],
|
|
91
|
+
dump_filename
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
# Executes sql
|
|
95
|
+
run cmd_data do |ch, stream, out|
|
|
96
|
+
ch.send_data "#{config[:password]}\n" if out =~ /^Enter password:/
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Compress dump
|
|
100
|
+
run "bzip2 #{dump_filename}"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
desc "Import last remote dumps to databases."
|
|
105
|
+
task :import, :roles => :db, :only => { :primary => true }, :once => true do
|
|
106
|
+
fetch_databases.each do |db,config|
|
|
107
|
+
remote_db_backup_dir = "#{deploy_to}/#{mysql_backup_dir}/#{db}"
|
|
108
|
+
last_dump = capture("ls -xt #{remote_db_backup_dir}").split.reverse.last
|
|
109
|
+
|
|
110
|
+
# cmd = "mysql -u%s -p\"%s\" %s < %s/%s" % [
|
|
111
|
+
# config[:user],
|
|
112
|
+
# config[:password],
|
|
113
|
+
# config[:dbname],
|
|
114
|
+
# remote_db_backup_dir,
|
|
115
|
+
# last_dump
|
|
116
|
+
# ]
|
|
117
|
+
# run cmd do |ch, stream, out|
|
|
118
|
+
# ch.send_data "#{config[:password]}\n" if out =~ /^Enter password:/
|
|
119
|
+
# end
|
|
120
|
+
|
|
121
|
+
run "bzcat #{remote_db_backup_dir}/#{last_dump} | mysql -u%s -p\"%s\" %s" % [
|
|
122
|
+
config[:user],
|
|
123
|
+
config[:password],
|
|
124
|
+
config[:dbname]
|
|
125
|
+
]
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
desc "Download last remote dumps of each databases."
|
|
130
|
+
task :download, :roles => :db, :only => { :primary => true }, :once => true do
|
|
131
|
+
fetch_databases.each do |db,config|
|
|
132
|
+
local_db_backup_dir = "#{mysql_backup_dir}/#{db}"
|
|
133
|
+
remote_db_backup_dir = "#{deploy_to}/#{mysql_backup_dir}/#{db}"
|
|
134
|
+
|
|
135
|
+
# Don't know how to avoid the command error if the remote_db_backup_dir
|
|
136
|
+
# does not exist, other than this way
|
|
137
|
+
begin
|
|
138
|
+
dumps = capture("test -d #{remote_db_backup_dir} && ls -xt #{remote_db_backup_dir}").split.reverse
|
|
139
|
+
rescue Capistrano::CommandError
|
|
140
|
+
logger.important "No dump found!"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
if dumps
|
|
144
|
+
FileUtils.mkdir_p(local_db_backup_dir)
|
|
145
|
+
hostname = capture("hostname -f").chop
|
|
146
|
+
file_name = "#{local_db_backup_dir}/#{hostname}-#{dumps.last}"
|
|
147
|
+
top.get("#{remote_db_backup_dir}/#{dumps.last}", file_name)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
desc "Upload last local dump of each databases."
|
|
153
|
+
task :upload, :roles => :db, :only => { :primary => true }, :once => true do
|
|
154
|
+
|
|
155
|
+
databases = fetch_databases
|
|
156
|
+
|
|
157
|
+
databases.each do |db,config|
|
|
158
|
+
|
|
159
|
+
local_db_backup_dir = "#{mysql_backup_dir}/#{db}"
|
|
160
|
+
remote_db_backup_dir = "#{deploy_to}/#{mysql_backup_dir}/#{db}"
|
|
161
|
+
|
|
162
|
+
if File.directory?(local_db_backup_dir) && last_dump = `ls -xt #{local_db_backup_dir}`.split.reverse.last
|
|
163
|
+
run "mkdir -p #{remote_db_backup_dir}"
|
|
164
|
+
top.upload("#{local_db_backup_dir}/#{last_dump}", "#{remote_db_backup_dir}/#{last_dump}")
|
|
165
|
+
logger.info "#{last_dump} uploaded."
|
|
166
|
+
else
|
|
167
|
+
logger.important 'No dump found!'
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
desc "[internal] Parses the config/databases.yml and returns compatible ones."
|
|
173
|
+
task :fetch_databases, :roles => :db, :only => { :primary => true }, :once => true do
|
|
174
|
+
location = "#{latest_release}/#{mysql_config_file}"
|
|
175
|
+
|
|
176
|
+
FileUtils.mkdir_p("config/deploy/tmp")
|
|
177
|
+
top.get(location, "config/deploy/tmp/parameters.yml")
|
|
178
|
+
config = YAML.load_file('config/deploy/tmp/parameters.yml').deep_symbolize_keys
|
|
179
|
+
FileUtils.rm("config/deploy/tmp/parameters.yml")
|
|
180
|
+
|
|
181
|
+
databases = config[mysql_yaml_key]
|
|
182
|
+
abort("No database found in #{mysql_config_file}") if databases.nil? || databases.length < 1
|
|
183
|
+
databases.delete_if { |key,value| value[:driver] != 'pdo_mysql' }
|
|
184
|
+
abort("No compatible database found in #{mysql_config_file}") if databases.length < 1
|
|
185
|
+
|
|
186
|
+
databases
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require 'capistrano-chocopoche/common'
|
|
1
|
+
require 'capistrano/chocopoche/common'
|
|
3
2
|
|
|
4
3
|
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
|
5
4
|
Capistrano::Configuration.instance(:must_exist) :
|
|
@@ -9,9 +8,9 @@ configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
|
|
9
8
|
configuration.load do
|
|
10
9
|
|
|
11
10
|
# Remove rails specific tasks
|
|
11
|
+
deploy.tasks.delete(:cold)
|
|
12
12
|
deploy.tasks.delete(:migrate)
|
|
13
13
|
deploy.tasks.delete(:migrations)
|
|
14
|
-
deploy.tasks.delete(:cold)
|
|
15
14
|
|
|
16
15
|
# Remove rails specific vars
|
|
17
16
|
unset :rails_env
|
|
@@ -26,9 +25,6 @@ configuration.load do
|
|
|
26
25
|
set(:deploy_to) { "/home/#{user}/apps/#{application}" }
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
# Remove rails specific shared children
|
|
30
|
-
# set :shared_children, []
|
|
31
|
-
|
|
32
28
|
namespace :deploy do
|
|
33
29
|
|
|
34
30
|
desc <<-DESC
|
|
@@ -44,34 +40,21 @@ configuration.load do
|
|
|
44
40
|
on_rollback do
|
|
45
41
|
if previous_release
|
|
46
42
|
previous_release_relative = relative_path(deploy_to, previous_release)
|
|
47
|
-
run "ln -
|
|
43
|
+
run "ln -nfs #{previous_release_relative} #{current_path}"
|
|
48
44
|
else
|
|
49
45
|
logger.important "no previous release to rollback to, rollback of symlink skipped"
|
|
50
46
|
end
|
|
51
47
|
end
|
|
52
48
|
latest_release_relative = relative_path(deploy_to,latest_release)
|
|
53
|
-
run "ln -
|
|
49
|
+
run "ln -nfs #{latest_release_relative} #{current_path}"
|
|
54
50
|
end
|
|
55
51
|
|
|
56
52
|
desc <<-DESC
|
|
57
|
-
[internal]
|
|
58
|
-
|
|
59
|
-
so if you are deploying something else, you may want to override this \
|
|
60
|
-
task with your own environment's requirements.
|
|
61
|
-
|
|
62
|
-
This task will make the release group-writable (if the :group_writable \
|
|
63
|
-
variable is set to true, which is the default). It will then set up \
|
|
64
|
-
symlinks to the shared directory for the log, system, and tmp/pids \
|
|
65
|
-
directories, and will lastly touch all assets in public/images, \
|
|
66
|
-
public/stylesheets, and public/javascripts so that the times are \
|
|
67
|
-
consistent (so that asset timestamping works). This touch process \
|
|
68
|
-
is only carried out if the :normalize_asset_timestamps variable is \
|
|
69
|
-
set to true, which is the default The asset directories can be overridden \
|
|
70
|
-
using the :public_children variable.
|
|
53
|
+
[internal] This is called by update_code after the basic deploy \
|
|
54
|
+
finishes.
|
|
71
55
|
DESC
|
|
72
56
|
task :finalize_update, :except => { :no_release => true } do
|
|
73
57
|
end
|
|
74
|
-
|
|
75
58
|
end
|
|
76
59
|
|
|
77
60
|
namespace :rollback do
|
|
@@ -83,7 +66,7 @@ configuration.load do
|
|
|
83
66
|
task :revision, :except => { :no_release => true } do
|
|
84
67
|
if previous_release
|
|
85
68
|
previous_release_relative = relative_path(deploy_to, previous_release)
|
|
86
|
-
run "ln -
|
|
69
|
+
run "ln -nfs #{previous_release_relative} #{current_path}"
|
|
87
70
|
else
|
|
88
71
|
abort "could not rollback the code because there is no prior release"
|
|
89
72
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'capistrano/cli'
|
|
2
|
+
|
|
3
|
+
module Capistrano
|
|
4
|
+
module Chocopoche
|
|
5
|
+
class SyncCLI
|
|
6
|
+
def prompt(default, *args)
|
|
7
|
+
print(*args)
|
|
8
|
+
result = STDIN.gets.strip
|
|
9
|
+
return result.empty? ? default : result
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def ensure_stages
|
|
13
|
+
show_error("The DATATYPE is missing.") if @args[0].nil?
|
|
14
|
+
show_error("The DATATYPE is incorrect.") unless @args[0] =~ /^files|mysql$/
|
|
15
|
+
show_error("The SOURCE is missing.") if @args[1].nil?
|
|
16
|
+
show_error("The DEST is missing.") if @args[2].nil?
|
|
17
|
+
@data = @args[0]
|
|
18
|
+
@source = @args[1]
|
|
19
|
+
@dest = @args[2]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def ensure_confirmation
|
|
23
|
+
unless @options[:no_confirmation] == false
|
|
24
|
+
confirm = prompt('y', "Sync from #{@source} to #{@dest}? [Y/n] ").downcase
|
|
25
|
+
unless confirm == "y"
|
|
26
|
+
abort("Cancelled")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def show_error(msg)
|
|
32
|
+
puts @parser.help
|
|
33
|
+
abort("\n[ERROR] #{msg}")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def initialize(args)
|
|
37
|
+
@args = args
|
|
38
|
+
@options = {}
|
|
39
|
+
@parser = OptionParser.new do |opts|
|
|
40
|
+
opts.banner = "Usage: files-sync [options] DATATYPE SOURCE DEST \n"
|
|
41
|
+
opts.banner += "Sync DATATYPE from the SOURCE stage to the DEST stage.\n"
|
|
42
|
+
opts.on("-y", "--no-confirmation", "Don't prompt for confirmation") do |v|
|
|
43
|
+
@options[:no_confirmation] = v
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
opts.on("--no-backup", "Dont backup databases before importing") do |v|
|
|
47
|
+
@options[:no_backup] = v
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def execute
|
|
53
|
+
@parser.parse!
|
|
54
|
+
ensure_stages
|
|
55
|
+
ensure_confirmation
|
|
56
|
+
if @data == 'mysql'
|
|
57
|
+
Capistrano::CLI.parse([@dest, "mysql:dump"]).execute! unless @options[:no_backup]
|
|
58
|
+
Capistrano::CLI.parse([@source, "mysql:dump", "mysql:download"]).execute!
|
|
59
|
+
Capistrano::CLI.parse([@dest, "mysql:upload", "mysql:import"]).execute!
|
|
60
|
+
elsif @data == 'files'
|
|
61
|
+
Capistrano::CLI.parse([@source, "files:download"]).execute!
|
|
62
|
+
Capistrano::CLI.parse([@dest, "files:upload"]).execute!
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: capistrano-chocopoche
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Corentin Merot
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2013-04-
|
|
11
|
+
date: 2013-04-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: capistrano
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.14'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.14'
|
|
13
27
|
- !ruby/object:Gem::Dependency
|
|
14
28
|
name: bundler
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -24,10 +38,11 @@ dependencies:
|
|
|
24
38
|
- - ~>
|
|
25
39
|
- !ruby/object:Gem::Version
|
|
26
40
|
version: '1.3'
|
|
27
|
-
description: Capistrano recipes
|
|
41
|
+
description: Capistrano recipes and bin for mysql, rsync, php composer.
|
|
28
42
|
email:
|
|
29
43
|
- cmerot@themarqueeblink.com
|
|
30
|
-
executables:
|
|
44
|
+
executables:
|
|
45
|
+
- csync
|
|
31
46
|
extensions: []
|
|
32
47
|
extra_rdoc_files: []
|
|
33
48
|
files:
|
|
@@ -35,10 +50,16 @@ files:
|
|
|
35
50
|
- Gemfile
|
|
36
51
|
- LICENSE.txt
|
|
37
52
|
- README.md
|
|
53
|
+
- bin/csync
|
|
38
54
|
- capistrano-chocopoche.gemspec
|
|
39
|
-
- lib/capistrano
|
|
40
|
-
- lib/capistrano
|
|
41
|
-
- lib/capistrano
|
|
55
|
+
- lib/capistrano/chocopoche.rb
|
|
56
|
+
- lib/capistrano/chocopoche/common.rb
|
|
57
|
+
- lib/capistrano/chocopoche/composer.rb
|
|
58
|
+
- lib/capistrano/chocopoche/files.rb
|
|
59
|
+
- lib/capistrano/chocopoche/mysql.rb
|
|
60
|
+
- lib/capistrano/chocopoche/railsless-deploy.rb
|
|
61
|
+
- lib/capistrano/chocopoche/sync-cli.rb
|
|
62
|
+
- lib/capistrano/chocopoche/version.rb
|
|
42
63
|
homepage: https://github.com/chocopoche/capistrano-chocopoche
|
|
43
64
|
licenses:
|
|
44
65
|
- MIT
|
|
@@ -49,12 +70,12 @@ require_paths:
|
|
|
49
70
|
- lib
|
|
50
71
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
72
|
requirements:
|
|
52
|
-
- -
|
|
73
|
+
- - '>='
|
|
53
74
|
- !ruby/object:Gem::Version
|
|
54
75
|
version: '0'
|
|
55
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
77
|
requirements:
|
|
57
|
-
- -
|
|
78
|
+
- - '>='
|
|
58
79
|
- !ruby/object:Gem::Version
|
|
59
80
|
version: '0'
|
|
60
81
|
requirements: []
|
|
@@ -64,4 +85,3 @@ signing_key:
|
|
|
64
85
|
specification_version: 4
|
|
65
86
|
summary: Chocopoche's Capistrano recipes
|
|
66
87
|
test_files: []
|
|
67
|
-
has_rdoc:
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
|
2
|
-
Capistrano::Configuration.instance(:must_exist) :
|
|
3
|
-
Capistrano.configuration(:must_exist)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
configuration.load do
|
|
7
|
-
|
|
8
|
-
_cset :user, Etc.getlogin
|
|
9
|
-
|
|
10
|
-
# Used to create relative symlinks in deploy.create_symlink
|
|
11
|
-
def relative_path(from_str, to_str)
|
|
12
|
-
require 'pathname'
|
|
13
|
-
Pathname.new(to_str).relative_path_from(Pathname.new(from_str)).to_s
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
end
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# Capistrano recipe to rsync files up and down.
|
|
2
|
-
#
|
|
3
|
-
# author: Corentin Merot
|
|
4
|
-
# real author: Michael Kessler aka netzpirat, see https://gist.github.com/111597
|
|
5
|
-
|
|
6
|
-
require 'fileutils'
|
|
7
|
-
require 'capistrano-chocopoche/common'
|
|
8
|
-
|
|
9
|
-
configuration = Capistrano::Configuration.respond_to?(:instance) ?
|
|
10
|
-
Capistrano::Configuration.instance(:must_exist) :
|
|
11
|
-
Capistrano.configuration(:must_exist)
|
|
12
|
-
|
|
13
|
-
configuration.load do
|
|
14
|
-
|
|
15
|
-
_cset :user, Etc.getlogin
|
|
16
|
-
_cset :files_directories, []
|
|
17
|
-
_cset :files_tmp_dir, 'tmp/capistrano-chocopoche/files'
|
|
18
|
-
|
|
19
|
-
namespace :files do
|
|
20
|
-
|
|
21
|
-
desc <<-DESC
|
|
22
|
-
Sync files from the first web server to the local temp directory. \
|
|
23
|
-
Files on the remote server must be somewhere in the shared directory.
|
|
24
|
-
DESC
|
|
25
|
-
task :download, :roles => :web, :only => { :primary => true }, :once => true do
|
|
26
|
-
|
|
27
|
-
host, port = host_and_port
|
|
28
|
-
|
|
29
|
-
Array(fetch(:files_directories, [])).each do |file_dir|
|
|
30
|
-
unless File.directory? "#{files_tmp_dir}/#{file_dir}"
|
|
31
|
-
logger.info "create temporary '#{files_tmp_dir}/#{file_dir}' folder"
|
|
32
|
-
FileUtils.mkdir_p "#{files_tmp_dir}/#{file_dir}"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
source = "#{shared_path}/#{file_dir}"
|
|
36
|
-
dest = File.dirname("#{files_tmp_dir}/#{file_dir}")
|
|
37
|
-
|
|
38
|
-
# Sync directory down
|
|
39
|
-
system "rsync --verbose --archive --compress --copy-links --delete --stats --rsh='ssh -p #{port}' #{user}@#{host}:#{source} #{dest}"
|
|
40
|
-
logger.info "sync files from #{host}:#{source} to #{dest} finished"
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
desc <<-DESC
|
|
46
|
-
Sync files from the local temp directory to the first web server. \
|
|
47
|
-
Files on the remote server will be copied in the shared directory.
|
|
48
|
-
DESC
|
|
49
|
-
task :upload, :roles => :web, :only => { :primary => true }, :once => true do
|
|
50
|
-
|
|
51
|
-
host, port = host_and_port
|
|
52
|
-
Array(fetch(:files_directories, [])).each do |file_dir|
|
|
53
|
-
source = "#{files_tmp_dir}/#{file_dir}"
|
|
54
|
-
dest = File.dirname("#{shared_path}/#{file_dir}")
|
|
55
|
-
|
|
56
|
-
# Sync directory up
|
|
57
|
-
system "rsync --verbose --archive --compress --keep-dirlinks --delete --stats --rsh='ssh -p #{port}' #{source} #{user}@#{host}:#{dest}"
|
|
58
|
-
logger.info "sync files from #{source} to #{host}:#{dest} finished"
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
desc <<-DESC
|
|
63
|
-
Creates :files_symlinks from the shared folder to the current one on the \
|
|
64
|
-
web servers
|
|
65
|
-
DESC
|
|
66
|
-
task :create_symlinks, :roles => [:web] do
|
|
67
|
-
symlinks = fetch(:files_symlinks)
|
|
68
|
-
cmds = symlinks.collect do | l |
|
|
69
|
-
parent = File.dirname("#{current_path}/#{l}")
|
|
70
|
-
"mkdir -p #{parent} && ln -fs #{shared_path}/#{l} #{current_path}/#{l}"
|
|
71
|
-
end
|
|
72
|
-
run cmds.join(' && ')
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
#
|
|
76
|
-
# Returns the actual host name to sync and port
|
|
77
|
-
#
|
|
78
|
-
def host_and_port
|
|
79
|
-
return roles[:web].servers.first.host, ssh_options[:port] || roles[:web].servers.first.port || 22
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
end
|
|
83
|
-
end
|