jugyo-grit 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/API.txt +101 -0
- data/History.txt +153 -0
- data/LICENSE +22 -0
- data/PURE_TODO +35 -0
- data/README.md +242 -0
- data/Rakefile +153 -0
- data/benchmarks.rb +129 -0
- data/benchmarks.txt +21 -0
- data/examples/ex_add_commit.rb +13 -0
- data/examples/ex_index.rb +21 -0
- data/jugyo-grit.gemspec +74 -0
- data/lib/grit.rb +75 -0
- data/lib/grit/actor.rb +52 -0
- data/lib/grit/blame.rb +66 -0
- data/lib/grit/blob.rb +126 -0
- data/lib/grit/commit.rb +308 -0
- data/lib/grit/commit_stats.rb +128 -0
- data/lib/grit/config.rb +44 -0
- data/lib/grit/diff.rb +79 -0
- data/lib/grit/errors.rb +10 -0
- data/lib/grit/git-ruby.rb +259 -0
- data/lib/grit/git-ruby/commit_db.rb +52 -0
- data/lib/grit/git-ruby/git_object.rb +353 -0
- data/lib/grit/git-ruby/internal/file_window.rb +58 -0
- data/lib/grit/git-ruby/internal/loose.rb +137 -0
- data/lib/grit/git-ruby/internal/pack.rb +391 -0
- data/lib/grit/git-ruby/internal/raw_object.rb +44 -0
- data/lib/grit/git-ruby/repository.rb +775 -0
- data/lib/grit/git.rb +501 -0
- data/lib/grit/index.rb +222 -0
- data/lib/grit/lazy.rb +35 -0
- data/lib/grit/merge.rb +45 -0
- data/lib/grit/ref.rb +78 -0
- data/lib/grit/repo.rb +709 -0
- data/lib/grit/ruby1.9.rb +7 -0
- data/lib/grit/status.rb +153 -0
- data/lib/grit/submodule.rb +88 -0
- data/lib/grit/tag.rb +102 -0
- data/lib/grit/tree.rb +125 -0
- metadata +134 -0
    
        data/lib/grit/actor.rb
    ADDED
    
    | @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            module Grit
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              class Actor
         | 
| 4 | 
            +
                attr_reader :name
         | 
| 5 | 
            +
                attr_reader :email
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(name, email)
         | 
| 8 | 
            +
                  @name = name
         | 
| 9 | 
            +
                  @email = email
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
                alias_method :to_s, :name
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                # Create an Actor from a string.
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                # str - The String in this format: 'John Doe <jdoe@example.com>'
         | 
| 16 | 
            +
                #
         | 
| 17 | 
            +
                # Returns Git::Actor.
         | 
| 18 | 
            +
                def self.from_string(str)
         | 
| 19 | 
            +
                  case str
         | 
| 20 | 
            +
                    when /<.+>/
         | 
| 21 | 
            +
                      m, name, email = *str.match(/(.*) <(.+?)>/)
         | 
| 22 | 
            +
                      return self.new(name, email)
         | 
| 23 | 
            +
                    else
         | 
| 24 | 
            +
                      return self.new(str, nil)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                # Outputs an actor string for Git commits.
         | 
| 29 | 
            +
                #
         | 
| 30 | 
            +
                #   actor = Actor.new('bob', 'bob@email.com')
         | 
| 31 | 
            +
                #   actor.output(time) # => "bob <bob@email.com> UNIX_TIME +0700"
         | 
| 32 | 
            +
                #
         | 
| 33 | 
            +
                # time - The Time the commit was authored or committed.
         | 
| 34 | 
            +
                #
         | 
| 35 | 
            +
                # Returns a String.
         | 
| 36 | 
            +
                def output(time)
         | 
| 37 | 
            +
                  out = @name.to_s.dup
         | 
| 38 | 
            +
                  if @email
         | 
| 39 | 
            +
                    out << " <#{@email}>"
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                  hours = (time.utc_offset.to_f / 3600).to_i # 60 * 60, seconds to hours
         | 
| 42 | 
            +
                  rem   = time.utc_offset.abs % 3600
         | 
| 43 | 
            +
                  out << " #{time.to_i} #{hours >= 0 ? :+ : :-}#{hours.abs.to_s.rjust(2, '0')}#{rem.to_s.rjust(2, '0')}"
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                # Pretty object inspection
         | 
| 47 | 
            +
                def inspect
         | 
| 48 | 
            +
                  %Q{#<Grit::Actor "#{@name} <#{@email}>">}
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end # Actor
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            end # Grit
         | 
    
        data/lib/grit/blame.rb
    ADDED
    
    | @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            module Grit
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              class Blame
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                attr_reader :lines
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(repo, file, commit)
         | 
| 8 | 
            +
                  @repo = repo
         | 
| 9 | 
            +
                  @file = file
         | 
| 10 | 
            +
                  @commit = commit
         | 
| 11 | 
            +
                  @lines = []
         | 
| 12 | 
            +
                  load_blame
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def load_blame
         | 
| 16 | 
            +
                  output = @repo.git.blame({'p' => true}, @commit, '--', @file)
         | 
| 17 | 
            +
                  process_raw_blame(output)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def process_raw_blame(output)
         | 
| 21 | 
            +
                  lines, final = [], []
         | 
| 22 | 
            +
                  info, commits = {}, {}
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # process the output
         | 
| 25 | 
            +
                  output.split("\n").each do |line|
         | 
| 26 | 
            +
                    if line[0, 1] == "\t"
         | 
| 27 | 
            +
                      lines << line[1, line.size]
         | 
| 28 | 
            +
                    elsif m = /^(\w{40}) (\d+) (\d+)/.match(line)
         | 
| 29 | 
            +
                      commit_id, old_lineno, lineno = m[1], m[2].to_i, m[3].to_i
         | 
| 30 | 
            +
                      commits[commit_id] = nil if !commits.key?(commit_id)
         | 
| 31 | 
            +
                      info[lineno] = [commit_id, old_lineno]
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  # load all commits in single call
         | 
| 36 | 
            +
                  @repo.batch(*commits.keys).each do |commit|
         | 
| 37 | 
            +
                    commits[commit.id] = commit
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  # get it together
         | 
| 41 | 
            +
                  info.sort.each do |lineno, (commit_id, old_lineno)|
         | 
| 42 | 
            +
                    commit = commits[commit_id]
         | 
| 43 | 
            +
                    final << BlameLine.new(lineno, old_lineno, commit, lines[lineno - 1])
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  @lines = final
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                # Pretty object inspection
         | 
| 50 | 
            +
                def inspect
         | 
| 51 | 
            +
                  %Q{#<Grit::Blame "#{@file} <#{@commit}>">}
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                class BlameLine
         | 
| 55 | 
            +
                  attr_accessor :lineno, :oldlineno, :commit, :line
         | 
| 56 | 
            +
                  def initialize(lineno, oldlineno, commit, line)
         | 
| 57 | 
            +
                    @lineno = lineno
         | 
| 58 | 
            +
                    @oldlineno = oldlineno
         | 
| 59 | 
            +
                    @commit = commit
         | 
| 60 | 
            +
                    @line = line
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              end # Blame
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            end # Grit
         | 
    
        data/lib/grit/blob.rb
    ADDED
    
    | @@ -0,0 +1,126 @@ | |
| 1 | 
            +
            module Grit
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              class Blob
         | 
| 4 | 
            +
                DEFAULT_MIME_TYPE = "text/plain"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                attr_reader :id
         | 
| 7 | 
            +
                attr_reader :mode
         | 
| 8 | 
            +
                attr_reader :name
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # Create an unbaked Blob containing just the specified attributes
         | 
| 11 | 
            +
                #   +repo+ is the Repo
         | 
| 12 | 
            +
                #   +atts+ is a Hash of instance variable data
         | 
| 13 | 
            +
                #
         | 
| 14 | 
            +
                # Returns Grit::Blob (unbaked)
         | 
| 15 | 
            +
                def self.create(repo, atts)
         | 
| 16 | 
            +
                  self.allocate.create_initialize(repo, atts)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                # Initializer for Blob.create
         | 
| 20 | 
            +
                #   +repo+ is the Repo
         | 
| 21 | 
            +
                #   +atts+ is a Hash of instance variable data
         | 
| 22 | 
            +
                #
         | 
| 23 | 
            +
                # Returns Grit::Blob (unbaked)
         | 
| 24 | 
            +
                def create_initialize(repo, atts)
         | 
| 25 | 
            +
                  @repo = repo
         | 
| 26 | 
            +
                  atts.each do |k, v|
         | 
| 27 | 
            +
                    instance_variable_set("@#{k}".to_sym, v)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                  self
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                # The size of this blob in bytes
         | 
| 33 | 
            +
                #
         | 
| 34 | 
            +
                # Returns Integer
         | 
| 35 | 
            +
                def size
         | 
| 36 | 
            +
                  @size ||= @repo.git.cat_file({:s => true}, id).chomp.to_i
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # The binary contents of this blob.
         | 
| 40 | 
            +
                #
         | 
| 41 | 
            +
                # Returns String
         | 
| 42 | 
            +
                def data
         | 
| 43 | 
            +
                  @data ||= @repo.git.cat_file({:p => true}, id)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                # The mime type of this file (based on the filename)
         | 
| 47 | 
            +
                #
         | 
| 48 | 
            +
                # Returns String
         | 
| 49 | 
            +
                def mime_type
         | 
| 50 | 
            +
                  guesses = MIME::Types.type_for(self.name) rescue []
         | 
| 51 | 
            +
                  guesses.first ? guesses.first.simplified : DEFAULT_MIME_TYPE
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                # The blame information for the given file at the given commit
         | 
| 55 | 
            +
                #
         | 
| 56 | 
            +
                # Returns Array: [Grit::Commit, Array: [<line>]]
         | 
| 57 | 
            +
                def self.blame(repo, commit, file)
         | 
| 58 | 
            +
                  data = repo.git.blame({:p => true}, commit, '--', file)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  commits = {}
         | 
| 61 | 
            +
                  blames = []
         | 
| 62 | 
            +
                  info = nil
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  data.split("\n").each do |line|
         | 
| 65 | 
            +
                    parts = line.split(/\s+/, 2)
         | 
| 66 | 
            +
                    case parts.first
         | 
| 67 | 
            +
                      when /^[0-9A-Fa-f]{40}$/
         | 
| 68 | 
            +
                        case line
         | 
| 69 | 
            +
                          when /^([0-9A-Fa-f]{40}) (\d+) (\d+) (\d+)$/
         | 
| 70 | 
            +
                            _, id, origin_line, final_line, group_lines = *line.match(/^([0-9A-Fa-f]{40}) (\d+) (\d+) (\d+)$/)
         | 
| 71 | 
            +
                            info = {:id => id}
         | 
| 72 | 
            +
                            blames << [nil, []]
         | 
| 73 | 
            +
                          when /^([0-9A-Fa-f]{40}) (\d+) (\d+)$/
         | 
| 74 | 
            +
                            _, id, origin_line, final_line = *line.match(/^([0-9A-Fa-f]{40}) (\d+) (\d+)$/)
         | 
| 75 | 
            +
                            info = {:id => id}
         | 
| 76 | 
            +
                        end
         | 
| 77 | 
            +
                      when /^(author|committer)/
         | 
| 78 | 
            +
                        case parts.first
         | 
| 79 | 
            +
                          when /^(.+)-mail$/
         | 
| 80 | 
            +
                            info["#{$1}_email".intern] = parts.last
         | 
| 81 | 
            +
                          when /^(.+)-time$/
         | 
| 82 | 
            +
                            info["#{$1}_date".intern] = Time.at(parts.last.to_i)
         | 
| 83 | 
            +
                          when /^(author|committer)$/
         | 
| 84 | 
            +
                            info[$1.intern] = parts.last
         | 
| 85 | 
            +
                        end
         | 
| 86 | 
            +
                      when /^filename/
         | 
| 87 | 
            +
                        info[:filename] = parts.last
         | 
| 88 | 
            +
                      when /^summary/
         | 
| 89 | 
            +
                        info[:summary] = parts.last
         | 
| 90 | 
            +
                      when ''
         | 
| 91 | 
            +
                        c = commits[info[:id]]
         | 
| 92 | 
            +
                        unless c
         | 
| 93 | 
            +
                          c = Commit.create(repo, :id => info[:id],
         | 
| 94 | 
            +
                                                  :author => Actor.from_string(info[:author] + ' ' + info[:author_email]),
         | 
| 95 | 
            +
                                                  :authored_date => info[:author_date],
         | 
| 96 | 
            +
                                                  :committer => Actor.from_string(info[:committer] + ' ' + info[:committer_email]),
         | 
| 97 | 
            +
                                                  :committed_date => info[:committer_date],
         | 
| 98 | 
            +
                                                  :message => info[:summary])
         | 
| 99 | 
            +
                          commits[info[:id]] = c
         | 
| 100 | 
            +
                        end
         | 
| 101 | 
            +
                        _, text = *line.match(/^\t(.*)$/)
         | 
| 102 | 
            +
                        blames.last[0] = c
         | 
| 103 | 
            +
                        blames.last[1] << text
         | 
| 104 | 
            +
                        info = nil
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  blames
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                def basename
         | 
| 112 | 
            +
                  File.basename(name)
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                # Pretty object inspection
         | 
| 116 | 
            +
                def inspect
         | 
| 117 | 
            +
                  %Q{#<Grit::Blob "#{@id}">}
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                # Compares blobs by name
         | 
| 121 | 
            +
                def <=>(other)
         | 
| 122 | 
            +
                  name <=> other.name
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
              end # Blob
         | 
| 125 | 
            +
             | 
| 126 | 
            +
            end # Grit
         | 
    
        data/lib/grit/commit.rb
    ADDED
    
    | @@ -0,0 +1,308 @@ | |
| 1 | 
            +
            module Grit
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              class Commit
         | 
| 4 | 
            +
                extend Lazy
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                attr_reader :id
         | 
| 7 | 
            +
                attr_reader :repo
         | 
| 8 | 
            +
                lazy_reader :parents
         | 
| 9 | 
            +
                lazy_reader :tree
         | 
| 10 | 
            +
                lazy_reader :author
         | 
| 11 | 
            +
                lazy_reader :authored_date
         | 
| 12 | 
            +
                lazy_reader :committer
         | 
| 13 | 
            +
                lazy_reader :committed_date
         | 
| 14 | 
            +
                lazy_reader :message
         | 
| 15 | 
            +
                lazy_reader :short_message
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                # Parses output from the `git-cat-file --batch'.
         | 
| 18 | 
            +
                #
         | 
| 19 | 
            +
                # repo   - Grit::Repo instance.
         | 
| 20 | 
            +
                # sha    - String SHA of the Commit.
         | 
| 21 | 
            +
                # size   - Fixnum size of the object.
         | 
| 22 | 
            +
                # object - Parsed String output from `git cat-file --batch`.
         | 
| 23 | 
            +
                #
         | 
| 24 | 
            +
                # Returns an Array of Grit::Commit objects.
         | 
| 25 | 
            +
                def self.parse_batch(repo, sha, size, object)
         | 
| 26 | 
            +
                  info, message = object.split("\n\n", 2)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  lines = info.split("\n")
         | 
| 29 | 
            +
                  tree = lines.shift.split(' ', 2).last
         | 
| 30 | 
            +
                  parents = []
         | 
| 31 | 
            +
                  parents << lines.shift[7..-1] while lines.first[0, 6] == 'parent'
         | 
| 32 | 
            +
                  author,    authored_date  = Grit::Commit.actor(lines.shift)
         | 
| 33 | 
            +
                  committer, committed_date = Grit::Commit.actor(lines.shift)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  Grit::Commit.new(
         | 
| 36 | 
            +
                    repo, sha, parents, tree,
         | 
| 37 | 
            +
                    author, authored_date,
         | 
| 38 | 
            +
                    committer, committed_date,
         | 
| 39 | 
            +
                    message.to_s.split("\n"))
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # Instantiate a new Commit
         | 
| 43 | 
            +
                #   +id+ is the id of the commit
         | 
| 44 | 
            +
                #   +parents+ is an array of commit ids (will be converted into Commit instances)
         | 
| 45 | 
            +
                #   +tree+ is the correspdonding tree id (will be converted into a Tree object)
         | 
| 46 | 
            +
                #   +author+ is the author string
         | 
| 47 | 
            +
                #   +authored_date+ is the authored Time
         | 
| 48 | 
            +
                #   +committer+ is the committer string
         | 
| 49 | 
            +
                #   +committed_date+ is the committed Time
         | 
| 50 | 
            +
                #   +message+ is an array of commit message lines
         | 
| 51 | 
            +
                #
         | 
| 52 | 
            +
                # Returns Grit::Commit (baked)
         | 
| 53 | 
            +
                def initialize(repo, id, parents, tree, author, authored_date, committer, committed_date, message)
         | 
| 54 | 
            +
                  @repo = repo
         | 
| 55 | 
            +
                  @id = id
         | 
| 56 | 
            +
                  @parents = parents.map { |p| Commit.create(repo, :id => p) }
         | 
| 57 | 
            +
                  @tree = Tree.create(repo, :id => tree)
         | 
| 58 | 
            +
                  @author = author
         | 
| 59 | 
            +
                  @authored_date = authored_date
         | 
| 60 | 
            +
                  @committer = committer
         | 
| 61 | 
            +
                  @committed_date = committed_date
         | 
| 62 | 
            +
                  @message = message.join("\n")
         | 
| 63 | 
            +
                  @short_message = message.select { |x| !x.strip.empty? }[0] || ''
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def id_abbrev
         | 
| 67 | 
            +
                  @id_abbrev ||= @repo.git.rev_parse({}, self.id).chomp[0, 7]
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                # Create an unbaked Commit containing just the specified attributes
         | 
| 71 | 
            +
                #   +repo+ is the Repo
         | 
| 72 | 
            +
                #   +atts+ is a Hash of instance variable data
         | 
| 73 | 
            +
                #
         | 
| 74 | 
            +
                # Returns Grit::Commit (unbaked)
         | 
| 75 | 
            +
                def self.create(repo, atts)
         | 
| 76 | 
            +
                  self.allocate.create_initialize(repo, atts)
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                # Initializer for Commit.create
         | 
| 80 | 
            +
                #   +repo+ is the Repo
         | 
| 81 | 
            +
                #   +atts+ is a Hash of instance variable data
         | 
| 82 | 
            +
                #
         | 
| 83 | 
            +
                # Returns Grit::Commit (unbaked)
         | 
| 84 | 
            +
                def create_initialize(repo, atts)
         | 
| 85 | 
            +
                  @repo = repo
         | 
| 86 | 
            +
                  atts.each do |k, v|
         | 
| 87 | 
            +
                    instance_variable_set("@#{k}", v)
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                  self
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                def lazy_source
         | 
| 93 | 
            +
                  self.class.find_all(@repo, @id, {:max_count => 1}).first
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                # Count the number of commits reachable from this ref
         | 
| 97 | 
            +
                #   +repo+ is the Repo
         | 
| 98 | 
            +
                #   +ref+ is the ref from which to begin (SHA1 or name)
         | 
| 99 | 
            +
                #
         | 
| 100 | 
            +
                # Returns Integer
         | 
| 101 | 
            +
                def self.count(repo, ref)
         | 
| 102 | 
            +
                  repo.git.rev_list({}, ref).size / 41
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                # Find all commits matching the given criteria.
         | 
| 106 | 
            +
                #   +repo+ is the Repo
         | 
| 107 | 
            +
                #   +ref+ is the ref from which to begin (SHA1 or name) or nil for --all
         | 
| 108 | 
            +
                #   +options+ is a Hash of optional arguments to git
         | 
| 109 | 
            +
                #     :max_count is the maximum number of commits to fetch
         | 
| 110 | 
            +
                #     :skip is the number of commits to skip
         | 
| 111 | 
            +
                #
         | 
| 112 | 
            +
                # Returns Grit::Commit[] (baked)
         | 
| 113 | 
            +
                def self.find_all(repo, ref, options = {})
         | 
| 114 | 
            +
                  allowed_options = [:max_count, :skip, :since]
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                  default_options = {:pretty => "raw"}
         | 
| 117 | 
            +
                  actual_options = default_options.merge(options)
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  if ref
         | 
| 120 | 
            +
                    output = repo.git.rev_list(actual_options, ref)
         | 
| 121 | 
            +
                  else
         | 
| 122 | 
            +
                    output = repo.git.rev_list(actual_options.merge(:all => true))
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  self.list_from_string(repo, output)
         | 
| 126 | 
            +
                rescue Grit::GitRuby::Repository::NoSuchShaFound
         | 
| 127 | 
            +
                  []
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                # Parse out commit information into an array of baked Commit objects
         | 
| 131 | 
            +
                #   +repo+ is the Repo
         | 
| 132 | 
            +
                #   +text+ is the text output from the git command (raw format)
         | 
| 133 | 
            +
                #
         | 
| 134 | 
            +
                # Returns Grit::Commit[] (baked)
         | 
| 135 | 
            +
                #
         | 
| 136 | 
            +
                # really should re-write this to be more accepting of non-standard commit messages
         | 
| 137 | 
            +
                # - it broke when 'encoding' was introduced - not sure what else might show up
         | 
| 138 | 
            +
                #
         | 
| 139 | 
            +
                def self.list_from_string(repo, text)
         | 
| 140 | 
            +
                  lines = text.split("\n")
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  commits = []
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                  while !lines.empty?
         | 
| 145 | 
            +
                    id = lines.shift.split.last
         | 
| 146 | 
            +
                    tree = lines.shift.split.last
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                    parents = []
         | 
| 149 | 
            +
                    parents << lines.shift.split.last while lines.first =~ /^parent/
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                    author, authored_date = self.actor(lines.shift)
         | 
| 152 | 
            +
                    committer, committed_date = self.actor(lines.shift)
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                    # not doing anything with this yet, but it's sometimes there
         | 
| 155 | 
            +
                    encoding = lines.shift.split.last if lines.first =~ /^encoding/
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                    lines.shift
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                    message_lines = []
         | 
| 160 | 
            +
                    message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                    lines.shift while lines.first && lines.first.empty?
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                    commits << Commit.new(repo, id, parents, tree, author, authored_date, committer, committed_date, message_lines)
         | 
| 165 | 
            +
                  end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                  commits
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                # Show diffs between two trees.
         | 
| 171 | 
            +
                #
         | 
| 172 | 
            +
                # repo    - The current Grit::Repo instance.
         | 
| 173 | 
            +
                # a       - A String named commit.
         | 
| 174 | 
            +
                # b       - An optional String named commit.  Passing an array assumes you
         | 
| 175 | 
            +
                #           wish to omit the second named commit and limit the diff to the
         | 
| 176 | 
            +
                #           given paths.
         | 
| 177 | 
            +
                # paths   - An optional Array of paths to limit the diff.
         | 
| 178 | 
            +
                # options - An optional Hash of options.  Merged into {:full_index => true}.
         | 
| 179 | 
            +
                #
         | 
| 180 | 
            +
                # Returns Grit::Diff[] (baked)
         | 
| 181 | 
            +
                def self.diff(repo, a, b = nil, paths = [], options = {})
         | 
| 182 | 
            +
                  if b.is_a?(Array)
         | 
| 183 | 
            +
                    paths = b
         | 
| 184 | 
            +
                    b     = nil
         | 
| 185 | 
            +
                  end
         | 
| 186 | 
            +
                  paths.unshift("--") unless paths.empty?
         | 
| 187 | 
            +
                  paths.unshift(b)    unless b.nil?
         | 
| 188 | 
            +
                  paths.unshift(a)
         | 
| 189 | 
            +
                  options = {:full_index => true}.update(options)
         | 
| 190 | 
            +
                  text    = repo.git.diff(options, *paths)
         | 
| 191 | 
            +
                  Diff.list_from_string(repo, text)
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                def show
         | 
| 195 | 
            +
                  if parents.size > 1
         | 
| 196 | 
            +
                    diff = @repo.git.native(:diff, {:full_index => true}, "#{parents[0].id}...#{parents[1].id}")
         | 
| 197 | 
            +
                  else
         | 
| 198 | 
            +
                    diff = @repo.git.show({:full_index => true, :pretty => 'raw'}, @id)
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                  if diff =~ /diff --git a/
         | 
| 202 | 
            +
                    diff = diff.sub(/.+?(diff --git a)/m, '\1')
         | 
| 203 | 
            +
                  else
         | 
| 204 | 
            +
                    diff = ''
         | 
| 205 | 
            +
                  end
         | 
| 206 | 
            +
                  Diff.list_from_string(@repo, diff)
         | 
| 207 | 
            +
                end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                # Shows diffs between the commit's parent and the commit.
         | 
| 210 | 
            +
                #
         | 
| 211 | 
            +
                # options - An optional Hash of options, passed to Grit::Commit.diff.
         | 
| 212 | 
            +
                #
         | 
| 213 | 
            +
                # Returns Grit::Diff[] (baked)
         | 
| 214 | 
            +
                def diffs(options = {})
         | 
| 215 | 
            +
                  if parents.empty?
         | 
| 216 | 
            +
                    show
         | 
| 217 | 
            +
                  else
         | 
| 218 | 
            +
                    self.class.diff(@repo, parents.first.id, @id, [], options)
         | 
| 219 | 
            +
                  end
         | 
| 220 | 
            +
                end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                def stats
         | 
| 223 | 
            +
                  stats = @repo.commit_stats(self.sha, 1)[0][-1]
         | 
| 224 | 
            +
                end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                # Convert this Commit to a String which is just the SHA1 id
         | 
| 227 | 
            +
                def to_s
         | 
| 228 | 
            +
                  @id
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                def sha
         | 
| 232 | 
            +
                  @id
         | 
| 233 | 
            +
                end
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                def date
         | 
| 236 | 
            +
                  @committed_date
         | 
| 237 | 
            +
                end
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                def to_patch
         | 
| 240 | 
            +
                  @repo.git.format_patch({'1' => true, :stdout => true}, to_s)
         | 
| 241 | 
            +
                end
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                def notes
         | 
| 244 | 
            +
                  ret = {}
         | 
| 245 | 
            +
                  notes = Note.find_all(@repo)
         | 
| 246 | 
            +
                  notes.each do |note|
         | 
| 247 | 
            +
                    if n = note.commit.tree/(self.id)
         | 
| 248 | 
            +
                      ret[note.name] = n.data
         | 
| 249 | 
            +
                    end
         | 
| 250 | 
            +
                  end
         | 
| 251 | 
            +
                  ret
         | 
| 252 | 
            +
                end
         | 
| 253 | 
            +
             | 
| 254 | 
            +
                # Calculates the commit's Patch ID. The Patch ID is essentially the SHA1
         | 
| 255 | 
            +
                # of the diff that the commit is introducing.
         | 
| 256 | 
            +
                #
         | 
| 257 | 
            +
                # Returns the 40 character hex String if a patch-id could be calculated
         | 
| 258 | 
            +
                #   or nil otherwise.
         | 
| 259 | 
            +
                def patch_id
         | 
| 260 | 
            +
                  show = @repo.git.show({}, @id)
         | 
| 261 | 
            +
                  patch_line = @repo.git.native(:patch_id, :input => show)
         | 
| 262 | 
            +
                  if patch_line =~ /^([0-9a-f]{40}) [0-9a-f]{40}\n$/
         | 
| 263 | 
            +
                    $1
         | 
| 264 | 
            +
                  else
         | 
| 265 | 
            +
                    nil
         | 
| 266 | 
            +
                  end
         | 
| 267 | 
            +
                end
         | 
| 268 | 
            +
             | 
| 269 | 
            +
                # Pretty object inspection
         | 
| 270 | 
            +
                def inspect
         | 
| 271 | 
            +
                  %Q{#<Grit::Commit "#{@id}">}
         | 
| 272 | 
            +
                end
         | 
| 273 | 
            +
             | 
| 274 | 
            +
                # private
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                # Parse out the actor (author or committer) info
         | 
| 277 | 
            +
                #
         | 
| 278 | 
            +
                # Returns [String (actor name and email), Time (acted at time)]
         | 
| 279 | 
            +
                def self.actor(line)
         | 
| 280 | 
            +
                  m, actor, epoch = *line.match(/^.+? (.*) (\d+) .*$/)
         | 
| 281 | 
            +
                  [Actor.from_string(actor), Time.at(epoch.to_i)]
         | 
| 282 | 
            +
                end
         | 
| 283 | 
            +
             | 
| 284 | 
            +
                def author_string
         | 
| 285 | 
            +
                  "%s <%s> %s %+05d" % [author.name, author.email, authored_date.to_i, 800]
         | 
| 286 | 
            +
                end
         | 
| 287 | 
            +
             | 
| 288 | 
            +
                def to_hash
         | 
| 289 | 
            +
                  {
         | 
| 290 | 
            +
                    'id'       => id,
         | 
| 291 | 
            +
                    'parents'  => parents.map { |p| { 'id' => p.id } },
         | 
| 292 | 
            +
                    'tree'     => tree.id,
         | 
| 293 | 
            +
                    'message'  => message,
         | 
| 294 | 
            +
                    'author'   => {
         | 
| 295 | 
            +
                      'name'  => author.name,
         | 
| 296 | 
            +
                      'email' => author.email
         | 
| 297 | 
            +
                    },
         | 
| 298 | 
            +
                    'committer' => {
         | 
| 299 | 
            +
                      'name'  => committer.name,
         | 
| 300 | 
            +
                      'email' => committer.email
         | 
| 301 | 
            +
                    },
         | 
| 302 | 
            +
                    'authored_date'  => authored_date.xmlschema,
         | 
| 303 | 
            +
                    'committed_date' => committed_date.xmlschema,
         | 
| 304 | 
            +
                  }
         | 
| 305 | 
            +
                end
         | 
| 306 | 
            +
              end # Commit
         | 
| 307 | 
            +
             | 
| 308 | 
            +
            end # Grit
         |