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:



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

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



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

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

  backups[limit..].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)


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

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



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

def restore_last_backup(filename = nil, count: 1)
  Doing.logger.measure(:restore_backup) do
    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}")
  end
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)


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

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)


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
128
# File 'lib/doing/util_backup.rb', line 98

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



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

def write_backup(filename = nil)
  Doing.logger.measure(:_write_backup) do
    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)
  end
end