Commit a1b2498e1161b1eb831fd2519bca054f88030502

added refs super class for tag & head + added remote subclass

Commit diff

lib/grit.rb

 
1616require 'grit/lazy'
1717require 'grit/errors'
1818require 'grit/git'
19require 'grit/head'
20require 'grit/tag'
19require 'grit/ref'
2120require 'grit/commit'
2221require 'grit/tree'
2322require 'grit/blob'
toggle raw diff

lib/grit/head.rb

 
0module Grit
1 HEAD_PREFIX = 'refs/heads'
2
3 # A Head is a named reference to a Commit. Every Head instance contains a name
4 # and a Commit object.
5 #
6 # r = Grit::Repo.new("/path/to/repo")
7 # h = r.heads.first
8 # h.name # => "master"
9 # h.commit # => #<Grit::Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455">
10 # h.commit.id # => "1c09f116cbc2cb4100fb6935bb162daa4723f455"
11 class Head
12 attr_reader :name
13 attr_reader :commit
14
15 # Instantiate a new Head
16 # +name+ is the name of the head
17 # +commit+ is the Commit that the head points to
18 #
19 # Returns Grit::Head (baked)
20 def initialize(name, commit)
21 @name = name
22 @commit = commit
23 end
24
25 # Find all Heads
26 # +repo+ is the Repo
27 # +options+ is a Hash of options
28 #
29 # Returns Grit::Head[] (baked)
30 def self.find_all(repo, options = {})
31 default_options = {:sort => "committerdate",
32 :format => "%(refname)%00%(objectname)"}
33
34 actual_options = default_options.merge(options)
35
36 output = repo.git.for_each_ref(actual_options, HEAD_PREFIX)
37
38 self.list_from_string(repo, output)
39 end
40
41 # Get the HEAD revision of the repo.
42 # +repo+ is the Repo
43 # +options+ is a Hash of options
44 #
45 # Returns Grit::Head (baked)
46 def self.current(repo, options = {})
47 head = File.open(File.join(repo.path, 'HEAD')).read.chomp
48 if /ref: refs\/heads\/(.*)/.match(head)
49 self.new($1, repo.git.rev_parse(options, 'HEAD'))
50 end
51 end
52
53 # Parse out head information into an array of baked head objects
54 # +repo+ is the Repo
55 # +text+ is the text output from the git command
56 #
57 # Returns Grit::Head[] (baked)
58 def self.list_from_string(repo, text)
59 heads = []
60
61 text.split("\n").each do |line|
62 heads << self.from_string(repo, line)
63 end
64
65 heads
66 end
67
68 # Create a new Head instance from the given string.
69 # +repo+ is the Repo
70 # +line+ is the formatted head information
71 #
72 # Format
73 # name: [a-zA-Z_/]+
74 # <null byte>
75 # id: [0-9A-Fa-f]{40}
76 #
77 # Returns Grit::Head (baked)
78 def self.from_string(repo, line)
79 full_name, id = line.split("\0")
80 name = full_name.sub("#{HEAD_PREFIX}/", '')
81 commit = Commit.create(repo, :id => id)
82 self.new(name, commit)
83 end
84
85 # Pretty object inspection
86 def inspect
87 %Q{#<Grit::Head "#{@name}">}
88 end
89 end # Head
90
91end # Grit
toggle raw diff

lib/grit/ref.rb

 
1module Grit
2
3 class Ref
4
5 class << self
6
7 # Find all Refs
8 # +repo+ is the Repo
9 # +options+ is a Hash of options
10 #
11 # Returns Grit::Ref[] (baked)
12 def find_all(repo, options = {})
13 default_options = {:sort => "committerdate",
14 :format => "%(refname)%00%(objectname)"}
15
16 actual_options = default_options.merge(options)
17
18 output = repo.git.for_each_ref(actual_options, prefix)
19
20 self.list_from_string(repo, output)
21 end
22
23 # Parse out ref information into an array of baked refs objects
24 # +repo+ is the Repo
25 # +text+ is the text output from the git command
26 #
27 # Returns Grit::Ref[] (baked)
28 def list_from_string(repo, text)
29 refs = []
30
31 text.split("\n").each do |line|
32 refs << self.from_string(repo, line)
33 end
34
35 refs.sort { | x, y | x.name <=> y.name }
36 end
37
38 # Create a new Ref instance from the given string.
39 # +repo+ is the Repo
40 # +line+ is the formatted head information
41 #
42 # Format
43 # name: [a-zA-Z_/]+
44 # <null byte>
45 # id: [0-9A-Fa-f]{40}
46 #
47 # Returns Grit::Ref (baked)
48 def from_string(repo, line)
49 full_name, id = line.split("\0")
50 name = full_name.sub("#{prefix}/", '')
51 commit = Commit.create(repo, :id => id)
52 self.new(name, commit)
53 end
54
55 protected
56
57 def prefix
58 "refs/#{name.to_s.gsub(/^.*::/, '').downcase}s"
59 end
60
61 end
62
63 attr_reader :name
64 attr_reader :commit
65
66 # Instantiate a new Head
67 # +name+ is the name of the head
68 # +commit+ is the Commit that the head points to
69 #
70 # Returns Grit::Head (baked)
71 def initialize(name, commit)
72 @name = name
73 @commit = commit
74 end
75
76 # Pretty object inspection
77 def inspect
78 %Q{#<#{self.class.name} "#{@name}">}
79 end
80 end # Ref
81
82 # A Head is a named reference to a Commit. Every Head instance contains a name
83 # and a Commit object.
84 #
85 # r = Grit::Repo.new("/path/to/repo")
86 # h = r.heads.first
87 # h.name # => "master"
88 # h.commit # => #<Grit::Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455">
89 # h.commit.id # => "1c09f116cbc2cb4100fb6935bb162daa4723f455"
90 class Head < Ref
91
92 # Get the HEAD revision of the repo.
93 # +repo+ is the Repo
94 # +options+ is a Hash of options
95 #
96 # Returns Grit::Head (baked)
97 def self.current(repo, options = {})
98 head = File.open(File.join(repo.path, 'HEAD')).read.chomp
99 if /ref: refs\/heads\/(.*)/.match(head)
100 self.new($1, repo.git.rev_parse(options, 'HEAD'))
101 end
102 end
103
104 end # Head
105
106 class Tag < Ref ; end
107
108 class Remote < Ref ; end
109
110end # Grit
toggle raw diff

lib/grit/repo.rb

 
6767 Tag.find_all(self)
6868 end
6969
70 # An array of Remote objects representing the remote branches in
71 # this repo
72 #
73 # Returns Grit::Remote[] (baked)
74 def remotes
75 Remote.find_all(self)
76 end
77
78 # An array of Ref objects representing the refs in
79 # this repo
80 #
81 # Returns Grit::Ref[] (baked)
82 def refs
83 [ Head.find_all(self), Tag.find_all(self), Remote.find_all(self) ].flatten
84 end
85
7086 # An array of Commit objects representing the history of a given ref/commit
7187 # +start+ is the branch/commit name (default 'master')
7288 # +max_count+ is the maximum number of commits to return (default 10)
toggle raw diff

lib/grit/tag.rb

 
0module Grit
1
2 class Tag
3 attr_reader :name
4 attr_reader :commit
5
6 # Instantiate a new Tag
7 # +name+ is the name of the head
8 # +commit+ is the Commit that the head points to
9 #
10 # Returns Grit::Tag (baked)
11 def initialize(name, commit)
12 @name = name
13 @commit = commit
14 end
15
16 # Find all Tags
17 # +repo+ is the Repo
18 # +options+ is a Hash of options
19 #
20 # Returns Grit::Tag[] (baked)
21 def self.find_all(repo, options = {})
22 default_options = {:sort => "committerdate",
23 :format => "%(refname)%00%(objectname)"}
24
25 actual_options = default_options.merge(options)
26
27 output = repo.git.for_each_ref(actual_options, "refs/tags")
28
29 self.list_from_string(repo, output)
30 end
31
32 # Parse out tag information into an array of baked Tag objects
33 # +repo+ is the Repo
34 # +text+ is the text output from the git command
35 #
36 # Returns Grit::Tag[] (baked)
37 def self.list_from_string(repo, text)
38 tags = []
39
40 text.split("\n").each do |line|
41 tags << self.from_string(repo, line)
42 end
43
44 tags
45 end
46
47 # Create a new Tag instance from the given string.
48 # +repo+ is the Repo
49 # +line+ is the formatted tag information
50 #
51 # Format
52 # name: [a-zA-Z_/]+
53 # <null byte>
54 # id: [0-9A-Fa-f]{40}
55 #
56 # Returns Grit::Tag (baked)
57 def self.from_string(repo, line)
58 full_name, id = line.split("\0")
59 name = full_name.split("/").last
60 commit = Commit.create(repo, :id => id)
61 self.new(name, commit)
62 end
63
64 # Pretty object inspection
65 def inspect
66 %Q{#<Grit::Tag "#{@name}">}
67 end
68 end # Tag
69
70end # Grit
toggle raw diff

test/fixtures/for_each_ref_remotes

 
toggle raw diff

test/test_remote.rb

 
1require File.dirname(__FILE__) + '/helper'
2
3class TestRemote < Test::Unit::TestCase
4 def setup
5 @r = Repo.new(GRIT_REPO)
6 Git.any_instance.expects(:for_each_ref).returns(fixture('for_each_ref_remotes'))
7 end
8
9 # inspect
10
11 def test_inspect
12 remote = @r.remotes.first
13 assert_equal %Q{#<Grit::Remote "#{remote.name}">}, remote.inspect
14 end
15end
toggle raw diff

test/test_repo.rb

 
44 def setup
55 @r = Repo.new(GRIT_REPO)
66 end
7
7
88 # new
9
9
1010 def test_new_should_raise_on_invalid_repo_location
1111 assert_raise(InvalidGitRepositoryError) do
1212 Repo.new("/tmp")
1313 end
1414 end
15
15
1616 def test_new_should_raise_on_non_existant_path
1717 assert_raise(NoSuchPathError) do
1818 Repo.new("/foobar")
1919 end
2020 end
21
21
2222 # descriptions
23
23
2424 def test_description
2525 assert_equal "Unnamed repository; edit this file to name it for gitweb.", @r.description
2626 end
27
27
28 # refs
29
30 def test_refs_should_return_array_of_ref_objects
31 @r.refs.each do |ref|
32 assert ref.is_a? Grit::Ref
33 end
34 end
35
2836 # heads
29
37
3038 def test_heads_should_return_array_of_head_objects
3139 @r.heads.each do |head|
3240 assert_equal Grit::Head, head.class
3341 end
3442 end
35
43
3644 def test_heads_should_populate_head_data
3745 Git.any_instance.expects(:for_each_ref).returns(fixture('for_each_ref'))
38
46
3947 head = @r.heads.first
40
48
4149 assert_equal 'master', head.name
4250 assert_equal '634396b2f541a9f2d58b00be1a07f0c358b999b3', head.commit.id
4351 end
44
52
4553 # branches
46
54
4755 def test_branches
4856 # same as heads
4957 end
50
58
5159 # commits
52
60
5361 def test_commits
5462 Git.any_instance.expects(:rev_list).returns(fixture('rev_list'))
55
63
5664 commits = @r.commits('master', 10)
57
65
5866 c = commits[0]
5967 assert_equal '4c8124ffcf4039d292442eeccabdeca5af5c5017', c.id
6068 assert_equal ["634396b2f541a9f2d58b00be1a07f0c358b999b3"], c.parents.map { |p| p.id }
7474 assert_equal "tom@mojombo.com", c.committer.email
7575 assert_equal Time.at(1191999972), c.committed_date
7676 assert_equal "implement Grit#heads", c.message
77
77
7878 c = commits[1]
7979 assert_equal [], c.parents
80
80
8181 c = commits[2]
8282 assert_equal ["6e64c55896aabb9a7d8e9f8f296f426d21a78c2c", "7f874954efb9ba35210445be456c74e037ba6af2"], c.parents.map { |p| p.id }
8383 assert_equal "Merge branch 'site'\n\n * Some other stuff\n * just one more", c.message
8484 assert_equal "Merge branch 'site'", c.short_message
8585 end
86
86
8787 # commit_count
88
88
8989 def test_commit_count
9090 Git.any_instance.expects(:rev_list).with({}, 'master').returns(fixture('rev_list_count'))
91
91
9292 assert_equal 655, @r.commit_count('master')
9393 end
94
94
9595 # commit
96
96
9797 def test_commit
9898 commit = @r.commit('634396b2f541a9f2d58b00be1a07f0c358b999b3')
99
99
100100 assert_equal "634396b2f541a9f2d58b00be1a07f0c358b999b3", commit.id
101101 end
102
102
103103 # tree
104
104
105105 def test_tree
106106 Git.any_instance.expects(:ls_tree).returns(fixture('ls_tree_a'))
107107 tree = @r.tree('master')
108
108
109109 assert_equal 4, tree.contents.select { |c| c.instance_of?(Blob) }.size
110110 assert_equal 3, tree.contents.select { |c| c.instance_of?(Tree) }.size
111111 end
112
112
113113 # blob
114
114
115115 def test_blob
116116 Git.any_instance.expects(:cat_file).returns(fixture('cat_file_blob'))
117117 blob = @r.blob("abc")
118118 assert_equal "Hello world", blob.data
119119 end
120
120
121121 # init_bare
122
122
123123 def test_init_bare
124124 Git.any_instance.expects(:init).returns(true)
125125 Repo.expects(:new).with("/foo/bar.git")
126126 Repo.init_bare("/foo/bar.git")
127127 end
128
128
129129 def test_init_bare_with_options
130130 Git.any_instance.expects(:init).with(
131131 :template => "/baz/sweet").returns(true)
132132 Repo.expects(:new).with("/foo/bar.git")
133133 Repo.init_bare("/foo/bar.git", :template => "/baz/sweet")
134134 end
135
135
136136 # fork_bare
137
137
138138 def test_fork_bare
139139 Git.any_instance.expects(:clone).with(
140 {:bare => true, :shared => true},
140 {:bare => true, :shared => true},
141141 "#{absolute_project_path}/.git",
142142 "/foo/bar.git").returns(nil)
143143 Repo.expects(:new)
144
144
145145 @r.fork_bare("/foo/bar.git")
146146 end
147
147
148148 def test_fork_bare_with_options
149149 Git.any_instance.expects(:clone).with(
150 {:bare => true, :shared => true, :template => '/awesome'},
150 {:bare => true, :shared => true, :template => '/awesome'},
151151 "#{absolute_project_path}/.git",
152152 "/foo/bar.git").returns(nil)
153153 Repo.expects(:new)
154
154
155155 @r.fork_bare("/foo/bar.git", :template => '/awesome')
156156 end
157
157
158158 # diff
159
159
160160 def test_diff
161161 Git.any_instance.expects(:diff).with({}, 'master^', 'master', '--')
162162 @r.diff('master^', 'master')
163
163
164164 Git.any_instance.expects(:diff).with({}, 'master^', 'master', '--', 'foo/bar')
165165 @r.diff('master^', 'master', 'foo/bar')
166
166
167167 Git.any_instance.expects(:diff).with({}, 'master^', 'master', '--', 'foo/bar', 'foo/baz')
168168 @r.diff('master^', 'master', 'foo/bar', 'foo/baz')
169169 end
170
170
171171 # commit_diff
172
172
173173 def test_diff
174174 Git.any_instance.expects(:diff).returns(fixture('diff_p'))
175175 diffs = @r.commit_diff('master')
176
176
177177 assert_equal 15, diffs.size
178178 end
179
179
180180 # init bare
181
181
182182 # archive
183
183
184184 def test_archive_tar
185185 @r.archive_tar
186186 end
187
187
188188 # archive_tar_gz
189
189
190190 def test_archive_tar_gz
191191 @r.archive_tar_gz
192192 end
193
193
194194 # enable_daemon_serve
195
195
196196 def test_enable_daemon_serve
197197 FileUtils.expects(:touch).with(File.join(@r.path, 'git-daemon-export-ok'))
198198 @r.enable_daemon_serve
199199 end
200
200
201201 # disable_daemon_serve
202
202
203203 def test_disable_daemon_serve
204204 FileUtils.expects(:rm_f).with(File.join(@r.path, 'git-daemon-export-ok'))
205205 @r.disable_daemon_serve
206206 end
207
207
208208 # alternates
209
209
210210 def test_alternates_with_two_alternates
211211 File.expects(:exist?).with("#{absolute_project_path}/.git/objects/info/alternates").returns(true)
212212 File.expects(:read).returns("/path/to/repo1/.git/objects\n/path/to/repo2.git/objects\n")
213
213
214214 assert_equal ["/path/to/repo1/.git/objects", "/path/to/repo2.git/objects"], @r.alternates
215215 end
216
216
217217 def test_alternates_no_file
218218 File.expects(:exist?).returns(false)
219
219
220220 assert_equal [], @r.alternates
221221 end
222
222
223223 # alternates=
224
224
225225 def test_alternates_setter_ok
226226 alts = %w{/path/to/repo.git/objects /path/to/repo2.git/objects}
227
227
228228 alts.each do |alt|
229229 File.expects(:exist?).with(alt).returns(true)
230230 end
231
231
232232 File.any_instance.expects(:write).with(alts.join("\n"))
233
233
234234 assert_nothing_raised do
235235 @r.alternates = alts
236236 end
237237 end
238
238
239239 def test_alternates_setter_bad
240240 alts = %w{/path/to/repo.git/objects}
241
241
242242 alts.each do |alt|
243243 File.expects(:exist?).with(alt).returns(false)
244244 end
245
245
246246 File.any_instance.expects(:write).never
247
247
248248 assert_raise RuntimeError do
249249 @r.alternates = alts
250250 end
251251 end
252
252
253253 def test_alternates_setter_empty
254254 File.expects(:delete)
255
255
256256 @r.alternates = []
257257 end
258
258
259259 # inspect
260
260
261261 def test_inspect
262262 assert_equal %Q{#<Grit::Repo "#{File.expand_path(GRIT_REPO)}/.git">}, @r.inspect
263263 end
toggle raw diff