Module: Doing::Util::Backup

Extended by:
Backup
Includes:
Doing::Util
Included in:
Backup
Defined in:
lib/doing/util_backup.rb

Overview

Backup utils

Instance Method Summary collapse

Methods included from Doing::Util

#args_for_editor, #deep_merge_hashes, #deep_merge_hashes!, #default_editor, #duplicable?, #duplicate_frozen_values, #editor_with_args, #exec_available, #find_default_editor, #first_available_exec, #mergable?, #merge_default_proc, #merge_values, #safe_load_file, #user_home, #write_to_file

Instance Method Details

#last_backup(filename = nil, count: 1) ⇒ String

Retrieve the most recent backup

Parameters:

  • filename (defaults to: nil)

    The filename

Returns:



33
34
35
36
37
38
# File 'lib/doing/util_backup.rb', line 33

def last_backup(filename = nil, count: 1)
  filename ||= Doing.setting('doing_file')

  backup = get_backups(filename).slice(count - 1)
  backup.nil? ? nil : File.join(backup_dir, backup)
end

#prune_backups(filename, limit = 10) ⇒ Object

Delete all but most recent 5 backups

Parameters:

  • limit (defaults to: 10)

    Maximum number of backups to retain



16
17
18
19
20
21
22
23
24
25
# File 'lib/doing/util_backup.rb', line 16

def prune_backups(filename, limit = 10)
  backups = get_backups(filename)
  return unless backups.count > limit

  backups[limit..-1].each do |file|
    FileUtils.rm(File.join(backup_dir, file))
  end

  clear_redo(filename)
end

#redo_backup(filename = nil, count: 1) ⇒ Object

Undo last undo

Parameters:

  • filename (defaults to: nil)

    The filename

Raises:

  • (HistoryLimitError)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/doing/util_backup.rb', line 67

def redo_backup(filename = nil, count: 1)
  filename ||= Doing.setting('doing_file')

  undones = Dir.glob("undone*#{File.basename(filename)}", base: backup_dir).sort.reverse
  total = undones.count
  count = total if count > total

  skipped = undones.slice!(0, count)
  undone = skipped.pop

  raise HistoryLimitError, 'End of redo history' if undone.nil?

  redo_file = File.join(backup_dir, undone)

  move_backup(redo_file, filename)

  skipped.each do |f|
    FileUtils.mv(File.join(backup_dir, f), File.join(backup_dir, f.sub(/^undone/, '')))
  end

  Doing.logger.warn('File update:', "restored undo step #{count}/#{total}")
  Doing.logger.debug('Backup:', "#{total - skipped.count - 1} redos remaining")
end

#restore_last_backup(filename = nil, count: 1) ⇒ Object

Restore the most recent backup. If a filename is provided, only backups of that filename will be used.

Parameters:

  • filename (defaults to: nil)

    The filename to restore, if different from default

Raises:

  • (HistoryLimitError)


47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/doing/util_backup.rb', line 47

def restore_last_backup(filename = nil, count: 1)
  Doing.logger.benchmark(:restore_backup, :start)
  filename ||= Doing.setting('doing_file')

  backup_file = last_backup(filename, count: count)
  raise HistoryLimitError, 'End of undo history' if backup_file.nil?

  save_undone(filename)
  move_backup(backup_file, filename)

  prune_backups_after(File.basename(backup_file))
  Doing.logger.warn('File update:', "restored from #{backup_file}")
  Doing.logger.benchmark(:restore_backup, :finish)
end

#select_backup(filename = nil) ⇒ Object

Select from recent backups. If a filename is provided, only backups of that filename will be used.

Parameters:

  • filename (defaults to: nil)

    The filename to restore

Raises:

  • (MissingBackupFile)


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/doing/util_backup.rb', line 135

def select_backup(filename = nil)
  filename ||= Doing.setting('doing_file')

  options = get_backups(filename).each_with_object([]) do |file, arr|
    d, _base = date_of_backup(file)
    next if d.nil?
    arr.push("#{d.time_ago}\t#{File.join(backup_dir, file)}")
  end

  raise MissingBackupFile, 'No backup files to load' if options.empty?

  backup_file = show_menu(options, filename)
  Util.write_to_file(File.join(backup_dir, "undone___#{File.basename(filename)}"), IO.read(filename), backup: false)
  move_backup(backup_file, filename)
  prune_backups_after(File.basename(backup_file))
  Doing.logger.warn('File update:', "restored from #{backup_file}")
end

#select_redo(filename = nil) ⇒ Object

Select from recent undos. If a filename is provided, only backups of that filename will be used.

Parameters:

  • filename (defaults to: nil)

    The filename to restore

Raises:

  • (HistoryLimitError)


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/doing/util_backup.rb', line 97

def select_redo(filename = nil)
  filename ||= Doing.setting('doing_file')

  undones = Dir.glob("undone*#{File.basename(filename)}", base: backup_dir).sort
  raise HistoryLimitError, 'End of redo history' if undones.empty?

  total = undones.count
  options = undones.each_with_object([]) do |file, arr|
    d, _base = date_of_backup(file)
    next if d.nil?

    arr.push("#{d.time_ago}\t#{File.join(backup_dir, file)}")
  end
  raise MissingBackupFile, 'No backup files to load' if options.empty?

  backup_file = show_menu(options, filename)
  idx = undones.index(File.basename(backup_file))
  skipped = undones.slice!(idx, undones.count - idx)
  undone = skipped.shift

  redo_file = File.join(backup_dir, undone)

  move_backup(redo_file, filename)

  skipped.each do |f|
    FileUtils.mv(File.join(backup_dir, f), File.join(backup_dir, f.sub(/^undone/, '')))
  end

  Doing.logger.warn('File update:', "restored undo step #{idx}/#{total}")
  Doing.logger.debug('Backup:', "#{total - skipped.count - 1} redos remaining")
end

#write_backup(filename = nil) ⇒ Object

Writes a copy of the content to a dated backup file in a hidden directory

Parameters:

  • filename (String) (defaults to: nil)

    The filename



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/doing/util_backup.rb', line 159

def write_backup(filename = nil)
  Doing.logger.benchmark(:_write_backup, :start)
  filename ||= Doing.setting('doing_file')

  unless File.exist?(filename)
    Doing.logger.debug('Backup:', "original file doesn't exist (#{filename})")
    return
  end

  backup_file = File.join(backup_dir, "#{timestamp_filename}___#{File.basename(filename)}")
  # compressed = Zlib::Deflate.deflate(content)
  # Zlib::GzipWriter.open(backup_file + '.gz') do |gz|
  #   gz.write(IO.read(filename))
  # end

  FileUtils.cp(filename, backup_file)

  prune_backups(filename, Doing.setting('history_size').to_i)
  clear_undone(filename)
  Doing.logger.benchmark(:_write_backup, :finish)
end