Crashplan, wut?
class BackedUpFile | |
PARSING_REGEX = /(?<status>[IW]) (?<date>\d\d\/\d\d\/\d\d) (?<time>\d\d:\d\d[AP]M) (?<some_num>\d+) (?<hash>\w+) (?<other_num>\d+) (?<filename>.*) \((?<size>\d+)\) \[(?<flags>[\d\,]+)\]/ | |
def self.from(line) | |
return unless match_data = PARSING_REGEX.match(line) | |
result = match_data.names.inject({}) do |memo, name| | |
if name == 'flags' | |
memo[:flags] = match_data[name.to_sym].split(',') | |
else | |
memo[name.to_sym] = match_data[name.to_sym] | |
end | |
memo | |
end | |
date = result.delete :date | |
time = result.delete :time | |
result[:datetime] = DateTime.strptime "#{date} #{time}", "%m/%d/%y %I:%M%p" | |
self.new result | |
rescue => e | |
puts e.inspect | |
puts "SKIP: #{line}" | |
end | |
attr_reader :params | |
delegate *%i{status datetime some_num hash other_num filename size flags}, to: :params | |
def initialize(params) | |
@params = OpenStruct.new(params) | |
end | |
def real_path | |
# TODO: Top-level config constant or somethin: | |
filename.gsub("/data", "/Volumes") | |
end | |
def missing? | |
!File.exist? real_path | |
end | |
def size_mismatch? | |
size.to_i != local_size | |
end | |
def local_size | |
File.size real_path | |
end | |
end |
class BackedUpFiles | |
attr_accessor :backed_up_files, :log_files, :missing_files, :unsized_files | |
delegate :count, to: :backed_up_files | |
def initialize(log_files) | |
@backed_up_files = {} | |
@log_files = log_files | |
@missing_files = [] | |
@unsized_files = [] | |
end | |
SKIP_REGEX = /\/\.\_|appdata|data\/apps|sparsebundle|DS_store/i | |
def load_logs! | |
log_files.each do |file| | |
File.open(file).each_line { |line| handle line } | |
end | |
end | |
def check! | |
backed_up_files.each do |_, bf| | |
if bf.missing? | |
puts "MISSING: #{bf.inspect}" | |
missing_files << bf.filename | |
elsif bf.size_mismatch? | |
puts "SIZE: Local(#{bf.local_size}) / #{bf.inspect}" | |
unsized_files << bf.filename | |
else | |
next | |
end | |
end | |
end | |
def report! | |
File.open 'missing.log', 'a' do |f| | |
missing_files.each { |mf| f.write mf; f.write "\n" } | |
end | |
File.open 'unsized_files.log', 'a' do |f| | |
unsized_files.each { |uf| f.write uf; f.write "\n" } | |
end | |
end | |
private | |
def handle(line) | |
return if SKIP_REGEX =~ line | |
return unless file = BackedUpFile.from(line) | |
if existing = backed_up_files[file.filename] | |
return if existing.datetime > file.datetime | |
end | |
backed_up_files[file.filename] = file | |
end | |
end |
require 'set' | |
require 'ostruct' | |
require 'active_support' | |
require 'active_support/all' | |
require 'date' | |
require 'time' | |
require 'pry' | |
require_relative 'backed_up_file' | |
require_relative 'backed_up_files' | |
LOG_FILES = %w{backup_files.log.1 backup_files.log.0} | |
backed_up_files = BackedUpFiles.new LOG_FILES | |
puts "Loading files..." | |
backed_up_files.load_logs! | |
puts "Loading done - #{backed_up_files.count} files backed up on CrashPlan according to log." | |
backed_up_files.check! | |
puts "Check done, writing files" | |
backed_up_files.report! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment