glittergallery/GlitterGallery

View on GitHub
lib/gg/sync.rb

Summary

Maintainability
A
45 mins
Test Coverage
# used to sync satellite and bare repo after push
# triggerd by api call from post-recieve
module Gg
  class Sync

    attr_reader :changes, :repo_path

    def initialize(repo_path, changes)
      @repo_path = repo_path
      @changes = changes
    end

    def sync_satellite
      refs = @changes.split(' ')
      branch = refs.last.split('/').last
      update_working_dir(@repo_path, branch)
      old_sha = refs.first
      new_sha = refs.second
      generate_images_between(old_sha, new_sha, branch)
    end

    # working dir or satellite folder needs to be in sync with bare repo
    # path is used to find the user and project
    # branch is used to get context of branch to sync
    def update_working_dir(path, branch)
      # path is of form username/project_name
      ids = path.split('/')
      project_owner = User.find_by(username: ids.first.to_s.downcase)
      @project = Project.with_deleted.find_by user_id: project_owner.id,
                                              name: ids.last.to_s.downcase

      # update of username/project/satellite with rugged
      @sat_repo = @project.satelliterepo
      bare_remote = @project.satelliterepo.remotes['bare']
      bare_remote = @sat_repo.remotes.create 'bare', @project.barerepo.path unless bare_remote
      # fetch from the bare remote
      bare_remote.fetch
      remote_branch = @sat_repo.branches["refs/remotes/bare/#{branch}"]
      local_branch = @sat_repo.branches["#{branch}"]
      local_branch = @sat_repo
        .create_branch("#{branch}", "remotes/bare/#{branch}") unless local_branch

      # checkout the branch, sync the refs and force checkout head to keep
      # working dir clean
      @sat_repo.checkout local_branch.name
      @sat_repo.references.update(@sat_repo.head.resolve, remote_branch.target_id)
      @sat_repo.checkout local_branch.name, strategy: :force
    end

    # find all the commits between old_sha and new_sha
    # pass each commit and parent pair to generate the thumbnail
    # pass the head after push for new inspire image if push branch is master
    def generate_images_between(old_sha, new_sha, branch)
      head = @sat_repo.lookup("#{new_sha}")
      # tails won't exist if previously repo was empty
      tail = @sat_repo.lookup("#{old_sha}") unless old_sha[0..5] == '000000'
      walker = Rugged::Walker.new(@sat_repo)
      walker.push(head)
      walker.hide(tail) unless old_sha[0..5] == '000000'
      # find diff for each parent child pair
      walker.each do |commit|
        # very first commit has no parent
        if commit.parents.empty?
          generate_for('thumbnail', commit, nil)
        else
          commit.parents.each do|p|
            generate_for('thumbnail', commit, p)
          end
        end
      end
      generate_for('inspire', head, head.parents.first) if branch == 'master'
    end

    # generates thumnail and inspire images from the last diff delta path
    # parent has to be a commit and not an array
    def generate_for(type, child, parent)
      diff =  child.diff(parent)
      path = diff.deltas.last.new_file[:path]
      case type
      when 'thumbnail'
        @project.generate_thumbnail path, child.oid
      when 'inspire'
        @project.generate_inspire_image path
      end
    end
  end
end