capistrano-file-transfer-ext 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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