6 # class for author/committer/tagger lines
8 attr_accessor :name, :email, :date, :offset
11 m = /^(.*?) <(.*)> (\d+) ([+-])0*(\d+?)$/.match(str)
13 raise RuntimeError, "invalid %s header in commit" % key
17 @date = Time.at(Integer(m[3]))
18 @offset = (m[4] == "-" ? -1 : 1)*Integer(m[5])
22 "%s <%s> %s %+05d" % [@name, @email, @date.to_i, @offset]
26 # base class for all git objects (blob, tree, commit, tag)
28 attr_accessor :repository
30 def Object.from_raw(rawobject, repository = nil)
33 return Blob.from_raw(rawobject, repository)
35 return Tree.from_raw(rawobject, repository)
37 return Commit.from_raw(rawobject, repository)
39 return Tag.from_raw(rawobject, repository)
41 raise RuntimeError, "got invalid object-type"
46 raise NotImplemented, "abstract class"
50 raise NotImplemented, "abstract class"
54 raise NotImplemented, "abstract class"
58 Digest::SHA1.hexdigest("%s %d\0" % \
59 [self.type, self.raw_content.length] + \
65 attr_accessor :content
67 def self.from_raw(rawobject, repository)
68 new(rawobject.content)
71 def initialize(content, repository=nil)
73 @repository = repository
91 attr_accessor :mode, :name, :sha1
93 m = /^(\d+) (.*)\0(.{20})$/m.match(buf)
95 raise RuntimeError, "invalid directory entry"
99 @mode = (@mode << 3) | (i-'0'[0])
102 @sha1 = m[3].unpack("H*")[0]
104 if ![S_IFLNK, S_IFDIR, S_IFREG].include?(@mode & S_IFMT)
105 raise RuntimeError, "unknown type for directory entry"
118 raise RuntimeError, "unknown type for directory entry"
125 @mode = (@mode & ~S_IFMT) | S_IFLNK
127 @mode = (@mode & ~S_IFMT) | S_IFDIR
129 @mode = (@mode & ~S_IFMT) | S_IFREG
131 raise RuntimeError, "invalid type"
136 "%o %s\0%s" % [@mode, @name, [@sha1].pack("H*")]
143 def self.from_raw(rawobject, repository=nil)
145 rawobject.content.scan(/\d+ .*?\0.{20}/m) do |raw|
146 entries << DirectoryEntry.new(raw)
148 new(entries, repository)
151 def initialize(entries=[], repository = nil)
153 @repository = repository
161 # TODO: sort correctly
162 #@entry.sort { |a,b| a.name <=> b.name }.
164 collect { |e| e.raw }.join
168 class Commit < Object
169 attr_accessor :author, :committer, :tree, :parent, :message
171 def self.from_raw(rawobject, repository=nil)
173 tree = author = committer = nil
175 headers, message = rawobject.content.split(/\n\n/, 2)
176 headers = headers.split(/\n/).map { |header| header.split(/ /, 2) }
177 headers.each do |key, value|
184 author = UserInfo.new(value)
186 committer = UserInfo.new(value)
188 warn "unknown header '%s' in commit %s" % \
189 [key, rawobject.sha1.unpack("H*")[0]]
192 if not tree && author && committer
193 raise RuntimeError, "incomplete raw commit object"
195 new(tree, parent, author, committer, message, repository)
198 def initialize(tree, parent, author, committer, message, repository=nil)
202 @committer = committer
204 @repository = repository
212 "tree %s\n%sauthor %s\ncommitter %s\n\n" % [
214 @parent.collect { |i| "parent %s\n" % i }.join,
215 @author, @committer] + @message
220 attr_accessor :object, :type, :tag, :tagger, :message
222 def self.from_raw(rawobject, repository=nil)
223 headers, message = rawobject.content.split(/\n\n/, 2)
224 headers = headers.split(/\n/).map { |header| header.split(/ /, 2) }
225 headers.each do |key, value|
230 if !["blob", "tree", "commit", "tag"].include?(value)
231 raise RuntimeError, "invalid type in tag"
237 tagger = UserInfo.new(value)
239 warn "unknown header '%s' in tag" % \
240 [key, rawobject.sha1.unpack("H*")[0]]
242 if not object && type && tag && tagger
243 raise RuntimeError, "incomplete raw tag object"
246 new(object, type, tag, tagger, repository)
249 def initialize(object, type, tag, tagger, repository=nil)
254 @repository = repository
258 "object %s\ntype %s\ntag %s\ntagger %s\n\n" % \
259 [@object, @type, @tag, @tagger] + @message