Class: Capistrano::Deploy::Strategy::Copy

Inherits:
Base
  • Object
show all
Defined in:
lib/capistrano/recipes/deploy/strategy/copy.rb

Overview

This class implements the strategy for deployments which work by preparing the source code locally, compressing it, copying the file to each target host, and uncompressing it to the deployment directory.

By default, the SCM checkout command is used to obtain the local copy of the source code. If you would rather use the export operation, you can set the :copy_strategy variable to :export.

set :copy_strategy, :export

For even faster deployments, you can set the :copy_cache variable to true. This will cause deployments to do a new checkout of your repository to a new directory, and then copy that checkout. Subsequent deploys will just resync that copy, rather than doing an entirely new checkout. Additionally, you can specify file patterns to exclude from the copy when using :copy_cache; just set the :copy_exclude variable to a file glob (or an array of globs).

set :copy_cache, true
set :copy_exclude, ".git/*"

Note that :copy_strategy is ignored when :copy_cache is set. Also, if you want the copy cache put somewhere specific, you can set the variable to the path you want, instead of merely 'true':

set :copy_cache, "/tmp/caches/myapp"

This deployment strategy also supports a special variable, :copy_compression, which must be one of :gzip, :bz2, or :zip, and which specifies how the source should be compressed for transmission to each host.

Defined Under Namespace

Classes: Compression

Instance Attribute Summary

Attributes inherited from Base

#configuration

Instance Method Summary (collapse)

Methods inherited from Base

#initialize

Constructor Details

This class inherits a constructor from Capistrano::Deploy::Strategy::Base

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Capistrano::Deploy::Strategy::Base

Instance Method Details

- (Object) check!



111
112
113
114
115
116
117
# File 'lib/capistrano/recipes/deploy/strategy/copy.rb', line 111

def check!
  super.check do |d|
    d.local.command(source.local.command) if source.local.command
    d.local.command(compress(nil, nil).first)
    d.remote.command(decompress(nil).first)
  end
end

- (Object) copy_cache

Returns the location of the local copy cache, if the strategy should use a local cache + copy instead of a new checkout/export every time. Returns nil unless :copy_cache has been set. If :copy_cache is true, a default cache location will be returned.



123
124
125
126
127
# File 'lib/capistrano/recipes/deploy/strategy/copy.rb', line 123

def copy_cache
  @copy_cache ||= configuration[:copy_cache] == true ?
    File.join(Dir.tmpdir, configuration[:application]) :
    configuration[:copy_cache]
end

- (Object) deploy!

Obtains a copy of the source code locally (via the #command method), compresses it to a single file, copies that file to all target servers, and uncompresses it on each of them into the deployment directory.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/capistrano/recipes/deploy/strategy/copy.rb', line 46

def deploy!
  if copy_cache
    if File.exists?(copy_cache)
      logger.debug "refreshing local cache to revision #{revision} at #{copy_cache}"
      system(source.sync(revision, copy_cache))
    else
      logger.debug "preparing local cache at #{copy_cache}"
      system(source.checkout(revision, copy_cache))
    end

    # Check the return code of last system command and rollback if not 0
    unless $? == 0
      raise Capistrano::Error, "shell command failed with return code #{$?}"
    end

    logger.debug "copying cache to deployment staging area #{destination}"
    Dir.chdir(copy_cache) do
      FileUtils.mkdir_p(destination)
      queue = Dir.glob("*", File::FNM_DOTMATCH)
      while queue.any?
        item = queue.shift
        name = File.basename(item)

        next if name == "." || name == ".."
        next if copy_exclude.any? { |pattern| File.fnmatch(pattern, item) }

        if File.symlink?(item)
          FileUtils.ln_s(File.readlink(File.join(copy_cache, item)), File.join(destination, item))
        elsif File.directory?(item)
          queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
          FileUtils.mkdir(File.join(destination, item))
        else
          FileUtils.ln(File.join(copy_cache, item), File.join(destination, item))
        end
      end
    end
  else
    logger.debug "getting (via #{copy_strategy}) revision #{revision} to #{destination}"
    system(command)

    if copy_exclude.any?
      logger.debug "processing exclusions..."
      if copy_exclude.any?
        copy_exclude.each do |pattern| 
          delete_list = Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)
          # avoid the /.. trap that deletes the parent directories
          delete_list.delete_if { |dir| dir =~ /\/\.\.$/ }
          FileUtils.rm_rf(delete_list.compact)
        end
      end
    end
  end

  File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }

  logger.trace "compressing #{destination} to #{filename}"
  Dir.chdir(tmpdir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }

  upload(filename, remote_filename)
  run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
ensure
  FileUtils.rm filename rescue nil
  FileUtils.rm_rf destination rescue nil
end