class Gollum::Git::Git

Public Class Methods

new(repo) click to toggle source

Rugged does not have a Git class, but the Repository class should allows us to do what's necessary.

# File lib/rugged_adapter/git_layer_rugged.rb, line 152
def initialize(repo)
  @repo = repo
end

Public Instance Methods

apply_patch(head_sha = 'HEAD', patch=nil) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 188
def apply_patch(head_sha = 'HEAD', patch=nil)
  false # Rewrite gollum-lib's revert so that it doesn't require a direct equivalent of Grit's apply_patch
end
cat_file(options, sha) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 184
def cat_file(options, sha)
  @repo.lookup(sha).read_raw
end
checkout(path, ref = 'HEAD', options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 197
def checkout(path, ref = 'HEAD', options = {})
  path = path.nil? ? path : [path]
  options = options.merge({:paths => path, :strategy => :force})
  if ref == 'HEAD'
    @repo.checkout_head(options)
  else
    ref = "refs/heads/#{ref}" unless ref =~ /^refs\/heads\//
    @repo.checkout_tree(sha_from_ref(ref), options)
  end
end
commit_from_ref(ref) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 273
def commit_from_ref(ref)
  sha_or_commit_from_ref(ref, :commit)
end
exist?() click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 156
def exist?
  ::File.exists?(@repo.path)
end
grep(query, options={}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 160
def grep(query, options={})
  ref = options[:ref] ? options[:ref] : "HEAD"
  tree = @repo.lookup(sha_from_ref(ref)).tree
  tree = @repo.lookup(tree[options[:path]][:oid]) if options[:path]
  results = []
  tree.walk_blobs(:postorder) do |root, entry|
    blob = @repo.lookup(entry[:oid])
    count = 0
    blob.content.each_line do |line|
      next unless line.force_encoding("UTF-8").match(/#{Regexp.escape(query)}/i)
      count += 1
    end
    path = options[:path] ? ::File.join(options[:path], root, entry[:name]) : "#{root}#{entry[:name]}"
    results << {:name => path, :count => count} unless count == 0
  end
  results
end
log(ref = 'refs/heads/master', path = nil, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 208
def log(ref = 'refs/heads/master', path = nil, options = {})
  default_options = {
    :limit => options[:max_count] ? options[:max_count] : 10,
    :offset => options[:skip] ? options[:skip] : 0,
    :path => path,
    :follow => false,
    :skip_merges => false
  }
  options = default_options.merge(options)
  options[:limit] ||= 0
  options[:offset] ||= 0
  sha = sha_from_ref(ref)
  return [] if sha.nil?
  begin
    build_log(sha, options)
  rescue Rugged::OdbError, Rugged::InvalidError, Rugged::ReferenceError
  # Return an empty array if the ref wasn't found
    []
  end
end
lookup(id) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 246
def lookup(id)
  @repo.lookup(id)
end
ls_files(query, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 233
def ls_files(query, options = {})
  ref = options[:ref] || "refs/heads/master"
  tree = @repo.lookup(sha_from_ref(ref)).tree
  tree = @repo.lookup(tree[options[:path]][:oid]) if options[:path]
  results = []
  tree.walk_blobs do |root, blob|
    next unless blob[:name] =~ /#{query}/
    path = options[:path] ? ::File.join(options[:path], root, blob[:name]) : "#{root}#{blob[:name]}"
    results << path
  end
  results
end
pull(remote, branches = nil, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 282
def pull(remote, branches = nil, options = {})
  branches = [branches].flatten.map {|branch| "refs/heads/#{branch}" unless branch =~ /^refs\/heads\//}
  r = @repo.remotes[remote]
  r.fetch(branches, options)
  branches.each do |branch|
    branch_name = branch.match(/^refs\/heads\/(.*)/)[1]
    remote_name = remote.match(/^(refs\/heads\/)?(.*)/)[2]
    remote_ref = @repo.branches["#{remote_name}/#{branch_name}"].target
    local_ref = @repo.branches[branch].target
    index = @repo.merge_commits(local_ref, remote_ref)
    options = { author: Actor.default_actor.to_h,
      committer:  Actor.default_actor.to_h,
      message:    "Merged branch #{branch} of #{remote}.",
      parents: [local_ref, remote_ref],
      tree: index.write_tree(@repo),
      update_ref: branch
    }
    Rugged::Commit.create @repo, options
    @repo.checkout(@repo.head.name, :strategy => :force) if !@repo.bare? && branch == @repo.head.name
  end
end
push(remote, branches = nil, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 277
def push(remote, branches = nil, options = {})
  branches = [branches].flatten.map {|branch| "refs/heads/#{branch}" unless branch =~ /^refs\/heads\//}
  @repo.push(remote, branches, options)
end
ref_to_sha(query) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 250
def ref_to_sha(query)
  return query if sha?(query)
  query = "refs/heads/#{query}" if !query.nil? && !(query =~ /^refs\/heads\//) && !(query == "HEAD")
  begin
    return @repo.rev_parse_oid(query)
  rescue Rugged::ReferenceError, Rugged::InvalidError
    return nil
  end
end
revert(path, sha1, sha2, ref) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 192
def revert(path, sha1, sha2, ref)
  # FIXME: See https://github.com/gollum/grit_adapter/pull/14
  fail NotImplementedError
end
rm(path, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 178
def rm(path, options = {})
  index = @repo.index
  index.write
  ::File.unlink ::File.join(@repo.workdir, path)
end
sha_from_ref(ref, request_kind = nil)
sha_or_commit_from_ref(ref, request_kind = nil) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 260
def sha_or_commit_from_ref(ref, request_kind = nil)
  sha = ref_to_sha(ref)
  return nil if sha.nil?
  object = @repo.lookup(sha)
  if object.kind_of?(Rugged::Commit) then
    return Gollum::Git::Commit.new(object) if request_kind == :commit
    sha
  elsif object.respond_to?(:target)
    sha_or_commit_from_ref(object.target.oid, request_kind)
  end
end
Also aliased as: sha_from_ref
versions_for_path(path = nil, ref = nil, options = {}) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 229
def versions_for_path(path = nil, ref = nil, options = {})
  log(ref, path, options)
end

Private Instance Methods

build_log(sha, options) click to toggle source

Return an array of log commits, given an SHA hash and a hash of options. From Gitlab::Git

# File lib/rugged_adapter/git_layer_rugged.rb, line 312
def build_log(sha, options)
  # Instantiate a Walker and add the SHA hash
  walker = Rugged::Walker.new(@repo)
  walker.push(sha)
  commits = []
  skipped = 0
  current_path = options[:path]
  current_path = nil if current_path == ''
  limit = options[:limit].to_i
  offset = options[:offset].to_i
  skip_merges = options[:skip_merges]
  walker.sorting(Rugged::SORT_DATE)

    walker.each do |c|
      break if limit > 0 && commits.length >= limit
        if skip_merges
          # Skip merge commits
          next if c.parents.length > 1
        end

        if !current_path ||
          commit_touches_path?(c, current_path, options[:follow], walker)
          # This is a commit we care about, unless we haven't skipped enough
          # yet
          skipped += 1
          commits.push(Gollum::Git::Commit.new(c)) if skipped > offset
        end
    end
  walker.reset
  commits
end
commit_touches_path?(commit, path, follow, walker) click to toggle source

Returns true if commit introduced changes to path, using commit trees to make that determination. Uses the history simplification rules that `git log` uses by default, where a commit is omitted if it is TREESAME to any parent.

If the follow option is true and the file specified by path was renamed, then the path value is set to the old path.

# File lib/rugged_adapter/git_layer_rugged.rb, line 351
def commit_touches_path?(commit, path, follow, walker)
  entry = tree_entry(commit, path)

    if commit.parents.empty?
      # This is the root commit, return true if it has +path+ in its tree
      return entry != nil
    end

  num_treesame = 0
  commit.parents.each do |parent|
    parent_entry = tree_entry(parent, path)

    # Only follow the first TREESAME parent for merge commits
    if num_treesame > 0
      walker.hide(parent)
      next
    end

    if entry.nil? && parent_entry.nil?
      num_treesame += 1
    elsif entry && parent_entry && entry[:oid] == parent_entry[:oid]
      num_treesame += 1
    end
  end

  case num_treesame
    when 0
      detect_rename(commit, commit.parents.first, path) if follow
      true
    else false
  end
end
detect_rename(commit, parent, path) click to toggle source

Compare commit and parent for path. If path is a file and was renamed in commit, then set path to the old filename.

# File lib/rugged_adapter/git_layer_rugged.rb, line 403
def detect_rename(commit, parent, path)
  diff = parent.diff(commit, paths: [path], disable_pathspec_match: true)

  # If +path+ is a filename, not a directory, then we should only have
  # one delta. We don't need to follow renames for directories.
  return nil if diff.each_delta.count > 1

  delta = diff.each_delta.first
  if delta.added?
    full_diff = parent.diff(commit)
    full_diff.find_similar!

    full_diff.each_delta do |full_delta|
      if full_delta.renamed? && path == full_delta.new_file[:path]
        # Look for the old path in ancestors
        path.replace(full_delta.old_file[:path])
      end
    end
  end
end
sha?(str) click to toggle source
# File lib/rugged_adapter/git_layer_rugged.rb, line 306
def sha?(str)
  !!(str =~ /^[0-9a-f]{40}$/)
end
tree_entry(commit, path) click to toggle source

Find the entry for path in the tree for commit

# File lib/rugged_adapter/git_layer_rugged.rb, line 385
def tree_entry(commit, path)
  pathname = Pathname.new(path)
  tmp_entry = nil

  pathname.each_filename do |dir|
    tmp_entry = if tmp_entry.nil?
                  commit.tree[dir]
                else
                  @repo.lookup(tmp_entry[:oid])[dir]
                end

    return nil unless tmp_entry
  end
  tmp_entry
end