Class: Rsyncbackup

Inherits:
Object
  • Object
show all
Includes:
Methadone::CLILogging
Defined in:
lib/rsyncbackup.rb,
lib/rsyncbackup/version.rb,
lib/rsyncbackup/utilities.rb

Constant Summary collapse

VERSION =
"1.0.2"
DEFAULT_EXCLUSIONS =
File.expand_path('.rsyncbackup.exclusions', ENV['HOME'])

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Rsyncbackup

Returns a new instance of Rsyncbackup.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/rsyncbackup.rb', line 11

def initialize(opts={})
  @options = {
    dry_run: false,
    exclusions: DEFAULT_EXCLUSIONS,
    archive: true,
    one_file_system: true,
    hard_links: true,
    human_readable: true,
    inplace: true,
    numeric_ids: true,
    delete: true,
    rsync_cmd: rsync_executable
  }.merge(opts)
  
  options[:source] = strip_trailing_separator_if_any(options[:source])
  options[:target] = strip_trailing_separator_if_any(options[:target])
  options[:link_dest] ||= last_full_backup
  
  if logger.warn? && options[:verbose] == true
    logger.level=Logger::INFO
  end

  debug "#{caller[0]}options: #{options.inspect}"

end

Instance Attribute Details

#optionsObject

Returns the value of attribute options.



9
10
11
# File 'lib/rsyncbackup.rb', line 9

def options
  @options
end

Instance Method Details

#backup_dir_nameObject

returns the directory name for the current backup directory name consists of a time format: YYYY-MM-DDTHH-MM-SS



53
54
55
# File 'lib/rsyncbackup/utilities.rb', line 53

def backup_dir_name
  @backup_dir_name ||= Time.now.strftime("%FT%H-%M-%S")
end

#build_commandObject

returns the command string to execute with all parameters set



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/rsyncbackup/utilities.rb', line 17

def build_command
  
  cmd = []
  cmd << options[:rsync_cmd]
  cmd << '--verbose --progress --itemize-changes' if logger.info?
  cmd << '--archive'             if options[:archive]
  cmd << '--one-file-system'     if options[:one_file_system]
  cmd << '--hard-links'          if options[:hard_links]
  cmd << '--human-readable'      if options[:human_readable]
  cmd << '--inplace'             if options[:inplace]
  cmd << '--numeric-ids'         if options[:numeric_ids]
  cmd << '--delete'              if options[:delete]
  cmd << "--exclude-file #{options[:exclusions]}" if File.exist?(options[:exclusions])
  cmd << "--link-dest '#{options[:link_dest]}'" if options[:link_dest]
  cmd << "'#{options[:source]}'"
  cmd << "'#{temp_target_path}'"
  
  cmd.join(' ').tap{|t| debug "#{caller[0]} Command: #{t}" }
  
end

#finalizeObject



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rsyncbackup.rb', line 66

def finalize

  incomplete = "#{options[:target]}/.incomplete"
  complete = "#{options[:target]}/#{backup_dir_name}"

  if File.exist?(incomplete) &&
      !File.exist?(complete)
    File.rename(incomplete, complete)
  end
  
  File.open("#{options[:target]}/.lastfull",'w') do |fh|
    fh.puts backup_dir_name
  end

  info "Backup saved in #{options[:target]}/#{backup_dir_name}"
end

#full_target_pathObject

returns the full target path, including backup directory name



58
59
60
# File 'lib/rsyncbackup/utilities.rb', line 58

def full_target_path
  @full_target_path ||= options[:target]+"/"+backup_dir_name
end

#last_full_backupObject

returns the directory name of the last full backup returns nil otherwise



40
41
42
43
44
45
46
47
48
49
# File 'lib/rsyncbackup/utilities.rb', line 40

def last_full_backup
  
  lastfull = "#{options[:target]}/.lastfull"
  if File.exist?(lastfull)
    last_full_directory = IO.readlines(lastfull).first.chomp
  else
    nil
  end

end

#rsync_executableObject

returns the path to the rsync executable If none found, raises an Exception



71
72
73
74
75
# File 'lib/rsyncbackup/utilities.rb', line 71

def rsync_executable
  rsync = `which rsync`.chomp
  raise "No rsync executable. Are you sure it\'s installed?" if rsync.empty?
  rsync
end

#runObject



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rsyncbackup.rb', line 38

def run
  cmd = build_command
  
  info "Rsync command: #{cmd}"
  if options[:dry_run]
    info "Dry run only"
  end
    
  if File.exist? temp_target_path
    warn "Preexisting temporary target. Moving it aside."
    File.rename temp_target_path, "#{temp_target_path}-#{"%0.4d" % Random.rand(1000)}"
  end


  Open3.popen3(cmd) do |stdin, stdout, stderr, wait|
    stdin.close
    until stdout.eof?
      info stdout.gets
    end
    until stderr.eof?
      errors =  stderr.gets
    end
    result = wait.value
    raise "Command failed. Return code: #{result}\n#{errors}" unless result == 0
  end
      
end

#strip_trailing_separator_if_any(s) ⇒ Object

Strip the trailing directory separator from the rsync source or target.

s

string to strip



81
82
83
84
# File 'lib/rsyncbackup/utilities.rb', line 81

def strip_trailing_separator_if_any(s)
  raise "not a String" unless s.is_a?(String)
  s = s.gsub(%r{/$},'')
end

#temp_target_pathObject

returns the temporary target path



63
64
65
# File 'lib/rsyncbackup/utilities.rb', line 63

def temp_target_path
  @temp_target_path ||= options[:target]+"/.incomplete"
end