4 # class for author/committer/tagger lines
6 attr_accessor :name, :email, :date, :offset
9 m = /^(.*?) <(.*)> (\d+) ([+-])0*(\d+?)$/.match(str)
11 raise RuntimeError, "invalid %s header in commit" % key
15 @date = Time.at(Integer(m[3]))
16 @offset = (m[4] == "-" ? -1 : 1)*Integer(m[5])
20 "%s <%s> %s %+05d" % [@name, @email, @date.to_i, @offset]
24 # base class for all git objects (blob, tree, commit, tag)
26 attr_accessor :repository
28 def Object.from_raw(rawobject, repository = nil)
31 return Blob.from_raw(rawobject, repository)
33 return Tree.from_raw(rawobject, repository)
35 return Commit.from_raw(rawobject, repository)
37 return Tag.from_raw(rawobject, repository)
39 raise RuntimeError, "got invalid object-type"
44 raise NotImplemented, "abstract class"
48 raise NotImplemented, "abstract class"
52 raise NotImplemented, "abstract class"
56 Digest::SHA1.hexdigest("%s %d\0" % \
57 [self.type, self.raw_content.length] + \
63 attr_accessor :content
65 def self.from_raw(rawobject, repository)
66 new(rawobject.content)
69 def initialize(content, repository=nil)
71 @repository = repository
89 attr_accessor :mode, :name, :sha1
91 m = /^(\d+) (.*)\0(.{20})$/m.match(buf)
93 raise RuntimeError, "invalid directory entry"
97 @mode = (@mode << 3) | (i-'0'[0])
100 @sha1 = m[3].unpack("H*")[0]
102 if ![S_IFLNK, S_IFDIR, S_IFREG].include?(@mode & S_IFMT)
103 raise RuntimeError, "unknown type for directory entry"
116 raise RuntimeError, "unknown type for directory entry"
123 @mode = (@mode & ~S_IFMT) | S_IFLNK
125 @mode = (@mode & ~S_IFMT) | S_IFDIR
127 @mode = (@mode & ~S_IFMT) | S_IFREG
129 raise RuntimeError, "invalid type"
134 "%o %s\0%s" % [@mode, @name, [@sha1].pack("H*")]
141 def self.from_raw(rawobject, repository=nil)
143 rawobject.content.scan(/\d+ .*?\0.{20}/m) do |raw|
144 entries << DirectoryEntry.new(raw)
146 new(entries, repository)
149 def initialize(entries=[], repository = nil)
151 @repository = repository
159 # TODO: sort correctly
160 #@entry.sort { |a,b| a.name <=> b.name }.
162 collect { |e| e.raw }.join
166 class Commit < Object
167 attr_accessor :author, :committer, :tree, :parent, :message
169 def self.from_raw(rawobject, repository=nil)
171 tree = author = committer = nil
173 headers, message = rawobject.content.split(/\n\n/, 2)
174 headers = headers.split(/\n/).map { |header| header.split(/ /, 2) }
175 headers.each do |key, value|
182 author = UserInfo.new(value)
184 committer = UserInfo.new(value)
186 raise RuntimeError, "invalid header %s in commit" % key
189 if not tree && author && committer
190 raise RuntimeError, "incomplete raw commit object"
192 new(tree, parent, author, committer, message, repository)
195 def initialize(tree, parent, author, committer, message, repository=nil)
199 @committer = committer
201 @repository = repository
209 "tree %s\n%sauthor %s\ncommitter %s\n\n" % [
211 @parent.collect { |i| "parent %s\n" % i }.join,
212 @author, @committer] + @message
217 attr_accessor :object, :type, :tag, :tagger, :message
219 def self.from_raw(rawobject, repository=nil)
220 headers, message = rawobject.content.split(/\n\n/, 2)
221 headers = headers.split(/\n/).map { |header| header.split(/ /, 2) }
222 headers.each do |key, value|
227 if !["blob", "tree", "commit", "tag"].include?(value)
228 raise RuntimeError, "invalid type in tag"
234 tagger = UserInfo.new(value)
236 raise RuntimeError, "invalid header %s in commit" % key
239 new(object, type, tag, tagger, repository)
242 def initialize(object, type, tag, tagger, repository=nil)
247 @repository = repository
251 "object %s\ntype %s\ntag %s\ntagger %s\n\n" % \
252 [@object, @type, @tag, @tagger] + @message