module SyncWrap::Rsync

Low level support for rsync command construction and template processing.

Private Instance Methods

expand_entries( src ) click to toggle source
# File lib/syncwrap/rsync.rb, line 220
def expand_entries( src ) # :doc:
  Dir.entries( src ).
    reject { |e| e =~ /^\.+$/ }.
    map { |e| File.join( src, e ) }
end
expand_implied_target( srcs ) click to toggle source
# File lib/syncwrap/rsync.rb, line 110
def expand_implied_target( srcs ) # :doc:
  #FIXME: Honor absolute arg paths?
  if srcs.length == 1
    target = "/" + srcs.first
    target = File.dirname( target ) + '/' unless target =~ %r{/$}
  else
    target = srcs.pop
  end
  [ srcs, target ]
end
find_source_erbs( sources ) click to toggle source
# File lib/syncwrap/rsync.rb, line 209
def find_source_erbs( sources ) # :doc:
  Array( sources ).inject([]) do |list, src|
    if File.directory?( src )
      list += find_source_erbs( expand_entries( src ) )
    elsif src =~ /\.erb$/
      list << src
    end
    list
  end
end
mktmpdir( opts ) { |path| ... } click to toggle source

Like Dir.mktmpdir but with option to specify :tmpdir_mode.

# File lib/syncwrap/rsync.rb, line 200
def mktmpdir( opts ) # :doc:
  path = Dir::Tmpname.create( 'syncwrap-' ) do |n|
    Dir.mkdir( n, opts[ :tmpdir_mode ] || 0700 )
  end
  yield path
ensure
  FileUtils.remove_entry( path ) if path
end
process_templates( srcs, opts ) { |processed_sources| ... } click to toggle source

Process templates in tmpdir and yield post-processed sources to block, cleaning up on exit.

# File lib/syncwrap/rsync.rb, line 169
def process_templates( srcs, opts ) # :doc:
  bnd = opts[ :erb_binding ] or raise "required :erb_binding param missing"
  erb_mode = opts[ :erb_mode ] || '<>' #Trim new line on "<% ... %>\n"
  mktmpdir( opts ) do |tmp_dir|
    processed_sources = []
    out_dir = File.join( tmp_dir, 'd' ) #for default perms
    srcs.each do |src|
      erbs = find_source_erbs( src )
      outname = nil
      erbs.each do |erb|
        spath = subpath( src, erb )
        outname = File.join( out_dir, spath, File.basename( erb, '.erb' ) )
        FileUtils.mkdir_p( File.dirname( outname ) )
        perm = File.stat( erb ).mode
        File.open( outname, "w", perm ) do |fout|
          template = ERB.new( IO.read( erb ), nil, erb_mode )
          template.filename = erb
          fout.puts( template.result( bnd ) )
        end
      end
      if erbs.length == 1 && src == erbs.first
        processed_sources << outname
      elsif !erbs.empty?
        processed_sources << ( out_dir + '/' )
      end
    end
    yield processed_sources
  end
end
resolve_source( path, sync_paths ) click to toggle source

Resolve the specified source path to the first existing file/directory in sync_paths roots and returns a relativize path. Also tries with an .erb suffix if a src does not have a trailing '/'. Preserves any trailing '/'. Returns nil if not found.

# File lib/syncwrap/rsync.rb, line 140
def resolve_source( path, sync_paths ) # :doc:
  #FIXME: Honor absolute arg paths?
  found = nil
  sync_paths.each do |r|
    candidate = File.join( r, path )
    if File.exist?( candidate )
      found = candidate
    elsif candidate !~ %r{(\.erb|/)$}
      candidate += '.erb'
      if File.exist?( candidate )
        found = candidate
      end
    end
    break if found
  end

  found && relativize( found )
end
resolve_source!( path, sync_paths ) click to toggle source

Resolve the specified source path via resolve_source. Raises SourceNotFound if not found.

# File lib/syncwrap/rsync.rb, line 129
def resolve_source!( path, sync_paths ) # :doc:
  resolve_source( path, sync_paths ) or
    raise( SourceNotFound,
          "#{path.inspect} not found in :sync_paths #{sync_paths.inspect}" )
end
resolve_sources( srcs, sync_paths ) click to toggle source

Resolves each srcs path via resolve_source! Raises SourceNotFound if any not found.

# File lib/syncwrap/rsync.rb, line 123
def resolve_sources( srcs, sync_paths ) # :doc:
  srcs.map { |path| resolve_source!( path, sync_paths ) }
end
rsync_args( host, srcs, target, opts = {} ) click to toggle source
# File lib/syncwrap/rsync.rb, line 32
def rsync_args( host, srcs, target, opts = {} ) # :doc:

  cmd = [ 'rsync' ]

  # -i --itemize-changes, used for counting changed files
  flags = %w[ -i ]

  # -r --recursive
  flags << '-r' if ( opts[:recursive] ||
                     ( !opts[:manifest] && ( opts[:recursive] != false ) ) )

  flags << "--files-from=#{opts[:manifest]}" if opts[:manifest]

  # -l --links (recreate symlinks on the destination)
  flags << '-l' unless opts[:links] == false

  # -p --perms (set destination to source permissions)
  # -E --executability (perserve execute only, default)
  if opts[:perms] != false
    if opts[:perms] == :p || opts[:perms].is_a?( String )
      flags << '-p'
      if opts[ :perms ].is_a?( String )
        flags << "--chmod=#{opts[ :perms ]}"
      end
    else
      flags << '-E'
    end
  end

  # -c --checksum (to determine changes; not just size,time)
  flags << '-c' unless opts[:checksum] == false

  # -b --backup (make backups)
  flags << '-b' unless opts[:backup] == false

  # Pass ssh options via -e (--rsh) flag
  ssh_flags = []
  ssh_flags += opts[ :ssh_flags ] if opts[ :ssh_flags ]
  if opts[ :ssh_options ]
    ssh_flags += opts[:ssh_options].map { |o| ['-o', o.join('=')] }.flatten
  end
  if opts[ :ssh_user ]
    ssh_flags += [ '-l', opts[ :ssh_user ] ]
    ssh_flags += [ '-i', opts[ :ssh_user_pem ] ] if opts[ :ssh_user_pem ]
  end
  flags += [ '-e', "ssh #{ssh_flags.join ' '}" ] unless ssh_flags.empty?

  if opts[ :user ]
    # Use sudo to place files at remote.
    user = opts[ :user ].to_s
    scmd = if user == 'root'
             %w[ sudo rsync ]
           else
             [ 'sudo', '-u', user, 'rsync' ]
           end
    if host == 'localhost'
      cmd = scmd
    else
      flags << "--rsync-path=#{scmd.join ' '}"
    end
  end

  excludes = Array( opts[ :excludes ] )
  flags += excludes.map do |e|
    if e == :dev
      '--cvs-exclude'
    else
      "--exclude=#{e}"
    end
  end

  flags << '-n' if opts[ :dryrun ]

  target = [ host, target ].join(':') unless host == 'localhost'

  [ *cmd, *flags, *srcs, target ]
end
subpath( src, file ) click to toggle source

Given file path within src, return any sub-directory path needed to reach file, or the empty string. This is also src trailing '/' aware.

# File lib/syncwrap/rsync.rb, line 162
def subpath( src, file ) # :doc:
  src = src.sub( %r{/[^/]*$}, '' ) #remove trail slash or last element
  File.dirname( file ).sub( /^#{src}\/?/, '' )
end