class Treet::Gitrepo

Attributes

author[R]
gitrepo[R]

Public Class Methods

new(path, opts = {}) click to toggle source
Calls superclass method Treet::Repo::new
# File lib/treet/gitrepo.rb, line 8
def initialize(path, opts = {})
  raise ArgumentError, "author required for updates" unless opts[:author]
  super

  @author = opts[:author]

  begin
    @gitrepo = Rugged::Repository.new(root)
  rescue Rugged::RepositoryError
    @gitrepo = initialize_gitrepo
    add_and_commit!
  end
end

Public Instance Methods

branch(name) click to toggle source

always branch from tip of master (private representation)

# File lib/treet/gitrepo.rb, line 78
def branch(name)
  gitrepo.create_branch(name)
end
branches(branchname = nil) click to toggle source
# File lib/treet/gitrepo.rb, line 69
def branches(branchname = nil)
  if branchname
    Rugged::Branch.lookup(gitrepo, branchname)
  else
    gitrepo.branches.map(&:name) - ['master']
  end
end
current?(tagname) click to toggle source
# File lib/treet/gitrepo.rb, line 94
def current?(tagname)
  commit_id_for(tagname) == head.target
end
detag(tagname) click to toggle source
# File lib/treet/gitrepo.rb, line 42
def detag(tagname)
  if tag_ref = Rugged::Reference.lookup(gitrepo, "refs/tags/#{tagname}")
    tag_ref.delete!
  end
end
entries() click to toggle source
# File lib/treet/gitrepo.rb, line 65
def entries
  index.entries.map{|e| e[:path]}
end
patch(patchdef) click to toggle source
Calls superclass method Treet::Repo#patch
# File lib/treet/gitrepo.rb, line 48
def patch(patchdef)
  super
  if git_changes?(patchdef)
    add_and_commit!
  end
end
remote(name) click to toggle source
# File lib/treet/gitrepo.rb, line 98
def remote(name)
  Rugged::Remote.lookup(gitrepo, name)
end
tag(tagname, opts = {}) click to toggle source
# File lib/treet/gitrepo.rb, line 26
def tag(tagname, opts = {})
  refname = "refs/tags/#{tagname}"
  commit = opts[:commit] || head.target
  if tag_ref = Rugged::Reference.lookup(gitrepo, refname)
    # move an existing tag
    tag_ref.set_target(commit)
  else
    # new tag
    Rugged::Reference.create(gitrepo, refname, commit)
  end
rescue Rugged::ReferenceError, Rugged::InvalidError => e
  # invalid string for source, e.g. blank or illegal punctuation (colons)
  # or opts[:commit] is invalid
  raise ArgumentError, "unable to tag '#{tagname}' on repo: #{e.message}"
end
tagged?(tagname) click to toggle source
# File lib/treet/gitrepo.rb, line 82
def tagged?(tagname)
  ! commit_id_for(tagname).nil?
end
tags() click to toggle source
# File lib/treet/gitrepo.rb, line 22
def tags
  gitrepo.refs.select {|ref| ref.name =~ %r{/tags/}}
end
to_hash(opts = {}) click to toggle source
Calls superclass method Treet::Repo#to_hash
# File lib/treet/gitrepo.rb, line 55
def to_hash(opts = {})
  if opts[:commit]
    snapshot(opts[:commit])
  elsif opts[:tag]
    tag_snapshot(opts[:tag])
  else
    super()
  end.merge(augmentation)
end
version(opts = {}) click to toggle source
# File lib/treet/gitrepo.rb, line 86
def version(opts = {})
  if tagname = opts[:tag]
    commit_id_for(tagname)
  else
    head.target
  end
end

Private Instance Methods

add_and_commit!() click to toggle source
# File lib/treet/gitrepo.rb, line 133
def add_and_commit!
  current_index = entries
  Dir.chdir(root) do
    # automatically ignores dotfiles
    current_files = Dir.glob('**/*')

    # additions
    (current_files - current_index).each do |file|
      # must add each filename explicitly, `index#add` does not recurse into directories
      if File.file?(file)
        index.add(file)
      end
    end

    # possible alterations - these changes won't be detected unless we explicitly git-add
    (current_files & current_index).each do |file|
      if File.file?(file)
        index.add(file)
      end
    end

    # deletions
    (current_index - current_files).each do |file|
      # `index#remove` handles directories
      index.remove(file)
    end

    index.write
    tree_sha = index.write_tree
    commit!(tree_sha)
  end
end
augmentation(path = root) click to toggle source
# File lib/treet/gitrepo.rb, line 216
def augmentation(path = root)
  dotfiles = Dir.entries(path).select {|f|  f =~ /^\./ && f !~ /^(\.|\.\.|\.git)$/}
  dotfiles.each_with_object({}) {|f,h| h[f] = expand_json("#{path}/#{f}")}
end
commit!(sha) click to toggle source

always commits to HEAD

# File lib/treet/gitrepo.rb, line 111
def commit!(sha)
  parent_shas = begin
    [gitrepo.head.target]
  rescue Rugged::ReferenceError
    # this is the first commit
    []
  end

  authorship = author.merge(:time => Time.now)

  sha = Rugged::Commit.create(gitrepo,
    :message => "",
    :author => authorship,
    :committer => authorship,
    :parents => parent_shas,
    :tree => sha,
    :update_ref => "HEAD"
  )

  sha
end
commit_id_for(tagname) click to toggle source
# File lib/treet/gitrepo.rb, line 203
def commit_id_for(tagname)
  (ref = Rugged::Reference.lookup(gitrepo, "refs/tags/#{tagname}")) && ref.target
end
git_changes?(patchdef) click to toggle source

any patches in here that affect anything that must be recorded in git?

# File lib/treet/gitrepo.rb, line 222
def git_changes?(patchdef)
  patchdef.find {|p| p[1] =~ /^[^.]/}
end
gitget(obj) click to toggle source

ruby 2.0 changed behavior on empty strings: JSON.load(“”) under 1.9.3 and previous, this caused an exception under 2.0, this just returns nil

# File lib/treet/gitrepo.rb, line 169
def gitget(obj)
  data = gitrepo.read(obj[:oid]).data
  begin
    v = JSON.load(data)
    v = obj[:name] if v.nil?
    v
  rescue JSON::ParserError
    # parser errors are not fatal
    # this just indicates a string entry rather than a hash
    data.empty? ? obj[:name] : data
  end
end
initialize_gitrepo() click to toggle source
# File lib/treet/gitrepo.rb, line 106
def initialize_gitrepo
  Rugged::Repository.init_at(root, false)
end
snapshot(commit_sha) click to toggle source
# File lib/treet/gitrepo.rb, line 182
def snapshot(commit_sha)
  commit = gitrepo.lookup(commit_sha)
  tree = commit.tree
  # must traverse the tree: entries are files or subtrees
  data = {}
  tree.each do |obj|
    data[obj[:name]] = case obj[:type]
    when :blob
      gitget(obj)
    when :tree
      gitrepo.lookup(obj[:oid]).each_with_object([]) do |subobj,d|
        d << gitget(subobj)
      end
    else
      raise TypeError, "UNRECOGNIZED GIT OBJECT TYPE #{obj[:type]}"
    end
  end

  Treet::Hash.new(data)
end
tag_snapshot(tagname) click to toggle source
# File lib/treet/gitrepo.rb, line 207
def tag_snapshot(tagname)
  if commitid = version(:tag => tagname)
    snapshot(commitid)
  else
    # this tag does not appear in the repo; this is NOT an exception
    {}
  end
end