capistrano-file-transfer-ext 0.1.0 → 0.1.1
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.
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
|