#!/usr/bin/ruby
#
# pdumpfs-rsync: remote pdumpfs using rsync
#
# Usage:
#   pdumpfs-rsync <username>@<source host>:<source directory> \
#                 <destination directory>
#
# Copyright(C) 2003 Taku YASUI <tach@debian.or.jp>, All rights reserved.
# This software uses codes from pdumpfs.  pdumpfs is copyrighted by
# Satoru Takabayashi <satoru@namazu.org>.
# This is free software with ABSOLUTELY NO WARRANTY.
#
# You can redistribute it and/or modify it under the terms of 
# the GNU General Public License version 2.
#

load File.join(File.dirname(__FILE__), 'pdumpfs')
require 'ftools'
require 'getoptlong'

PDUMPFS_RSYNC_VERSION  = '0.8.1'

def parse_options
  patterns = []
  globs = []
  size = nil
  rsync_options = []
  options = {}
  ret = []
  base = nil

  parser = GetoptLong.new
  parser.set_options(
    ['--exclude',			GetoptLong::REQUIRED_ARGUMENT],
    ['--exclude-from',			GetoptLong::REQUIRED_ARGUMENT],
    ['--include',			GetoptLong::REQUIRED_ARGUMENT],
    ['--include-from',			GetoptLong::REQUIRED_ARGUMENT],
    ['--exclude-by-regexp', '-e',	GetoptLong::REQUIRED_ARGUMENT],
    ['--exclude-by-size', '-s',		GetoptLong::REQUIRED_ARGUMENT],
    ['--exclude-by-glob', '-w',		GetoptLong::REQUIRED_ARGUMENT],
    ['--base',				GetoptLong::REQUIRED_ARGUMENT],
    ['--force-hardlink', '-f',		GetoptLong::NO_ARGUMENT],
    ['--help', '-h',			GetoptLong::NO_ARGUMENT],
    ['--version', '-v',			GetoptLong::NO_ARGUMENT])
  parser.each_option do |name, arg|
    case name
    when /^--(in|ex)clude(-from)?$/
      rsync_options.push(sprintf("%s=%s", name, arg))
    when '--exclude-by-regexp'
      patterns.push(Regexp.new(arg))
    when '--exclude-by-size'
      size = arg
    when '--exclude-by-glob'
      globs.push(arg)
    when '--help'
      usage
    when '--version'
      version
    when '--base'
      base = arg
    else
      options[name.sub(/^--/, "")] = arg
    end
  end
  matcher = Pdumpfs::FileMatcher.new(:size	=> size,
				     :globs	=> globs,
				     :patterns	=> patterns)

  usage if ( ARGV.length < 2 )

  # strip the trailing / to avoid basename(src) == ''.
  src  = ARGV[0].sub(%r!/+$!, "")
  dest = ARGV[1]
  base = ARGV[2] || base || File.basename(ARGV[0].sub(%r!^[^/]+?:!, '').sub(%r!/+$!, ''))

  nodir(dest) if File.directory?(dest) == false
  if windows?
    dest = expand_special_folders(dest)
  end

  ret.push(File.join(ARGV[1], 'latest', base))
  ret.push(dest)
  ret.push(base)
  ret.push(matcher)
  ret.push(rsync_options)
  ret.push(options)
end

def usage
  puts "Usage: pdumpfs <source directory> <destination directory>" +
       " [destination basename]"
  puts "  -e, --exclude-by-regexp=PATTERN  exclude files/directories matching PATTERN"
  puts "  -s, --exclude-by-size=SIZE       exclude files larger than SIZE"
  puts "  -w, --exclude-by-glob=GLOB       exclude files matching GLOB"
  puts "      --exclude=PATTERN            exclude files matching PATTERN (rsync)"
  puts "      --include=PATTERN            include files matching PATTERN (rsync)"
  puts "      --exclude-from=FILE          exclude patterns listed in FILE (rsync)"
  puts "      --include-from=FILE          include patterns listed in FILE (rsync)"
  puts "  -f, --force-hardlink             Force hardlinking when rsync is failed"
  puts "  -v, --version                    print version information and exit"
  puts "  -h, --help                       show this help message"
  exit 0
end

def version
  puts 'pdumpfs-rsync ' + PDUMPFS_RSYNC_VERSION
  exit 0
end

def main
  src, dest, base, matcher, rsync_opts, opts = parse_options
  rsync_array = ['/usr/local/bin/rsync',
		 '-avH',
		 '--delete',
		 '--delete-excluded',
		 '--size-only',
		 '--exclude=lost+found/',
		 '--rsh=/usr/bin/ssh']

  if windows?
    fstype = get_filesystem_type(dest)

    if fstype !~ /ntfs/i
      STDERR.fprintf("pdumpfs: only NTFS is supported but %s is %s.",
		     dest, fstype)
      exit 1
    end
  end

  start_time = Time.now
  pdumpfs = Pdumpfs::Pdumpfs.new(opts)
  latest = pdumpfs.latest_snapshot(start_time, src, dest, base)
  today = File.join(dest, pdumpfs.datedir(Date.today), base)
  rsync_array = rsync_array + rsync_opts
  rsync_array.push(ARGV[0].sub(%r!/+$!, '') + '/')
  rsync_array.push(src + '/')

  File.umask(0077)
  File.mkpath(src)
  File.mkpath(today)
  if ( system(*rsync_array) || opts['force-hardlink'] )
    if ( $? >> 8 != 0 )
      STDERR.print "WARNING: rsync failed: #{ARGV[0]}; exit value: #{$? >> 8}\n"
    end
    if latest
      pdumpfs.update_snapshot(src, latest, today)
    else
      pdumpfs.recursive_copy(src, today)
    end
  else
    STDERR.print "rsync failed: #{ARGV[0]}; exit value: #{$? >> 8}\n"
    exit $? >> 8
  end
end

main if __FILE__ == $0


syntax highlighted by Code2HTML, v. 0.9.1