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
- * `: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.
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
- Source file.
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
- Destination file.
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 just like `mv`.
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
- Source file on remote server.
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
- Destination file on remote server.
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 not given, preserve original mode of `to`.
158
- * `:owner` The owner of destination file. If not given and `:via` is `:sudo`, preserve original mode of `to`.
159
- * `:group` The group of destination file. If not given and `:via` is `:sudo`, preserve original mode of `to`.
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
- Source file on remote server.
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
- Destination file on remote server.
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 mode of `to`.
190
- * `:group` The group of destination file. If not given and `:via` is `:sudo`, preserve original mode of `to`.
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
- digest_method = options.fetch(:digest, :md5).to_s
68
- digest_cmd = options.fetch(:digest_cmd, "#{digest_method.downcase}sum")
69
- require "digest/#{digest_method.downcase}"
70
- target = direction == :up ? from : to
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
- if target.respond_to?(:read)
73
- pos = target.pos
74
- digest = Digest.const_get(digest_method.upcase).hexdigest(target.read)
75
- target.pos = pos
76
- else
77
- begin
78
- digest = Digest.const_get(digest_method.upcase).hexdigest(File.read(target))
79
- rescue SystemCallError
80
- digest = nil
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
- execute_on_servers(options) do |servers|
88
- targets = servers.map { |server| sessions[server] }.reject { |session|
89
- remote_digest = session.exec!("test -f #{remote_target.dump} && #{digest_cmd} #{remote_target.dump} | #{DIGEST_FILTER_CMD}")
90
- logger.debug("#{session.xserver.host}: #{digest_method.upcase}(#{remote_target}) = #{remote_digest}")
91
- result = !( digest.nil? or remote_digest.nil? ) && digest.strip == remote_digest.strip
92
- logger.info("#{session.xserver.host}: skip transfering since no changes: #{[direction, from, to] * ', '}") if result
93
- result
94
- }
95
- Capistrano::Transfer.process(direction, from, to, targets, options.merge(:logger => logger), &block) unless targets.empty?
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
- try_sudo = sudo
127
+ _try_sudo = sudo
112
128
  else
113
- try_sudo = ""
114
- options[:via] = via
129
+ _try_sudo = ""
130
+ options[:via] = via if via
115
131
  end
116
- if options.key?(:mode)
117
- mode = options.delete(:mode)
118
- elsif fetch(:install_preserve_mode, true)
119
- begin
120
- # respect mode of original file
121
- # `stat -c` for GNU, `stat -f` for BSD
122
- s = capture("test -f #{to.dump} && ( stat -c '%a' #{to.dump} || stat -f '%p' #{to.dump} )", options)
123
- mode = s.to_i(8) & 0777 if /^[0-7]+$/ =~ s
124
- logger.debug("preserve original file mode #{mode.to_s(8)}.")
125
- rescue
126
- # nop
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
- if options.key?(:owner)
130
- owner = options.delete(:owner)
131
- elsif fetch(:install_preserve_owner, true) and via == :sudo
132
- begin
133
- owner = capture("test -f #{to.dump} && ( stat -c '%u' #{to.dump} || stat -f '%u' #{to.dump} )", options).strip
134
- logger.debug("preserve original file owner #{owner.dump}.")
135
- rescue
136
- # nop
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
- if options.key?(:group)
140
- group = options.delete(:group)
141
- elsif fetch(:install_preserve_group, true) and via == :sudo
142
- begin
143
- group = capture("test -f #{to.dump} && ( stat -c '%g' #{to.dump} || stat -f '%g' #{to.dump} )", options).strip
144
- logger.debug("preserve original file grop #{group.dump}.")
145
- rescue
146
- # nop
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} || #{try_sudo} mkdir -p #{File.dirname(to).dump} )"
154
- execute << "#{try_sudo} mv -f #{from.dump} #{to.dump}"
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 << "#{try_sudo} chmod #{mode.dump} #{to.dump}"
188
+ execute << "#{_try_sudo} chmod #{mode.dump} #{to.dump}"
159
189
  end
160
- execute << "#{try_sudo} chown #{owner.to_s.dump} #{to.dump}" if owner
161
- execute << "#{try_sudo} chgrp #{group.to_s.dump} #{to.dump}" if group
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} || #{try_sudo} mkdir -p #{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
- #{try_sudo} mv -f #{from.dump} #{to.dump};
229
+ #{_try_sudo} mv -f #{from.dump} #{to.dump};
193
230
  fi
194
231
  EOS
195
232
  execute.join(" && ")
@@ -2,7 +2,7 @@ module Capistrano
2
2
  class Configuration
3
3
  module Actions
4
4
  module FileTransferExt
5
- VERSION = "0.1.0"
5
+ VERSION = "0.1.1"
6
6
  end
7
7
  end
8
8
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  bundle exec vagrant up
4
4
  bundle exec cap test_all
5
- bundle exec vagrant destroy -f
5
+ bundle exec vagrant halt
6
6
 
7
7
  # vim:set ft=sh :
@@ -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) {
@@ -2,6 +2,6 @@
2
2
 
3
3
  bundle exec vagrant up
4
4
  bundle exec cap test_all
5
- bundle exec vagrant destroy -f
5
+ bundle exec vagrant halt
6
6
 
7
7
  # vim:set ft=sh :
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.0
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-14 00:00:00.000000000 Z
12
+ date: 2013-03-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: capistrano