capistrano-file-transfer-ext 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
data/README.md
CHANGED
@@ -64,7 +64,7 @@ All of the options of `upload` are sensible. In addition, there are some extra o
|
|
64
64
|
* `:install` It must be either `:always` (the default), or `:if_modified`. If `:if_modified` is given, install the file only if the checksums are different.
|
65
65
|
* `:digest` This is a symbol indicating which algorithm should be used to calculate the checksum of files. `:md5` is default.
|
66
66
|
* `:digest_cmd` The command to calculate checksum of files. `md5sum` is default.
|
67
|
-
* `:
|
67
|
+
* `:run_method` specify the method to run commands. `:run` by default. you may need to set this value as `:sudo` if you want to overwrite system files.
|
68
68
|
|
69
69
|
|
70
70
|
### `safe_put`
|
@@ -115,11 +115,11 @@ The direction of transfer. `:up` or `:down` is sensible.
|
|
115
115
|
|
116
116
|
**from**
|
117
117
|
|
118
|
-
|
118
|
+
Thie may be either a String, or an IO object (e.g. an open file handle, or a StringIO instance).
|
119
119
|
|
120
120
|
**to**
|
121
121
|
|
122
|
-
|
122
|
+
This must be a string indicating the path on the remote server that should be uploaded to.
|
123
123
|
|
124
124
|
**options**
|
125
125
|
|
@@ -139,24 +139,24 @@ All of the options of `transfer` are sensible. In addition, there are some extra
|
|
139
139
|
|
140
140
|
Capistrano::Configuration::Actions::FileTransferExt
|
141
141
|
|
142
|
-
Install files on remote servers. This method acts
|
142
|
+
Install files on remote servers. This method acts like `mv`, but with little enhancements.
|
143
143
|
|
144
144
|
#### Arguments
|
145
145
|
|
146
146
|
**from**
|
147
147
|
|
148
|
-
|
148
|
+
This must be a string indicating the path on the remote server that should be installed from.
|
149
149
|
|
150
150
|
**to**
|
151
151
|
|
152
|
-
|
152
|
+
This must be a string indicating the path on the remote server that should be installed to.
|
153
153
|
|
154
154
|
**options**
|
155
155
|
|
156
156
|
* `:via` specify the method to run commands. `:run` by default. you may need to set this value as `:sudo` if you want to overwrite system files.
|
157
|
-
* `:mode` The mode of destination file. If
|
158
|
-
* `:owner` The owner of destination file. If
|
159
|
-
* `:group` The group of destination file. If
|
157
|
+
* `:mode` The mode of destination file. If `:preserve` is given, preserve original mode of `to`.
|
158
|
+
* `:owner` The owner of destination file. If `:preserve` is given and `:via` is `:sudo`, preserve original owner of `to`.
|
159
|
+
* `:group` The group of destination file. If `:preserve` is given and `:via` is `:sudo`, preserve original group of `to`.
|
160
160
|
|
161
161
|
|
162
162
|
### `install_if_modified`
|
@@ -176,18 +176,18 @@ Install files on remote servers only if they are different.
|
|
176
176
|
|
177
177
|
**from**
|
178
178
|
|
179
|
-
|
179
|
+
This must be a string indicating the path on the remote server that should be installed from.
|
180
180
|
|
181
181
|
**to**
|
182
182
|
|
183
|
-
|
183
|
+
This must be a string indicating the path on the remote server that should be installed to.
|
184
184
|
|
185
185
|
**options**
|
186
186
|
|
187
187
|
* `:via` specify the method to run commands. `:run` by default. you may need to set this value as `:sudo` if you want to overwrite system files.
|
188
188
|
* `:mode` The mode of destination file. If not given, preserve original mode of `to`.
|
189
|
-
* `:owner` The owner of destination file. If not given and `:via` is `:sudo`, preserve original
|
190
|
-
* `:group` The group of destination file. If not given and `:via` is `:sudo`, preserve original
|
189
|
+
* `:owner` The owner of destination file. If not given and `:via` is `:sudo`, preserve original owner of `to`.
|
190
|
+
* `:group` The group of destination file. If not given and `:via` is `:sudo`, preserve original group of `to`.
|
191
191
|
* `:digest` This is a symbol indicating which algorithm should be used to calculate the checksum of files. `:md5` is default.
|
192
192
|
* `:digest_cmd` The command to calculate checksum of files. `md5sum` is default.
|
193
193
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require "capistrano/configuration/actions/file_transfer_ext/version"
|
2
2
|
require "capistrano/configuration"
|
3
3
|
require "capistrano/transfer"
|
4
|
+
require "find"
|
5
|
+
require "pathname"
|
4
6
|
require "stringio"
|
5
7
|
|
6
8
|
module Capistrano
|
@@ -36,6 +38,7 @@ module Capistrano
|
|
36
38
|
# * :install - use install_if_modified if :if_modified is set
|
37
39
|
# * :run_method - the default is :run.
|
38
40
|
def safe_upload(from, to, options={}, &block)
|
41
|
+
options = options.dup
|
39
42
|
transfer_method = options.delete(:transfer) == :if_modified ? :transfer_if_modified : :transfer
|
40
43
|
if options.has_key?(:install)
|
41
44
|
install_method = options.delete(:install) == :if_modified ? :install_if_modified : :install
|
@@ -64,35 +67,47 @@ module Capistrano
|
|
64
67
|
# * :digest_cmd - the digest command. the default is "#{digest}sum".
|
65
68
|
#
|
66
69
|
def transfer_if_modified(direction, from, to, options={}, &block)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
target
|
70
|
+
safe_options = options.dup
|
71
|
+
digest_method = safe_options.fetch(:digest, :md5).to_s
|
72
|
+
digest_cmd = safe_options.fetch(:digest_cmd, "#{digest_method.downcase}sum")
|
73
|
+
target = direction == :up ? from : to
|
71
74
|
remote_target = direction == :up ? to : from
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
target
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
75
|
+
require "digest/#{digest_method.downcase}"
|
76
|
+
target_is_io = target.respond_to?(:read)
|
77
|
+
if not(target_is_io) and FileTest.directory?(target)
|
78
|
+
Find.find(target) do |_target|
|
79
|
+
relative_path = Pathname.new(_target).relative_path_from(Pathname.new(target))
|
80
|
+
_remote_target = File.join(remote_target, relative_path)
|
81
|
+
from = direction == :up ? _target : _remote_target
|
82
|
+
to = direction == :up ? _remote_target : _target
|
83
|
+
transfer_if_modified(direction, from, to, options, &block) unless FileTest.directory?(_target)
|
81
84
|
end
|
82
|
-
end
|
83
|
-
logger.debug("#{digest_method.upcase}(#{target}) = #{digest}")
|
84
|
-
if dry_run
|
85
|
-
logger.debug("transfering: #{[direction, from, to] * ', '}")
|
86
85
|
else
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
86
|
+
if target_is_io
|
87
|
+
pos = target.pos
|
88
|
+
digest = Digest.const_get(digest_method.upcase).hexdigest(target.read)
|
89
|
+
target.pos = pos
|
90
|
+
else
|
91
|
+
begin
|
92
|
+
digest = Digest.const_get(digest_method.upcase).hexdigest(File.read(target))
|
93
|
+
rescue SystemCallError
|
94
|
+
digest = nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
logger.debug("#{digest_method.upcase}(#{target}) = #{digest}")
|
98
|
+
if dry_run
|
99
|
+
logger.debug("transfering: #{[direction, from, to] * ', '}")
|
100
|
+
else
|
101
|
+
execute_on_servers(safe_options) do |servers|
|
102
|
+
targets = servers.map { |server| sessions[server] }.reject { |session|
|
103
|
+
remote_digest = session.exec!("test -f #{remote_target.dump} && #{digest_cmd} #{remote_target.dump} | #{DIGEST_FILTER_CMD}")
|
104
|
+
logger.debug("#{session.xserver.host}: #{digest_method.upcase}(#{remote_target}) = #{remote_digest}")
|
105
|
+
result = !( digest.nil? or remote_digest.nil? ) && digest.strip == remote_digest.strip
|
106
|
+
logger.info("#{session.xserver.host}: skip transfering since no changes: #{[direction, from, to] * ', '}") if result
|
107
|
+
result
|
108
|
+
}
|
109
|
+
Capistrano::Transfer.process(direction, from, to, targets, safe_options.merge(:logger => logger), &block) unless targets.empty?
|
110
|
+
end
|
96
111
|
end
|
97
112
|
end
|
98
113
|
end
|
@@ -105,60 +120,75 @@ module Capistrano
|
|
105
120
|
# * :via - :run by default.
|
106
121
|
#
|
107
122
|
def install(from, to, options={}, &block)
|
123
|
+
options = options.dup
|
108
124
|
via = options.delete(:via)
|
109
125
|
if via == :sudo or options.delete(:sudo) # check :sudo for backward compatibility
|
110
126
|
# ignore {:via => :sudo} since `sudo()` cannot handle multiple commands properly.
|
111
|
-
|
127
|
+
_try_sudo = sudo
|
112
128
|
else
|
113
|
-
|
114
|
-
options[:via] = via
|
129
|
+
_try_sudo = ""
|
130
|
+
options[:via] = via if via
|
115
131
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
132
|
+
# * If :mode is :preserve or :mode is not given, preserve original mode.
|
133
|
+
# * Otherwise, just respect given :mode.
|
134
|
+
mode_given = options.key?(:mode)
|
135
|
+
mode = options.delete(:mode)
|
136
|
+
if mode_given ? mode == :preserve : true
|
137
|
+
if fetch(:install_preserve_mode, true)
|
138
|
+
begin
|
139
|
+
# respect mode of original file
|
140
|
+
# `stat -c` for GNU, `stat -f` for BSD
|
141
|
+
s = capture("test -f #{to.dump} && ( stat -c '%a' #{to.dump} || stat -f '%p' #{to.dump} )", options)
|
142
|
+
mode = s.to_i(8) & 0777 if /^[0-7]+$/ =~ s
|
143
|
+
logger.debug("preserve original file mode #{mode.to_s(8)}.")
|
144
|
+
rescue
|
145
|
+
mode = nil
|
146
|
+
end
|
147
|
+
else
|
148
|
+
mode = nil
|
127
149
|
end
|
128
150
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
151
|
+
owner_given = options.key?(:owner)
|
152
|
+
owner = options.delete(:owner)
|
153
|
+
if owner_given ? owner == :preserve : true
|
154
|
+
if fetch(:install_preserve_owner, true) and via == :sudo
|
155
|
+
begin
|
156
|
+
owner = capture("test -f #{to.dump} && ( stat -c '%u' #{to.dump} || stat -f '%u' #{to.dump} )", options).strip
|
157
|
+
logger.debug("preserve original file owner #{owner.dump}.")
|
158
|
+
rescue
|
159
|
+
owner = nil
|
160
|
+
end
|
161
|
+
else
|
162
|
+
owner = nil
|
137
163
|
end
|
138
164
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
165
|
+
group_given = options.key?(:group)
|
166
|
+
group = options.delete(:group)
|
167
|
+
if group_given ? group == :preserve : true
|
168
|
+
if fetch(:install_preserve_group, true) and via == :sudo
|
169
|
+
begin
|
170
|
+
group = capture("test -f #{to.dump} && ( stat -c '%g' #{to.dump} || stat -f '%g' #{to.dump} )", options).strip
|
171
|
+
logger.debug("preserve original file grop #{group.dump}.")
|
172
|
+
rescue
|
173
|
+
group = nil
|
174
|
+
end
|
175
|
+
else
|
176
|
+
group = nil
|
147
177
|
end
|
148
178
|
end
|
149
179
|
execute = []
|
150
180
|
if block_given?
|
151
181
|
execute << yield(from, to)
|
152
182
|
else
|
153
|
-
execute << "( test -d #{File.dirname(to).dump} || #{
|
154
|
-
execute << "#{
|
183
|
+
execute << "( test -d #{File.dirname(to).dump} || #{_try_sudo} mkdir -p #{File.dirname(to).dump} )"
|
184
|
+
execute << "#{_try_sudo} mv -f #{from.dump} #{to.dump}"
|
155
185
|
end
|
156
186
|
if mode
|
157
187
|
mode = mode.is_a?(Numeric) ? mode.to_s(8) : mode.to_s
|
158
|
-
execute << "#{
|
188
|
+
execute << "#{_try_sudo} chmod #{mode.dump} #{to.dump}"
|
159
189
|
end
|
160
|
-
execute << "#{
|
161
|
-
execute << "#{
|
190
|
+
execute << "#{_try_sudo} chown #{owner.to_s.dump} #{to.dump}" if owner
|
191
|
+
execute << "#{_try_sudo} chgrp #{group.to_s.dump} #{to.dump}" if group
|
162
192
|
invoke_command(execute.join(" && "), options)
|
163
193
|
end
|
164
194
|
alias place install
|
@@ -173,11 +203,18 @@ module Capistrano
|
|
173
203
|
# * :digest_cmd - the digest command. the default is "#{digest}sum".
|
174
204
|
#
|
175
205
|
def install_if_modified(from, to, options={}, &block)
|
206
|
+
options = options.dup
|
207
|
+
if options[:via] == :sudo or options.delete(:sudo)
|
208
|
+
_try_sudo = sudo
|
209
|
+
options[:via] = :sudo
|
210
|
+
else
|
211
|
+
_try_sudo = ""
|
212
|
+
end
|
176
213
|
digest_method = options.fetch(:digest, :md5).to_s
|
177
214
|
digest_cmd = options.fetch(:digest_cmd, "#{digest_method.downcase}sum")
|
178
215
|
install(from, to, options) do |from, to|
|
179
216
|
execute = []
|
180
|
-
execute << %{( test -d #{File.dirname(to).dump} || #{
|
217
|
+
execute << %{( test -d #{File.dirname(to).dump} || #{_try_sudo} mkdir -p #{File.dirname(to).dump} )}
|
181
218
|
# calculate hexdigest of `from'
|
182
219
|
execute << %{from=$(#{digest_cmd} #{from.dump} 2>/dev/null | #{DIGEST_FILTER_CMD} || true)}
|
183
220
|
execute << %{echo %s} % ["#{digest_method.upcase}(#{from}) = ${from}".dump]
|
@@ -189,7 +226,7 @@ module Capistrano
|
|
189
226
|
if [ -n "${from}" -a "${to}" ] && [ "${from}" = "${to}" ]; then
|
190
227
|
echo "skip installing since no changes.";
|
191
228
|
else
|
192
|
-
#{
|
229
|
+
#{_try_sudo} mv -f #{from.dump} #{to.dump};
|
193
230
|
fi
|
194
231
|
EOS
|
195
232
|
execute.join(" && ")
|
data/test/centos6-64/run.sh
CHANGED
data/test/config/deploy.rb
CHANGED
@@ -153,6 +153,20 @@ namespace(:test_default) {
|
|
153
153
|
run("test -f #{to.dump}")
|
154
154
|
run("test #{body.dump} = $(cat #{to.dump})")
|
155
155
|
}
|
156
|
+
|
157
|
+
task(:test_safe_upload_directory) {
|
158
|
+
files = %w(x y z)
|
159
|
+
body = "baz"
|
160
|
+
from = "tmp/baz"
|
161
|
+
from_files = files.map { |x| File.join(from, x) }
|
162
|
+
to = "tmp/rbaz"
|
163
|
+
to_files = files.map { |x| File.join(to, x) }
|
164
|
+
run_locally("rm -rf #{from.dump}; mkdir -p #{from.dump}")
|
165
|
+
run_locally(from_files.map { |file| "echo #{body.dump} > #{file.dump}" }.join(" && "))
|
166
|
+
run("rm -rf #{to.dump}")
|
167
|
+
safe_upload(from, to)
|
168
|
+
run(to_files.map { |file| "test -f #{file.dump}" }.join(" && "))
|
169
|
+
}
|
156
170
|
}
|
157
171
|
|
158
172
|
namespace(:test_transfer_if_modified) {
|
data/test/precise64/run.sh
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano-file-transfer-ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: capistrano
|