class Armature::Repo::Git

Public Class Methods

from_url(cache, url) click to toggle source

Gets a repo object for a given URL. Mirrors the repo in the local cache if it doesn't already exist.

# File lib/armature/repo/git.rb, line 4
def self.from_url(cache, url)
  repo = cache.get_repo("git", url)
  if repo
    return repo
  end

  fresh = false
  repo_dir = cache.open_repo("git", url) do |temp_path|
    Logging.logger[self].debug("Cloning '#{url}' for the first time")

    # Mirror copies *all* refs, not just branches. Ignore output.
    Armature::Run.clean_git("clone", "--quiet", "--mirror", url, temp_path)
    fresh = true

    Logging.logger[self].debug("Done cloning '#{url}'")
  end

  return self.new(cache, repo_dir, fresh)
end
new(cache, repo_dir, is_fresh=false) click to toggle source
Calls superclass method Armature::Repo::new
# File lib/armature/repo/git.rb, line 24
def initialize(cache, repo_dir, is_fresh=false)
  super(cache, repo_dir)
  @fresh = is_fresh
end

Public Instance Methods

_branch_ref(ref_str, name, sha) click to toggle source
# File lib/armature/repo/git.rb, line 141
def _branch_ref(ref_str, name, sha)
  make_ref(Armature::Ref::Mutable, ref_str, sha, "branch", name)
  @ref_cache[name] = @ref_cache[ref_str]
end
branch_ref(name) click to toggle source
# File lib/armature/repo/git.rb, line 131
def branch_ref(name)
  ref_str = "refs/heads/#{name}"
  freshen()

  return @ref_cache[ref_str] if @ref_cache[ref_str]

  sha = rev_parse!(ref_str)
  _branch_ref(ref_str, name, sha)
end
check_out(ref) click to toggle source

Check out a ref from a repo and return the path

# File lib/armature/repo/git.rb, line 34
def check_out(ref)
  @cache.open_ref(ref) do |object_path|
    git "reset", "--hard", ref.identity, :work_dir=>object_path
  end
end
flush_memory!() click to toggle source
# File lib/armature/repo/git.rb, line 51
def flush_memory!
  @fresh = false
  @ref_cache = {}
  @rev_cache = {}
end
freshen!() click to toggle source
# File lib/armature/repo/git.rb, line 40
def freshen!
  flush_memory!

  @logger.info("Fetching from #{url}")
  Armature::Util::lock(@repo_dir, File::LOCK_EX, "fetch") do
    ### FIXME Only flush memory if this makes changes
    git "remote", "update", "--prune"
  end
  @fresh = true
end
general_ref(ref_str) click to toggle source

Get ref object

# File lib/armature/repo/git.rb, line 58
def general_ref(ref_str)
  return @ref_cache[ref_str] if @ref_cache[ref_str]

  if ref_str.start_with? "refs/heads/"
    return branch_ref(ref_str.sub("refs/heads/", ""))
  end

  if ref_str.start_with? "refs/tags/"
    return tag_ref(ref_str.sub("refs/tags/", ""))
  end

  retry_fresh do
    if ref_str.start_with? "refs/"
      freshen()
      return make_ref(Armature::Ref::Mutable, ref_str, rev_parse!(ref_str),
        "ref", ref_str)
    end

    if sha = rev_parse("refs/heads/#{ref_str}")
      return branch_ref(ref_str)
    end

    if sha = rev_parse("refs/tags/#{ref_str}")
      return tag_ref(ref_str)
    end

    # This could trigger a retry
    sha = rev_parse!(ref_str)
    if sha_match? sha, ref_str
      return identity_ref(sha)
    end

    # It exists, but it's outside of refs/. Treat it as mutable.
    make_ref(Armature::Ref::Mutable, ref_str, sha, "ref", ref_str)
  end
end
get_branches() click to toggle source
# File lib/armature/repo/git.rb, line 173
def get_branches()
  freshen()
  data = git("for-each-ref",
    "--format", "%(objectname) %(refname)",
    "refs/heads")
  lines = data.split(/[\r\n]/).reject { |line| line == "" }

  lines.map do |line|
    sha, ref_str = line.split(' ', 2)
    name = ref_str.sub("refs/heads/", "")
    _branch_ref(ref_str, name, sha)
    name
  end
end
git(*arguments) click to toggle source
# File lib/armature/repo/git.rb, line 155
def git(*arguments)
  # This accepts a hash of options as the last argument
  options = if arguments.last.is_a? Hash then arguments.pop else {} end
  options = Armature::Util.process_options(options, { :work_dir => nil }, {})

  if options[:work_dir]
    work_dir_arguments = [ "--work-tree=" + options[:work_dir] ]
  else
    work_dir_arguments = []
  end

  command = [ "--git-dir=#{@repo_dir}" ] \
    + work_dir_arguments \
    + arguments

  Armature::Run.clean_git(*command)
end
identity_ref(sha) click to toggle source

The identity of an object itself, i.e. a SHA

# File lib/armature/repo/git.rb, line 113
def identity_ref(sha)
  return @ref_cache[sha] if @ref_cache[sha]

  real_sha = nil # needs to be bound to this scope
  retry_fresh do
    # real_sha will always be a full SHA, but sha might be partial
    real_sha = rev_parse!(sha)
    if ! sha_match? real_sha, sha
      raise Armature::RefError, "'#{sha}' is not a Git SHA"
    end
  end

  make_ref(Armature::Ref::Identity, real_sha, real_sha, "revision", real_sha)

  # If sha is partial, register it in the cache too.
  @ref_cache[sha] = @ref_cache[real_sha]
end
mutable_fs_ref(ref_str) click to toggle source

Get ref object for some sort of mutable ref we found in the FS cache

# File lib/armature/repo/git.rb, line 96
def mutable_fs_ref(ref_str)
  freshen()

  return @ref_cache[ref_str] if @ref_cache[ref_str]

  if ref_str.start_with? "refs/heads/"
    return branch_ref(ref_str.sub("refs/heads/", ""))
  end

  if ref_str.start_with? "refs/tags/"
    return tag_ref(ref_str.sub("refs/tags/", ""))
  end

  make_ref(Armature::Ref::Mutable, ref_str, rev_parse!(ref_str), "ref", ref_str)
end
tag_ref(name) click to toggle source
# File lib/armature/repo/git.rb, line 146
def tag_ref(name)
  ref_str = "refs/tags/#{name}"
  return @ref_cache[ref_str] if @ref_cache[ref_str]

  sha = retry_fresh { rev_parse!(ref_str) }
  make_ref(Armature::Ref::Immutable, ref_str, sha, "tag", name)
  @ref_cache[name] = @ref_cache[ref_str]
end
url() click to toggle source
# File lib/armature/repo/git.rb, line 29
def url
  @url ||= git("config", "--get", "remote.origin.url").chomp()
end

Private Instance Methods

make_ref(klass, ref_str, sha, type, name) click to toggle source
# File lib/armature/repo/git.rb, line 202
def make_ref(klass, ref_str, sha, type, name)
  @ref_cache[ref_str] = klass.new(self, ref_str, sha, type, name)
end
retry_fresh() { || ... } click to toggle source
# File lib/armature/repo/git.rb, line 190
def retry_fresh
  yield
rescue Armature::RefError
  if @fresh
    raise
  end

  @logger.debug("Got ref error; fetching to see if that helps.")
  freshen()
  yield
end
rev_parse(ref_str) click to toggle source

Get the SHA for a ref, or nil if it doesn't exist

# File lib/armature/repo/git.rb, line 207
def rev_parse(ref_str)
  rev_parse!(ref_str)
rescue Armature::RefError
  nil
end
rev_parse!(ref_str) click to toggle source

Get the SHA for a ref, or raise if it doesn't exist

# File lib/armature/repo/git.rb, line 214
def rev_parse!(ref_str)
  if @rev_cache[ref_str]
    @rev_cache[ref_str]
  end

  @rev_cache[ref_str] = git("rev-parse", "--verify", "#{ref_str}^{commit}").chomp
rescue Armature::Run::CommandFailureError
  raise Armature::RefError, "no such ref '#{ref_str}' in repo '#{self}'"
end
sha_match?(real, candidate) click to toggle source

Check if a real (full) SHA matches a (possibly partial) candidate SHA

# File lib/armature/repo/git.rb, line 225
def sha_match? real, candidate
  real.start_with? candidate
end