added name-rev support for commit objects
[rubygit.git] / lib / git / object.rb
blob437246307936062cd268ee2a3017a702da786b49
1 module Git
2   
3   class GitTagNameDoesNotExist< StandardError 
4   end
5   
6   # represents a git object
7   class Object
8     
9     class AbstractObject
10       attr_accessor :sha, :size, :type, :mode
11     
12       @base = nil
13     
14       def initialize(base, sha)
15         @base = base
16         @sha = sha.to_s
17         @size = @base.lib.object_size(@sha)
18         setup
19       end
20     
21       def contents
22         @base.lib.object_contents(@sha)
23       end
24       
25       def contents_array
26         self.contents.split("\n")
27       end
28       
29       def setup
30         raise NotImplementedError
31       end
32       
33       def to_s
34         @sha
35       end
36       
37       def grep(string, path_limiter = nil, opts = {})
38         default = {:object => @sha, :path_limiter => path_limiter}
39         grep_options = default.merge(opts)
40         @base.lib.grep(string, grep_options)
41       end
42       
43       def diff(objectish)
44         Git::Diff.new(@base, @sha, objectish)
45       end
46       
47       def log(count = 30)
48         Git::Log.new(@base, count).object(@sha)
49       end
50       
51       # creates an archive of this object (tree)
52       def archive(file = nil, opts = {})
53         @base.lib.archive(@sha, file, opts)
54       end
55       
56     end
57   
58     
59     class Blob < AbstractObject
60       
61       def initialize(base, sha, mode = nil)
62         super(base, sha)
63         @mode = mode
64       end
65       
66       private
67       
68         def setup
69           @type = 'blob'
70         end
71     end
72   
73     class Tree < AbstractObject
74       
75       @trees = nil
76       @blobs = nil
77       
78       def initialize(base, sha, mode = nil)
79         super(base, sha)
80         @mode = mode
81       end
82             
83       def children
84         blobs.merge(subtrees)
85       end
86       
87       def blobs
88         check_tree
89         @blobs
90       end
91       alias_method :files, :blobs
92       
93       def trees
94         check_tree
95         @trees
96       end
97       alias_method :subtrees, :trees
98       alias_method :subdirectories, :trees
99        
100       private
101       
102         def setup
103           @type = 'tree'
104         end 
106         # actually run the git command
107         def check_tree
108           if !@trees
109             @trees = {}
110             @blobs = {}
111             data = @base.lib.ls_tree(@sha)
112             data['tree'].each { |k, d| @trees[k] = Tree.new(@base, d[:sha], d[:mode]) }
113             data['blob'].each { |k, d| @blobs[k] = Blob.new(@base, d[:sha], d[:mode]) }
114           end
115         end
116       
117     end
118   
119     class Commit < AbstractObject
120       
121       @tree = nil
122       @parents = nil
123       @author = nil
124       @committer = nil
125       @message = nil
126       
127       def message
128         check_commit
129         @message
130       end
131       
132       def name
133         @base.lib.namerev(@sha)
134       end
135       
136       def gtree
137         check_commit
138         Tree.new(@base, @tree)
139       end
140       
141       def parent
142         parents.first
143       end
144       
145       # array of all parent commits
146       def parents
147         check_commit
148         @parents        
149       end
150       
151       # git author
152       def author     
153         check_commit
154         @author
155       end
156       
157       def author_date
158         author.date
159       end
160       
161       # git author
162       def committer
163         check_commit
164         @committer
165       end
166       
167       def committer_date 
168         committer.date
169       end
170       alias_method :date, :committer_date
172       def diff_parent
173         diff(parent)
174       end
175             
176       private
177       
178         def setup
179           @type = 'commit'
180         end
181   
182         # see if this object has been initialized and do so if not
183         def check_commit
184           if !@tree
185             data = @base.lib.commit_data(@sha)
186             @committer = Git::Author.new(data['committer'])
187             @author = Git::Author.new(data['author'])
188             @tree = Tree.new(@base, data['tree'])
189             @parents = data['parent'].map{ |sha| Commit.new(@base, sha) }
190             @message = data['message'].chomp
191           end
192         end
193       
194     end
195   
196     class Tag < AbstractObject
197       attr_accessor :name
198       
199       def initialize(base, sha, name)
200         super(base, sha)
201         @name = name
202       end
203       
204       private
205         
206         def setup
207           @type = 'tag'
208         end
209         
210     end
211     
212     class << self
213       # if we're calling this, we don't know what type it is yet
214       # so this is our little factory method
215       def new(base, objectish, is_tag = false)
216         if is_tag
217           sha = base.lib.tag_sha(objectish)
218           if sha == ''
219             raise Git::GitTagNameDoesNotExist.new(objectish)
220           end
221           return Tag.new(base, sha, objectish)
222         else
223           sha = base.lib.revparse(objectish)
224           type = base.lib.object_type(sha) 
225         end
226         
227         klass =
228           case type
229           when /blob/:   Blob   
230           when /commit/: Commit
231           when /tree/:   Tree
232           end
233         klass::new(base, sha)
234       end
235     end 
236     
237   end