capistrano-file-transfer-ext 0.0.1 → 0.0.2

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.
@@ -7,36 +7,121 @@ module Capistrano
7
7
  class Configuration
8
8
  module Actions
9
9
  module FileTransferExt
10
+ DIGEST_FILTER_CMD = %{awk '{for(n=1;n<=NF;n++){if(match($n,"^[0-9a-z]{16,}$")){print($n);break}}}'}
11
+
10
12
  def safe_put(data, path, options={})
11
13
  opts = options.dup
12
14
  safe_upload(StringIO.new(data), path, opts)
13
15
  end
14
16
 
17
+ # upload file from local to remote.
18
+ # this method uses temporary file to avoid incomplete transmission of files.
19
+ #
20
+ # The +options+ hash may include any of the following keys:
21
+ #
22
+ # * :transfer - use transfer_if_modified if :if_modified is set
23
+ # * :place - use place_if_modified if :if_modified is set
24
+ # * :run_method - the default is :run.
15
25
  def safe_upload(from, to, options={}, &block)
16
- mode = options.delete(:mode)
17
- via = ( options.delete(:via) || :run )
18
- compare_method = ( options.delete(:compare_method) || :cmp )
26
+ transfer_method = options.delete(:transfer) == :if_modified ? :transfer_if_modified : :transfer
27
+ place_method = options.delete(:place) == :if_modified ? :place_if_modified : :place
28
+ run_method = ( options.delete(:run_method) || :run )
19
29
  begin
20
30
  tempname = File.join("/tmp", File.basename(to) + ".XXXXXXXXXX")
21
31
  tempfile = capture("mktemp #{tempname.dump}").strip
22
32
  run("rm -f #{tempfile.dump}", options)
23
- transfer(:up, from, tempfile, options, &block)
24
- execute = []
25
- case compare_method
26
- when :diff
27
- execute << "( diff -u #{to.dump} #{tempfile.dump} || mv -f #{tempfile.dump} #{to.dump} )"
28
- else
29
- execute << "( cmp #{to.dump} #{tempfile.dump} || mv -f #{tempfile.dump} #{to.dump} )"
30
- end
31
- if mode
32
- mode = mode.is_a?(Numeric) ? mode.to_s(8) : mode.to_s
33
- execute << "chmod #{mode} #{to}"
34
- end
35
- invoke_command(execute.join(" && "), options.merge(:via => via))
33
+ send(transfer_method, :up, from, tempfile, options, &block)
34
+ send(place_method, tempfile, to, options.merge(:via => run_method), &block)
36
35
  ensure
37
36
  run("rm -f #{tempfile.dump}", options) rescue nil
38
37
  end
39
38
  end
39
+
40
+ # transfer file (or IO like object) from local to remote, only if the file checksum is differ.
41
+ # do not care if the transfer has been completed or not.
42
+ #
43
+ # The +options+ hash may include any of the following keys:
44
+ #
45
+ # * :digest - digest algorithm. the default is "md5".
46
+ # * :digest_cmd - the digest command. the default is "#{digest}sum".
47
+ #
48
+ def transfer_if_modified(direction, from, to, options={}, &block)
49
+ digest_method = options.fetch(:digest, "md5")
50
+ digest_cmd = options.fetch(:digest_cmd, "#{digest_method.downcase}sum")
51
+ require "digest/#{digest_method.downcase}"
52
+ target = direction == :up ? from : to
53
+ remote_target = direction == :up ? to : from
54
+ if target.respond_to?(:read)
55
+ pos = target.pos
56
+ digest = Digest.const_get(digest_method.upcase).hexdigest(target.read)
57
+ target.pos = pos
58
+ else
59
+ begin
60
+ digest = Digest::const_get(digest_method.upcase).hexdigest(File.read(target))
61
+ rescue SystemCallError
62
+ digest = nil
63
+ end
64
+ end
65
+ if dry_run
66
+ logger.debug("transfering: #{[direction, from, to] * ', '}")
67
+ else
68
+ execute_on_servers(options) do |servers|
69
+ targets = servers.map { |server| sessions[server] }.reject { |session|
70
+ remote_digest = session.exec!("test -f #{remote_target.dump} && #{digest_cmd} #{remote_target.dump} | #{DIGEST_FILTER_CMD}")
71
+ result = !( digest.nil? or remote_digest.nil? ) && digest == remote_digest.strip
72
+ logger.info("#{session.xserver.host}: skip transfering since no changes: #{[direction, from, to] * ', '}") if result
73
+ result
74
+ }
75
+ Capistrano::Transfer.process(direction, from, to, targets, options.merge(:logger => logger), &block) unless targets.empty?
76
+ end
77
+ end
78
+ end
79
+
80
+ # place a file on remote.
81
+ #
82
+ # The +options+ hash may include any of the following keys:
83
+ #
84
+ # * :mode - permission of the file.
85
+ # * :sudo - use sudo if set true. the default is false.
86
+ #
87
+ def place(from, to, options={}, &block)
88
+ mode = options.delete(:mode)
89
+ try_sudo = options.delete(:sudo) ? sudo : ""
90
+ execute = []
91
+ execute << "( test -d #{File.dirname(to).dump} || #{try_sudo} mkdir -p #{File.dirname(to).dump} )"
92
+ execute << "#{try_sudo} mv -f #{from.dump} #{to.dump}"
93
+ if mode
94
+ mode = mode.is_a?(Numeric) ? mode.to_s(8) : mode.to_s
95
+ execute << "#{try_sudo} chmod #{mode} #{to.dump}"
96
+ end
97
+ invoke_command(execute.join(" && "), options)
98
+ end
99
+
100
+ # place a file on remote, only if the destination is differ from source.
101
+ #
102
+ # The +options+ hash may include any of the following keys:
103
+ #
104
+ # * :mode - permission of the file.
105
+ # * :sudo - use sudo if set true. the default is false.
106
+ # * :digest - digest algorithm. the default is "md5".
107
+ # * :digest_cmd - the digest command. the default is "#{digest}sum".
108
+ #
109
+ def place_if_modified(from, to, options={}, &block)
110
+ mode = options.delete(:mode)
111
+ try_sudo = options.delete(:sudo) ? sudo : ""
112
+ digest_method = options.fetch(:digest, "md5")
113
+ digest_cmd = options.fetch(:digest_cmd, "#{digest_method.downcase}sum")
114
+ execute = []
115
+ execute << %{( test -d #{File.dirname(to).dump} || #{try_sudo} mkdir -p #{File.dirname(to).dump} )}
116
+ execute << %{from=$(#{digest_cmd} #{from.dump} | #{DIGEST_FILTER_CMD})}
117
+ execute << %{to=$(#{digest_cmd} #{to.dump} | #{DIGEST_FILTER_CMD})}
118
+ execute << %{( test "x${from}" = "x${to}" || ( echo #{from.dump} '->' #{to.dump}; #{try_sudo} mv -f #{from.dump} #{to.dump} ) )}
119
+ if mode
120
+ mode = mode.is_a?(Numeric) ? mode.to_s(8) : mode.to_s
121
+ execute << "#{try_sudo} chmod #{mode} #{to.dump}"
122
+ end
123
+ invoke_command(execute.join(" && "), options)
124
+ end
40
125
  end
41
126
  end
42
127
  end
@@ -2,7 +2,7 @@ module Capistrano
2
2
  class Configuration
3
3
  module Actions
4
4
  module FileTransferExt
5
- VERSION = "0.0.1"
5
+ VERSION = "0.0.2"
6
6
  end
7
7
  end
8
8
  end
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.0.1
4
+ version: 0.0.2
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-02-19 00:00:00.000000000 Z
12
+ date: 2013-02-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: capistrano