class Bdsync::Core
Attributes
data_path[R]
Public Class Methods
new(params, sync_type)
click to toggle source
# File lib/bdsync/core.rb, line 9 def initialize params, sync_type raise "local path not specified" if !params["local_root_path"] raise "remote path not specified" if !params["remote_root_path"] @local_root_path = params["local_root_path"] @remote_root_path = params["remote_root_path"] @infinite_loop = params["infinite_loop"] @data_path = "#{Dir.home}/.bdsync/#{sync_type}_#{Utils.md5 params.to_s}.yaml" end
options()
click to toggle source
# File lib/bdsync/core.rb, line 19 def self.options ["local_root_path:", "remote_root_path:", "infinite_loop"] end
Public Instance Methods
do_first_time_sync_from_local(relative_path, local_path, remote_path, remote, type)
click to toggle source
# File lib/bdsync/core.rb, line 192 def do_first_time_sync_from_local relative_path, local_path, remote_path, remote, type case type when :file if !remote remote = upload_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime elsif remote.directory? handle_remote_conflict remote_path remote = upload_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime else # compare file contents, conflict if not equal if !is_same_contents local_path, remote_path handle_remote_conflict remote_path remote = upload_file local_path, remote_path end update_file_data relative_path, local_path, remote.mtime end when :directory if !remote remote = remote_mkdir remote_path update_directory_data relative_path, local_path, remote.mtime elsif remote.directory? update_directory_data relative_path, local_path, remote.mtime else handle_remote_conflict remote_path remote = remote_mkdir remote_path update_directory_data relative_path, local_path, remote.mtime end end end
do_first_time_sync_from_remote(relative_path, local_path, remote_path, remote, type)
click to toggle source
# File lib/bdsync/core.rb, line 159 def do_first_time_sync_from_remote relative_path, local_path, remote_path, remote, type case type when :file if !File.exist? local_path download_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime elsif File.directory? local_path handle_local_conflict local_path download_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime else # compare file contents, conflict if not equal if !is_same_contents local_path, remote_path handle_local_conflict local_path download_file local_path, remote_path end update_file_data relative_path, local_path, remote.mtime end when :directory if !File.exist? local_path local_mkdir local_path update_directory_data relative_path, local_path, remote.mtime elsif File.directory? local_path update_directory_data relative_path, local_path, remote.mtime else handle_local_conflict local_path local_mkdir local_path update_directory_data relative_path, local_path, remote.mtime end end end
do_sync_from_local(relative_path, local_path, remote_path, remote, type, old)
click to toggle source
# File lib/bdsync/core.rb, line 312 def do_sync_from_local relative_path, local_path, remote_path, remote, type, old local_changed = (File.mtime(local_path).to_i - old[:local_mtime]) != 0 case type when :file if !remote if !local_changed local_remove_file local_path else handle_local_conflict local_path end elsif remote.directory? if !local_changed local_remove_file local_path local_mkdir local_path update_directory_data relative_path, local_path, remote.mtime else if File.mtime(local_path).to_i > remote.mtime handle_remote_conflict remote_path remote = upload_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime else handle_local_conflict local_path local_mkdir local_path update_directory_data relative_path, local_path, remote.mtime end end else remote_changed = (remote.mtime - old[:remote_mtime]) != 0 if !local_changed && !remote_changed @data[relative_path] = old elsif local_changed && !remote_changed remote = upload_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime elsif !local_changed && remote_changed download_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime else if File.mtime(local_path).to_i > remote.mtime # compare file contents, conflict if not equal if !is_same_contents local_path, remote_path handle_remote_conflict remote_path remote = upload_file local_path, remote_path end update_file_data relative_path, local_path, remote.mtime else # compare file contents, conflict if not equal if !is_same_contents local_path, remote_path handle_local_conflict local_path download_file local_path, remote_path end update_file_data relative_path, local_path, remote.mtime end end end when :directory if !remote if !local_changed local_remove_directory local_path else handle_local_conflict local_path end elsif remote.directory? update_directory_data relative_path, local_path, remote.mtime else if !local_changed local_remove_directory local_path download_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime else if File.mtime(local_path).to_i > remote.mtime handle_remote_conflict remote_path remote = remote_mkdir remote_path update_directory_data relative_path, local_path, remote.mtime else handle_local_conflict local_path download_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime end end end end end
do_sync_from_remote(relative_path, local_path, remote_path, remote, type, old)
click to toggle source
# File lib/bdsync/core.rb, line 225 def do_sync_from_remote relative_path, local_path, remote_path, remote, type, old remote_changed = (remote.mtime - old[:remote_mtime]) != 0 case type when :file if !File.exist? local_path if !remote_changed remote_remove_file remote_path else handle_remote_conflict remote_path end elsif File.directory? local_path if !remote_changed remote_remove_file remote_path remote = remote_mkdir remote_path update_directory_data relative_path, local_path, remote.mtime else if File.mtime(local_path).to_i > remote.mtime handle_remote_conflict remote_path remote = remote_mkdir remote_path update_directory_data relative_path, local_path, remote.mtime else handle_local_conflict local_path download_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime end end else local_changed = (File.mtime(local_path).to_i - old[:local_mtime]) != 0 if !local_changed && !remote_changed @data[relative_path] = old elsif local_changed && !remote_changed remote = upload_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime elsif !local_changed && remote_changed download_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime else if File.mtime(local_path).to_i > remote.mtime # compare file contents, conflict if not equal if !is_same_contents local_path, remote_path handle_remote_conflict remote_path remote = upload_file local_path, remote_path end update_file_data relative_path, local_path, remote.mtime else # compare file contents, conflict if not equal if !is_same_contents local_path, remote_path handle_local_conflict local_path download_file local_path, remote_path end update_file_data relative_path, local_path, remote.mtime end end end when :directory if !File.exist? local_path if !remote_changed remote_remove_dir remote_path else handle_remote_conflict remote_path end elsif File.directory? local_path update_directory_data relative_path, local_path, remote.mtime else if !remote_changed remote_remove_dir remote_path remote = upload_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime else if File.mtime(local_path).to_i > remote.mtime handle_remote_conflict remote_path remote = upload_file local_path, remote_path update_file_data relative_path, local_path, remote.mtime else handle_local_conflict local_path local_mkdir local_path update_directory_data relative_path, local_path, remote.mtime end end end end end
handle_local_conflict(local_path)
click to toggle source
# File lib/bdsync/core.rb, line 415 def handle_local_conflict local_path ts = Utils.timestamp local_conflict_path = local_path.sub(@local_root_path, "#{@local_root_path}/.conflict") + "." + ts local_ensure_parent local_conflict_path local_rename local_path, local_conflict_path end
handle_local_entry(path, type)
click to toggle source
# File lib/bdsync/core.rb, line 139 def handle_local_entry path, type puts "#{'%9s' % type}: #{path}".green # NOTE: force_encoding to output readable japanese text relative_path = path.sub(@local_root_path + "/", "").force_encoding("UTF-8") local_path = "#{@local_root_path}/#{relative_path}" remote_path = "#{@remote_root_path}/#{relative_path}" remote = remote_get_object remote_path old = @old_data[relative_path] if !old # no old sync record do_first_time_sync_from_local relative_path, local_path, remote_path, remote, type else # old sync record found do_sync_from_local relative_path, local_path, remote_path, remote, type, old end end
handle_remote_conflict(remote_path)
click to toggle source
# File lib/bdsync/core.rb, line 423 def handle_remote_conflict remote_path ts = Utils.timestamp remote_conflict_path = remote_path.sub(@remote_root_path, "#{@remote_root_path}/.conflict") + "." + ts remote_ensure_parent remote_conflict_path remote_rename remote_path, remote_conflict_path end
handle_remote_entry(remote, path, type)
click to toggle source
# File lib/bdsync/core.rb, line 121 def handle_remote_entry remote, path, type puts "#{'%9s' % type}: #{path}".green # NOTE: force_encoding to output readable japanese text relative_path = path.sub(@remote_root_path + "/", "").force_encoding("UTF-8") local_path = "#{@local_root_path}/#{relative_path}" remote_path = "#{@remote_root_path}/#{relative_path}" old = @old_data[relative_path] if !old # no old sync record do_first_time_sync_from_remote relative_path, local_path, remote_path, remote, type else # old sync record found do_sync_from_remote relative_path, local_path, remote_path, remote, type, old end end
is_same_contents(local_path, remote_path)
click to toggle source
# File lib/bdsync/core.rb, line 459 def is_same_contents local_path, remote_path local_file_md5 = Utils.file_md5 local_path remote_file_md5 = get_remote_file_md5 remote_path local_file_md5 == remote_file_md5 end
load_data()
click to toggle source
# File lib/bdsync/core.rb, line 53 def load_data puts "\nload #{@data_path}" YAML.load_file @data_path rescue Errno::ENOENT {} end
local_ensure_dir(path)
click to toggle source
# File lib/bdsync/core.rb, line 451 def local_ensure_dir path FileUtils.mkdir_p path if !File.directory? path end
local_ensure_parent(path)
click to toggle source
# File lib/bdsync/core.rb, line 455 def local_ensure_parent path local_ensure_dir File.dirname path end
local_mkdir(local_path)
click to toggle source
# File lib/bdsync/core.rb, line 431 def local_mkdir local_path puts "#{Utils.caller_info 1} mkdir_p #{local_path}".white FileUtils.mkdir_p local_path end
local_remove_directory(local_path)
click to toggle source
# File lib/bdsync/core.rb, line 441 def local_remove_directory local_path puts "#{Utils.caller_info 1} rm_rf #{local_path}".white FileUtils.rm_rf local_path end
local_remove_file(local_path)
click to toggle source
# File lib/bdsync/core.rb, line 436 def local_remove_file local_path puts "#{Utils.caller_info 1} rm #{local_path}".white FileUtils.rm local_path end
local_rename(local_path, new_local_path)
click to toggle source
# File lib/bdsync/core.rb, line 446 def local_rename local_path, new_local_path puts "#{Utils.caller_info 1} mv #{local_path} #{new_local_path}".yellow FileUtils.mv local_path, new_local_path end
save_data(data)
click to toggle source
# File lib/bdsync/core.rb, line 60 def save_data data local_ensure_parent @data_path File.write @data_path, data.to_yaml puts "\nsaved to #{@data_path}" end
synchronize()
click to toggle source
# File lib/bdsync/core.rb, line 23 def synchronize # Run only one instance of a Ruby program at the same time - self locking # SEE: https://code-maven.com/run-only-one-instance-of-a-script Utils.try_lock { loop { @old_data = load_data @data = {} remote_ensure_dir @remote_root_path local_ensure_dir @local_root_path puts "\n==== traverse_remote_path ====" traverse_remote_path @remote_root_path # merge @data to @old_data, and clear @data @old_data.merge! @data @data = {} puts "\n==== traverse_local_path ====" traverse_local_path @local_root_path save_data @data break if !@infinite_loop sleep 1 } } end
traverse_local_path(local_path)
click to toggle source
# File lib/bdsync/core.rb, line 95 def traverse_local_path local_path next_level_dirs = [] Dir.foreach(local_path) { |entry_name| next if [".", "..", ".conflict"].include? entry_name path = "#{local_path}/#{entry_name}" if File.directory? path next_level_dirs << path else handle_local_entry path, :file end } next_level_dirs.sort.each { |path| handle_local_entry path, :directory begin traverse_local_path path rescue Errno::ENOENT # OK: the local directory may be deleted with synchronization! end } end
traverse_remote_path(remote_path)
click to toggle source
# File lib/bdsync/core.rb, line 66 def traverse_remote_path remote_path next_level_dirs = [] remote_dir_foreach(remote_path) { |entry| next if [".", "..", ".conflict"].include? entry.name path = "#{remote_path}/#{entry.name}" remote = entry.attributes if remote.directory? next_level_dirs << [path, remote] else handle_remote_entry remote, path, :file end } next_level_dirs.sort.each { |path, remote| handle_remote_entry remote, path, :directory begin traverse_remote_path path rescue Net::SFTP::StatusException # OK: the remote directory may be deleted with synchronization! rescue Errno::ENOENT # OK: the remote directory may be deleted with synchronization! end } end
update_directory_data(relative_path, local_path, remote_mtime)
click to toggle source
# File lib/bdsync/core.rb, line 407 def update_directory_data relative_path, local_path, remote_mtime @data[relative_path] = { type: :directory, remote_mtime: remote_mtime, local_mtime: File.mtime(local_path).to_i } end
update_file_data(relative_path, local_path, remote_mtime)
click to toggle source
# File lib/bdsync/core.rb, line 399 def update_file_data relative_path, local_path, remote_mtime @data[relative_path] = { type: :file, remote_mtime: remote_mtime, local_mtime: File.mtime(local_path).to_i } end