Skip to content

Instantly share code, notes, and snippets.

@Folling
Created January 31, 2024 19:33
Show Gist options
  • Save Folling/7c9c35588becd69c7c6fa8d9c880e837 to your computer and use it in GitHub Desktop.
Save Folling/7c9c35588becd69c7c6fa8d9c880e837 to your computer and use it in GitHub Desktop.
restic-append-only-backup
#!/usr/bin/env ruby
require 'date'
require 'json'
require 'open3'
File.readlines(".env", chomp: true).select { !_1.start_with?('#') && !_1.strip.empty? }.each {
k, v =_1.strip.split('=')
ENV[k] = v
}
raise 'must set REMOTE env var' unless remote = ENV["REMOTE"]
raise 'must set REPOSITORY env var' unless repo = ENV["REPOSITORY"]
raise 'must set RESTIC_COMPRESSION env var' unless compression = ENV["RESTIC_COMPRESSION"]
script = "restic backup --compression=#{compression} -r #{remote}/#{repo} --exclude-file=exclude --files-from=include"
puts "running dry-run to see if changes occurred";
output = ""
begin
Open3.popen3(ENV, "#{script} --quiet --json --dry-run") { |i, o, e, t|
output = o.read
puts "dry run yielded: #{output}"
raise "dry run failed with #{t.value} #{e.read}" unless t.value.success?
}
rescue => e
raise "unable to run dry run: #{e}"
end
begin
output_json = JSON.parse(output);
rescue JSON::ParserError => e
raise "result from dry run couldn't be parsed to JSON: #{e}"
end
raise "output didn't contain 'files_new'" unless new_files = output_json["files_new"]
raise "output didn't contain 'files_changed'" unless changed_files = output_json["files_changed"]
raise "output didn't contain 'dirs_new'" unless new_dirs = output_json["dirs_new"]
raise "output didn't contain 'dirs_changed'" unless changed_dirs = output_json["dirs_changed"]
total_changes = new_files + changed_files + new_dirs + changed_dirs
puts "total changes: #{total_changes}"
if total_changes == 0 then
puts "no changes detected, not creating snapshot"
return
end
puts "detected changes, running backup"
begin
Open3.popen3(ENV, "#{script}") { |i, o, e, t|
output = o.read
puts "run yielded: #{output}"
raise "restic backup failed with #{t.value}" unless t.value.success?
}
rescue => e
raise "unable to run backup: #{e}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment