class GRSync::Syncer

Public Class Methods

new(ssh, local_path, remote_path) click to toggle source
  • ssh - ssh object used for issuing commands

  • local_path - source of the sync link which should be a path of a directory on local machine

  • remote_path - destination of the sync link which should be a path of a directory on remote machine

# File lib/grsync.rb, line 9
def initialize(ssh, local_path, remote_path)
    @ssh = ssh
    @local_path = local_path # existence should be checked before
    @remote_path = remote_path # existence remains to be checked
end

Public Instance Methods

sync() click to toggle source

sync remote git repository with the local one

# File lib/grsync.rb, line 16
def sync
    # preparation
    check_remote_path_valid
    check_git_repo
    reset_remote_repo

    diff_text = local_diff
    apply_diff_to_remote diff_text

    # output = @ssh.exec! 'hostname'
    # puts output
end

Private Instance Methods

apply_diff_to_remote(diff_text) click to toggle source
# File lib/grsync.rb, line 41
def apply_diff_to_remote(diff_text)
    # remove trailing spaces from diff text
    # very important because trailing spaces would cause git apply failure
    no_trailing_diff_text = []
    diff_text.split("\n").each{|line| no_trailing_diff_text << line.rstrip }

    # be careful, string in ruby may not be used safely in shell directly
    # so here's a conversion
    echoable_text = Shellwords.escape no_trailing_diff_text.join("\n")

    result = @ssh.exec! "cd #{@remote_path} && (echo #{echoable_text} | git apply -)"
    # diff fails if something other than empty string returns
    raise GitDiffApplyException, "Apply failed: #{result}" if result != ''
end
check_git_repo() click to toggle source

check the followings:

  1. whether both local and remote directory are git repositories

  2. whether their branches are matched

# File lib/grsync.rb, line 64
def check_git_repo
    # check local dir

    # use Open3 in order to get stderr output from child process
    # `` syntax only returns stdout output which is not enough

    # since command are all executed in newly spawned child processes so there's no need to record old dir path
    stdout, stderr = Open3.popen3("cd #{@local_path} && git status")[1..2]

    local_branch_name = stdout.gets.to_s.match(/^On branch ([^\s]+)/)[1]
    unless local_branch_name
        raise GitRepoException, "local path #{@local_path} is not a git repository"
    end

    # check remote dir
    valid = true
    remote_branch_name = ''
    @ssh.exec!("cd #{@remote_path} && git status") do |ch, stream, data|
        case stream
            when :stdout
                valid = false unless (remote_branch_name = data.match(/^On branch ([^\s]+)/)[1])
            when :stderr
                valid = false unless (data.nil? or data == '')
        end
    end
    unless valid
        raise GitRepoException, "remote path #{@remote_path} is not a git repository"
    end

    # check match
    if local_branch_name != remote_branch_name
        raise GitRepoException, "local branch(#{local_branch_name}) and remote branch(#{remote_branch_name}) don't match"
    end
end
check_remote_path_valid() click to toggle source

check whether the remote path is valid

# File lib/grsync.rb, line 100
def check_remote_path_valid
    @ssh.exec!("ls #{@remote_path}") do |ch, stream, data|
        if stream == :stderr and not data.nil?
            raise RemotePathInvalidException, "remote path #{@remote_path} not found"
        end
    end
end
local_diff() click to toggle source

diff the local git repository and returns the diff text for later use

# File lib/grsync.rb, line 57
def local_diff
    `cd #{@local_path} && git diff HEAD`
end
reset_remote_repo() click to toggle source

checkout all files from HEAD to flush all changes made in remote repo thus new git apply can be applied safely :)

# File lib/grsync.rb, line 33
def reset_remote_repo
    @ssh.exec! "cd #{@remote_path} && git reset --hard" do |ch, stream, data|
        if stream == :stderr and data.to_s != '' # check for nil or ''
            raise GitResetException, "Reset failed: #{data}"
        end
    end
end