Permalink
Browse files

added some blame and merge stuff

  • Loading branch information...
schacon committed Dec 11, 2008
1 parent 1c36188 commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
View
@@ -1,6 +0,0 @@
-coverage
-pkg/*.tgz
-doc
-test/specifics.rb
-test.rb
-*.gem
View
@@ -4,7 +4,7 @@ grit
== DESCRIPTION:
-Grit is a Ruby library for extracting information from a git repository in and
+Grit is a Ruby library for extracting information from a git repository in an
object oriented manner.
== REQUIREMENTS:
View
@@ -36,6 +36,8 @@
require 'grit/index'
require 'grit/status'
require 'grit/submodule'
+require 'grit/blame'
+require 'grit/merge'
module Grit
View
@@ -0,0 +1,61 @@
+module Grit
+
+ class Blame
+
+ attr_reader :lines
+
+ def initialize(repo, file, commit)
+ @repo = repo
+ @file = file
+ @commit = commit
+ @lines = []
+ load_blame
+ end
+
+ def load_blame
+ output = @repo.git.blame({'p' => true}, @commit, '--', @file)
+ process_raw_blame(output)
+ end
+
+ def process_raw_blame(output)
+ lines, final = [], []
+ info, commits = {}, {}
+
+ # process the output
+ output.split("\n").each do |line|
+ if line[0, 1] == "\t"
+ lines << line[1, line.size]
+ elsif m = /^(\w{40}) (\d+) (\d+)/.match(line)
+ if !commits[m[1]]
+ commits[m[1]] = @repo.commit(m[1])
+ end
+ info[m[3].to_i] = [commits[m[1]], m[2].to_i]
+ end
+ end
+
+ # get it together
+ info.sort.each do |lineno, commit|
+ final << BlameLine.new(lineno, commit[1], commit[0], lines[lineno - 1])
+ end
+
+ @lines = final
+ end
+
+ # Pretty object inspection
+ def inspect
+ %Q{#<Grit::Blame "#{@file} <#{@commit}>">}
+ end
+
+ class BlameLine
+ attr_accessor :lineno, :oldlineno, :commit, :line
+ def initialize(lineno, oldlineno, commit, line)
+ @lineno = lineno
+ @oldlineno = oldlineno
+ @commit = commit
+ @line = line
+ end
+ end
+
+ end # Blame
+
+end # Grit
View
@@ -10,6 +10,7 @@ class Commit
lazy_reader :committed_date
lazy_reader :message
lazy_reader :short_message
+ lazy_reader :author_string
# Instantiate a new Commit
# +id+ is the id of the commit
@@ -205,7 +206,11 @@ def self.actor(line)
m, actor, epoch = *line.match(/^.+? (.*) (\d+) .*$/)
[Actor.from_string(actor), Time.at(epoch.to_i)]
end
-
+
+ def author_string
+ "%s <%s> %s %+05d" % [author.name, author.email, authored_date.to_i, 800]
+ end
+
def to_hash
{
'id' => id,
View
@@ -113,6 +113,8 @@ def file_type(ref)
def blame_tree(commit, path = nil)
begin
+ path = path.to_a.join('/').to_s + '/' if (path && path != '')
+ path = '' if !path.is_a? String
commits = file_index.last_commits(rev_parse({}, commit), looking_for(commit, path))
clean_paths(commits)
rescue FileIndex::IndexFileNotFound
@@ -22,12 +22,18 @@ class IndexFileNotFound < StandardError
class UnsupportedRef < StandardError
end
+ class << self
+ attr_accessor :max_file_size
+ end
+
+ self.max_file_size = 10_000_000 # ~10M
+
attr_reader :files
# initializes index given repo_path
def initialize(repo_path)
@index_file = File.join(repo_path, 'file-index')
- if File.file?(@index_file)
+ if File.file?(@index_file) && (File.size(@index_file) < Grit::GitRuby::FileIndex.max_file_size)
read_index
else
raise IndexFileNotFound
@@ -46,6 +52,7 @@ def count(commit_sha)
commits_from(commit_sha).size
end
+ # builds a list of all commits reachable from a single commit
def commits_from(commit_sha)
raise UnsupportedRef if commit_sha.is_a? Array
@@ -69,7 +76,7 @@ def commits_from(commit_sha)
end
def sort_commits(sha_array)
- sha_array.sort { |a, b| @commit_order[b] <=> @commit_order[a] }
+ sha_array.sort { |a, b| @commit_order[b].to_i <=> @commit_order[a].to_i }
end
# returns files changed at commit sha
@@ -183,4 +190,4 @@ def read_index
end
-
+
@@ -664,6 +664,7 @@ def git_path(path)
private
def initloose
+ @loaded = []
@loose = []
load_loose(git_path('objects'))
load_alternate_loose(git_path('objects'))
@@ -675,6 +676,7 @@ def load_alternate_loose(path)
alt = File.join(path, 'info/alternates')
if File.exists?(alt)
File.readlines(alt).each do |line|
+ next if @loaded.include?(line.chomp)
if line[0, 2] == '..'
line = File.expand_path(File.join(@git_dir, line))
end
@@ -685,12 +687,14 @@ def load_alternate_loose(path)
end
def load_loose(path)
+ @loaded << path
return if !File.exists?(path)
@loose << Grit::GitRuby::Internal::LooseStorage.new(path)
end
def initpacks
close
+ @loaded_packs = []
@packs = []
load_packs(git_path("objects/pack"))
load_alternate_packs(git_path('objects'))
@@ -705,13 +709,15 @@ def load_alternate_packs(path)
line = File.expand_path(File.join(@git_dir, line))
end
full_pack = File.join(line.chomp, 'pack')
+ next if @loaded_packs.include?(full_pack)
load_packs(full_pack)
load_alternate_packs(File.join(line.chomp))
end
end
end
def load_packs(path)
+ @loaded_packs << path
return if !File.exists?(path)
Dir.open(path) do |dir|
dir.each do |entry|
View
@@ -21,6 +21,13 @@ class << self
self.git_binary = "/usr/bin/env git"
self.git_timeout = 10
+ def self.with_timeout(timeout = 10.seconds)
+ old_timeout = Grit::Git.git_timeout
+ Grit::Git.git_timeout = timeout
+ yield
+ Grit::Git.git_timeout = old_timeout
+ end
+
attr_accessor :git_dir, :bytes_read
def initialize(git_dir)
@@ -43,12 +50,12 @@ def method_missing(cmd, options = {}, *args)
end
def run(prefix, cmd, postfix, options, args)
- timeout = options.delete(:timeout)
+ timeout = options.delete(:timeout) rescue nil
timeout = true if timeout.nil?
opt_args = transform_options(options)
ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|') ? a : "'#{a}'" }
-
+
call = "#{prefix}#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{postfix}"
Grit.log(call) if Grit.debug
response, err = timeout ? sh(call) : wild_sh(call)
View
@@ -64,14 +64,7 @@ def commit(message, parents = nil, actor = nil, last_tree = nil, head = 'master'
commit_sha1 = self.repo.git.ruby_git.put_raw_object(contents.join("\n"), 'commit')
- # self.repo.git.update_ref({}, 'HEAD', commit_sha1)
- ref_heads = File.join(self.repo.path, 'refs', 'heads')
- FileUtils.mkdir_p(ref_heads)
- File.open(File.join(ref_heads, head), 'w') do |f|
- f.write(commit_sha1)
- end if commit_sha1
-
- commit_sha1
+ self.repo.update_ref(head, commit_sha1)
end
# Recursively write a tree to the index
View
@@ -0,0 +1,45 @@
+module Grit
+
+ class Merge
+
+ STATUS_BOTH = 'both'
+ STATUS_OURS = 'ours'
+ STATUS_THEIRS = 'theirs'
+
+ attr_reader :conflicts, :text, :sections
+
+ def initialize(str)
+ status = STATUS_BOTH
+
+ section = 1
+ @conflicts = 0
+ @text = {}
+
+ lines = str.split("\n")
+ lines.each do |line|
+ if /^<<<<<<< (.*?)/.match(line)
+ status = STATUS_OURS
+ @conflicts += 1
+ section += 1
+ elsif line == '======='
+ status = STATUS_THEIRS
+ elsif /^>>>>>>> (.*?)/.match(line)
+ status = STATUS_BOTH
+ section += 1
+ else
+ @text[section] ||= {}
+ @text[section][status] ||= []
+ @text[section][status] << line
+ end
+ end
+ @text = @text.values
+ @sections = @text.size
+ end
+
+ # Pretty object inspection
+ def inspect
+ %Q{#<Grit::Merge}
+ end
+ end # Merge
+
+end # Grit
View
@@ -51,6 +51,11 @@ def self.init(path)
def description
File.open(File.join(self.path, 'description')).read.chomp
end
+
+ def blame(file, commit = nil)
+ Blame.new(self, file, commit)
+ end
+
# An array of Head objects representing the branch heads in
# this repo
@@ -62,10 +67,14 @@ def heads
alias_method :branches, :heads
- def is_head?(head_name)
+ def get_head(head_name)
heads.find { |h| h.name == head_name }
end
+ def is_head?(head_name)
+ get_head(head_name)
+ end
+
# Object reprsenting the current repo head.
#
# Returns Grit::Head (baked)
@@ -320,7 +329,6 @@ def archive_to_file(treeish = 'master', prefix = nil, filename = 'archive.tar.gz
self.git.archive(options, treeish, "| gzip > #{filename}")
end
-
# Enable git-daemon serving of this repository by writing the
# git-daemon-export-ok file to its git directory
#
@@ -378,6 +386,30 @@ def index
Index.new(self)
end
+ def update_ref(head, commit_sha)
+ return nil if !commit_sha || (commit_sha.size != 40)
+
+ # check packed refs - remove head if it's there
+ packed_refs = File.join(self.path, 'packed-refs')
+ if File.file?(packed_refs)
+ pr = File.read(packed_refs)
+ refs = pr.split("\n")
+ refs = refs.reject { |ref| /[0-9a-z]{40} refs\/heads\/#{head}/.match(ref) }
+ pr = refs.join("\n")
+ File.open(packed_refs, 'w') do |f|
+ f.write(pr)
+ end
+ end
+
+ ref_heads = File.join(self.path, 'refs', 'heads')
+ FileUtils.mkdir_p(ref_heads)
+ File.open(File.join(ref_heads, head), 'w') do |f|
+ f.write(commit_sha)
+ end
+ commit_sha
+
+ end
+
# Pretty object inspection
def inspect
%Q{#<Grit::Repo "#{@path}">}
Oops, something went wrong.

0 comments on commit 1c002dd

Please sign in to comment.