git-ds 0.9.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/README.rdoc +795 -0
- data/doc/Examples.rdoc +36 -0
- data/doc/examples/key_value/kv_get.rb +29 -0
- data/doc/examples/key_value/kv_init.rb +20 -0
- data/doc/examples/key_value/kv_list.rb +28 -0
- data/doc/examples/key_value/kv_remove.rb +29 -0
- data/doc/examples/key_value/kv_set.rb +39 -0
- data/doc/examples/key_value/model.rb +156 -0
- data/doc/examples/key_value/test.rb +50 -0
- data/doc/examples/test_suite/model.rb +503 -0
- data/doc/examples/test_suite/test.rb +173 -0
- data/doc/examples/test_suite/ts_add_bug.rb +65 -0
- data/doc/examples/test_suite/ts_add_module.rb +74 -0
- data/doc/examples/test_suite/ts_add_module_to_test.rb +78 -0
- data/doc/examples/test_suite/ts_add_test.rb +77 -0
- data/doc/examples/test_suite/ts_add_test_suite.rb +65 -0
- data/doc/examples/test_suite/ts_add_test_to_bug.rb +76 -0
- data/doc/examples/test_suite/ts_init.rb +20 -0
- data/doc/examples/test_suite/ts_list.rb +118 -0
- data/doc/examples/test_suite/ts_perform_test.rb +104 -0
- data/doc/examples/test_suite/ts_update_bugs.rb +58 -0
- data/doc/examples/user_group/model.rb +265 -0
- data/doc/examples/user_group/test.rb +64 -0
- data/doc/examples/user_group/ug_add_group.rb +39 -0
- data/doc/examples/user_group/ug_add_group_user.rb +36 -0
- data/doc/examples/user_group/ug_add_user.rb +39 -0
- data/doc/examples/user_group/ug_init.rb +20 -0
- data/doc/examples/user_group/ug_list.rb +32 -0
- data/lib/git-ds.rb +14 -0
- data/lib/git-ds/config.rb +53 -0
- data/lib/git-ds/database.rb +289 -0
- data/lib/git-ds/exec_cmd.rb +107 -0
- data/lib/git-ds/index.rb +205 -0
- data/lib/git-ds/model.rb +136 -0
- data/lib/git-ds/model/db_item.rb +42 -0
- data/lib/git-ds/model/fs_item.rb +51 -0
- data/lib/git-ds/model/item.rb +428 -0
- data/lib/git-ds/model/item_list.rb +97 -0
- data/lib/git-ds/model/item_proxy.rb +128 -0
- data/lib/git-ds/model/property.rb +144 -0
- data/lib/git-ds/model/root.rb +46 -0
- data/lib/git-ds/repo.rb +455 -0
- data/lib/git-ds/shared.rb +17 -0
- data/lib/git-ds/transaction.rb +77 -0
- data/tests/ut_database.rb +304 -0
- data/tests/ut_git_grit_equiv.rb +195 -0
- data/tests/ut_index.rb +203 -0
- data/tests/ut_model.rb +360 -0
- data/tests/ut_repo.rb +260 -0
- data/tests/ut_user_group_model.rb +316 -0
- metadata +142 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# :title: Git-DS::Shared
|
3
|
+
=begin rdoc
|
4
|
+
|
5
|
+
Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
6
|
+
=end
|
7
|
+
|
8
|
+
module GitDS
|
9
|
+
|
10
|
+
# =============================================================================
|
11
|
+
=begin rdoc
|
12
|
+
Exception raised when a repo-backed object does not exist
|
13
|
+
=end
|
14
|
+
class ObjectNotFound < NameError
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# :title: Git-DS::Transaction
|
3
|
+
=begin rdoc
|
4
|
+
|
5
|
+
Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
6
|
+
=end
|
7
|
+
|
8
|
+
require 'git-ds/shared'
|
9
|
+
require 'git-ds/exec_cmd'
|
10
|
+
|
11
|
+
module GitDS
|
12
|
+
|
13
|
+
=begin rdoc
|
14
|
+
Exception raised to rollback a transaction.
|
15
|
+
=end
|
16
|
+
class TransactionRollback < RuntimeError
|
17
|
+
end
|
18
|
+
|
19
|
+
=begin rdoc
|
20
|
+
A Transaction takes a code block and guarantees that all of its commands, or
|
21
|
+
none, are executed. Transactions can be nested.
|
22
|
+
|
23
|
+
Usage:
|
24
|
+
db.transaction { |trans, idx| ... }
|
25
|
+
=end
|
26
|
+
class Transaction < ExecCmd
|
27
|
+
|
28
|
+
attr_reader :propagate_exceptions
|
29
|
+
|
30
|
+
=begin rdoc
|
31
|
+
A transaction is considered successful if the transaction block executes with
|
32
|
+
no exceptions. If a block must exit prematurely and abort the transaction,
|
33
|
+
it should use the rollback method.
|
34
|
+
|
35
|
+
Note that exceptions are propagated to the parent if transaction is nested;
|
36
|
+
this permits an inner transaction to abort an outer transaction when
|
37
|
+
rollback() is called.
|
38
|
+
=end
|
39
|
+
def perform
|
40
|
+
@propagate_exceptions = false # propagation off by default
|
41
|
+
rv = true
|
42
|
+
begin
|
43
|
+
instance_eval(&self.block)
|
44
|
+
rescue Exception => e
|
45
|
+
raise e if self.nested
|
46
|
+
raise e if (not e.kind_of? TransactionRollback) && @propagate_exceptions
|
47
|
+
|
48
|
+
rv = false
|
49
|
+
end
|
50
|
+
|
51
|
+
if rv
|
52
|
+
self.index.build # required during nesting to support merge_and_branch
|
53
|
+
commit if not @nested
|
54
|
+
end
|
55
|
+
|
56
|
+
rv
|
57
|
+
end
|
58
|
+
|
59
|
+
=begin rdoc
|
60
|
+
Throw all non-rollback exceptions after aborting the transaction. This is
|
61
|
+
useful for debugging transaction blocks.
|
62
|
+
|
63
|
+
By default, all exceptions are caught and discarded.
|
64
|
+
=end
|
65
|
+
def propagate
|
66
|
+
@propagate_exceptions = true
|
67
|
+
end
|
68
|
+
|
69
|
+
=begin rdoc
|
70
|
+
Abort the transaction.
|
71
|
+
=end
|
72
|
+
def rollback
|
73
|
+
raise TransactionRollback.new
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,304 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
3
|
+
# Unit test for Git-DS Database class
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
require 'git-ds/database'
|
9
|
+
|
10
|
+
# StageIndex that tracks the number of writes made
|
11
|
+
class TestStageIndex < GitDS::StageIndex
|
12
|
+
attr_reader :write_count
|
13
|
+
|
14
|
+
def commit(msg, author=nil)
|
15
|
+
@write_count ||= 0
|
16
|
+
@write_count += 1
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def clear_write_count
|
21
|
+
@write_count = 0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class TC_GitDatabaseTest < Test::Unit::TestCase
|
26
|
+
TMP = File.dirname(__FILE__) + File::SEPARATOR + 'tmp'
|
27
|
+
|
28
|
+
attr_reader :db
|
29
|
+
|
30
|
+
def setup
|
31
|
+
FileUtils.remove_dir(TMP) if File.exist?(TMP)
|
32
|
+
Dir.mkdir(TMP)
|
33
|
+
|
34
|
+
path = TMP + File::SEPARATOR + 'db_test'
|
35
|
+
@db = GitDS::Database.new(path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def teardown
|
39
|
+
FileUtils.remove_dir(TMP) if File.exist?(TMP)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_connect
|
43
|
+
path = TMP + File::SEPARATOR + 'test-db-conn'
|
44
|
+
|
45
|
+
# no-create should refuse to create the database
|
46
|
+
GitDS::Database.connect(path, false)
|
47
|
+
assert( (not File.exist?(path + File::SEPARATOR + '.git')),
|
48
|
+
"Repo #{path} incorrectly created by connect" )
|
49
|
+
|
50
|
+
# ...otherwise connect should create the db
|
51
|
+
db = GitDS::Database.connect(path)
|
52
|
+
assert( File.exist?(path + File::SEPARATOR + '.git'),
|
53
|
+
"Repo #{path} not created by connect" )
|
54
|
+
|
55
|
+
# verify that closing the DB works.
|
56
|
+
db.close
|
57
|
+
|
58
|
+
# verify that a closed database cannot be acted on
|
59
|
+
# NOTE: this should verify every method
|
60
|
+
assert_raise( GitDS::InvalidDbError ) { db.exec }
|
61
|
+
assert_raise( GitDS::InvalidDbError ) { db.head }
|
62
|
+
assert_raise( GitDS::InvalidDbError ) { db.tree }
|
63
|
+
assert_raise( GitDS::InvalidDbError ) { db.index }
|
64
|
+
assert_raise( GitDS::InvalidDbError ) { db.transaction }
|
65
|
+
assert_raise( GitDS::InvalidDbError ) { db.purge }
|
66
|
+
assert_raise( GitDS::InvalidDbError ) { db.close }
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_create_delete
|
70
|
+
path = TMP + File::SEPARATOR + 'test-db'
|
71
|
+
|
72
|
+
# test that ctor creates a database by default
|
73
|
+
GitDS::Database.new(path)
|
74
|
+
assert( File.exist?(path + File::SEPARATOR + '.git'),
|
75
|
+
"Repo #{path} not created via new" )
|
76
|
+
|
77
|
+
# test that connecting to an existing database works
|
78
|
+
db = GitDS::Database.connect(path, false)
|
79
|
+
assert_not_nil( db, 'Connect to existing DB failed' )
|
80
|
+
|
81
|
+
# test that deleting a database works
|
82
|
+
db.purge
|
83
|
+
assert( (not File.exist?(path + File::SEPARATOR + '.git')),
|
84
|
+
"Repo #{path} did not get deleted" )
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_config
|
88
|
+
cfg = GitDS::RepoConfig.new(@db)
|
89
|
+
assert_equal('misc.stuff', cfg.path('stuff'), 'Default path is wrong')
|
90
|
+
|
91
|
+
cfg = GitDS::RepoConfig.new(@db, 'a_b c?d')
|
92
|
+
assert_equal('a-b-c-d.stuff', cfg.path('stuff'), 'Cleaned path is wrong')
|
93
|
+
|
94
|
+
cfg = GitDS::RepoConfig.new(@db, 'test')
|
95
|
+
cfg['stuff'] = '123456'
|
96
|
+
assert_equal('123456', cfg['stuff'], 'Could not write to section')
|
97
|
+
|
98
|
+
assert_equal('', @db.config['a test entry'], 'Test cfg entry not empty')
|
99
|
+
assert_equal('git-ds.a-test-entry', @db.config.path('a test entry'),
|
100
|
+
'Config object generated wrong path')
|
101
|
+
@db.config['a test entry'] = 'abcdef'
|
102
|
+
assert_equal('abcdef', @db.config['a test entry'], 'Cfg string incorrect')
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_staging
|
106
|
+
assert((not @db.staging?), 'db.staging not nil by default')
|
107
|
+
|
108
|
+
index = GitDS::StageIndex.new(@db)
|
109
|
+
@db.staging = index
|
110
|
+
assert_equal(index, @db.staging, 'db.staging= method failed')
|
111
|
+
|
112
|
+
@db.staging = nil
|
113
|
+
assert((not @db.staging?), 'db.staging=nil method failed')
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_exec
|
117
|
+
assert((not @db.staging?), 'db.staging not nil by default')
|
118
|
+
|
119
|
+
# test with no index
|
120
|
+
fname, data = 'a_test_file', '123456'
|
121
|
+
@db.exec { index.add(fname, data) }
|
122
|
+
assert( (not @db.staging?), 'exec created current index!')
|
123
|
+
|
124
|
+
# verify that exceptions do not break anything
|
125
|
+
assert_raises(RuntimeError, 'ExecCmd did not propagate error') {
|
126
|
+
@db.exec {
|
127
|
+
raise RuntimeError
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
# Verify that the exec worked
|
132
|
+
index = TestStageIndex.new(@db)
|
133
|
+
blob = index.current_tree./(fname)
|
134
|
+
assert_not_nil(blob, "db.exec did not create '#{fname}' in staging")
|
135
|
+
assert_equal(data, blob.data, "BLOB data for '#{fname}' does not match")
|
136
|
+
|
137
|
+
# test exec with staging set
|
138
|
+
@db.staging = index
|
139
|
+
@db.exec { index.delete(fname) }
|
140
|
+
index.build
|
141
|
+
blob = index.current_tree./(fname)
|
142
|
+
assert_equal(index, @db.staging, 'db.exec clobbered staging')
|
143
|
+
assert_nil(blob, "db.exec did not delete '#{fname}' in staging")
|
144
|
+
|
145
|
+
# test nested exec
|
146
|
+
name1, data1 = 'test1', '!!##$$@@^^**&&%%'
|
147
|
+
name2, data2 = 'test2', '_-_-_-'
|
148
|
+
@db.staging.clear_write_count
|
149
|
+
@db.exec {
|
150
|
+
index.add(name1, data1)
|
151
|
+
database.exec { index.add(name2, data2) }
|
152
|
+
}
|
153
|
+
@db.staging.commit('etc')
|
154
|
+
assert_equal(index, @db.staging,
|
155
|
+
'nested db.exec clobbered staging')
|
156
|
+
assert_equal(1, @db.staging.write_count,
|
157
|
+
'Nested exec caused > 1 write!')
|
158
|
+
|
159
|
+
# verify that both files in nested exec were created
|
160
|
+
blob = index.current_tree./(name1)
|
161
|
+
assert_not_nil(blob, "nested db.exec did not create '#{name1}' in staging")
|
162
|
+
assert_equal(data1, blob.data, "BLOB data for '#{name1}' does not match")
|
163
|
+
|
164
|
+
blob = index.current_tree./(name2)
|
165
|
+
assert_not_nil(blob, "nested db.exec did not create '#{name2}' in staging")
|
166
|
+
assert_equal(data2, blob.data, "BLOB data for '#{name2}' does not match")
|
167
|
+
|
168
|
+
# cleanup
|
169
|
+
index.delete(name1)
|
170
|
+
index.delete(name2)
|
171
|
+
@db.staging = nil
|
172
|
+
|
173
|
+
# test commits
|
174
|
+
num_commits = @db.commits.count
|
175
|
+
@db.exec {
|
176
|
+
index.add('exec-nested-commit-file-1', 'zaazza')
|
177
|
+
database.exec {
|
178
|
+
index.add('exec-nested-commit-file-2', 'plplpl')
|
179
|
+
commit
|
180
|
+
}
|
181
|
+
}
|
182
|
+
assert_equal(num_commits + 2, @db.commits.count, 'Nested commits failed')
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_transaction
|
186
|
+
assert((not @db.staging?), 'db.staging not nil by default')
|
187
|
+
|
188
|
+
# test with no index
|
189
|
+
fname, data = 'test_file_1', 'abcdef'
|
190
|
+
@db.transaction { index.add(fname, data) }
|
191
|
+
assert( (not @db.staging?), 'transaction created current index!')
|
192
|
+
|
193
|
+
# Verify that the transaction worked
|
194
|
+
index = TestStageIndex.new(@db)
|
195
|
+
blob = index.current_tree./(fname)
|
196
|
+
assert_not_nil(blob, "db.exec did not create '#{fname}' in staging")
|
197
|
+
assert_equal(data, blob.data, "BLOB data for '#{fname}' does not match")
|
198
|
+
|
199
|
+
# test rollback method
|
200
|
+
name1, data1 = 'test_file_2', '54321'
|
201
|
+
@db.transaction {
|
202
|
+
index.add(name1, data1)
|
203
|
+
rollback
|
204
|
+
}
|
205
|
+
blob = index.current_tree./(name1)
|
206
|
+
assert_nil(blob, "rollback still created '#{name1}' in staging")
|
207
|
+
|
208
|
+
# test nested rollback
|
209
|
+
@db.transaction {
|
210
|
+
index.add(name1, data1)
|
211
|
+
database.transaction { rollback }
|
212
|
+
}
|
213
|
+
blob = index.current_tree./(name1)
|
214
|
+
assert_nil(blob, "rollback still created '#{name1}' in staging")
|
215
|
+
|
216
|
+
# test rollback on raise
|
217
|
+
@db.transaction {
|
218
|
+
index.add(name1, data1)
|
219
|
+
raise "ROLLBACK!"
|
220
|
+
}
|
221
|
+
blob = index.current_tree./(name1)
|
222
|
+
assert_nil(blob, "transaction raise still created '#{name1}' in staging")
|
223
|
+
|
224
|
+
assert_raises(RuntimeError, 'Transaction did not propagate error') {
|
225
|
+
@db.transaction {
|
226
|
+
propagate
|
227
|
+
raise RuntimeError
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
# test commit
|
232
|
+
msg = 'SUCCESS'
|
233
|
+
name, email = 'me', 'myself@i.com'
|
234
|
+
@db.transaction {
|
235
|
+
author name, email
|
236
|
+
message(msg)
|
237
|
+
index.add('test-commit-file', 'zyxwvu')
|
238
|
+
}
|
239
|
+
cmt = @db.commits.last
|
240
|
+
assert_not_nil(cmt, "transaction did not create commit")
|
241
|
+
assert_equal(msg, cmt.message, "transaction commit has wrong message")
|
242
|
+
assert_equal(name, cmt.author.name, "transaction commit has wrong author")
|
243
|
+
assert_equal(email, cmt.author.email, "transaction commit has wrong email")
|
244
|
+
|
245
|
+
# test commits in nested transaction
|
246
|
+
num_commits = @db.commits.count
|
247
|
+
@db.transaction {
|
248
|
+
index.add('trans-nested-commit-file-1', '223344')
|
249
|
+
database.transaction {
|
250
|
+
index.add('trans-nested-commit-file-2', 'ccddff')
|
251
|
+
commit
|
252
|
+
}
|
253
|
+
}
|
254
|
+
assert_equal(num_commits + 2, @db.commits.count, 'Nested commits failed')
|
255
|
+
|
256
|
+
# test transaction with staging set
|
257
|
+
@db.staging = index
|
258
|
+
@db.transaction { index.delete(fname) }
|
259
|
+
blob = index.current_tree./(fname)
|
260
|
+
assert_equal(index, @db.staging, 'db.exec clobbered staging')
|
261
|
+
|
262
|
+
# test nested transactions
|
263
|
+
name2, data2 = 'xtest2', '~~~~~~~'
|
264
|
+
@db.staging.clear_write_count
|
265
|
+
@db.transaction {
|
266
|
+
index.add(name1, data1)
|
267
|
+
database.transaction { index.add(name2, data2) }
|
268
|
+
}
|
269
|
+
index.commit('etc') # existing index means both transactions are nested
|
270
|
+
assert_equal(index, @db.staging, 'nested transaction clobbered staging')
|
271
|
+
assert_equal(1, @db.staging.write_count,
|
272
|
+
'Nested transaction caused > 1 write!')
|
273
|
+
|
274
|
+
# verify that both files in nested exec were created
|
275
|
+
blob = index.current_tree./(name1)
|
276
|
+
assert_not_nil(blob, "nested db.exec did not create '#{name1}' in staging")
|
277
|
+
assert_equal(data1, blob.data, "BLOB data for '#{name1}' does not match")
|
278
|
+
|
279
|
+
blob = index.current_tree./(name2)
|
280
|
+
assert_not_nil(blob, "nested db.exec did not create '#{name2}' in staging")
|
281
|
+
assert_equal(data2, blob.data, "BLOB data for '#{name2}' does not match")
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_branch
|
285
|
+
|
286
|
+
num = @db.heads.count
|
287
|
+
@db.branch_and_merge {
|
288
|
+
index.add('tmp/1', '1')
|
289
|
+
}
|
290
|
+
assert_equal(num+1, @db.heads.count, 'Anon Branch&Merge failed!')
|
291
|
+
|
292
|
+
name = 'named branch'
|
293
|
+
num = @db.heads.count
|
294
|
+
@db.branch_and_merge(name) {
|
295
|
+
database.index.add('tmp/2', '2')
|
296
|
+
}
|
297
|
+
assert_equal(num+1, @db.heads.count, 'Named Branch&Merge failed!')
|
298
|
+
assert_equal(1, @db.heads.select{ |h| h.name == @db.clean_tag(name)}.count,
|
299
|
+
'Named Branch not present!')
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
@@ -0,0 +1,195 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
|
3
|
+
# Unit tests to ensure that assumptions about Grit behaving like Git still hold.
|
4
|
+
# Note: This is used to verify that Grit can be made to act like the Git
|
5
|
+
# command line, and to determine what Grit methods correspond to
|
6
|
+
# Git commands.
|
7
|
+
|
8
|
+
require 'test/unit'
|
9
|
+
require 'fileutils'
|
10
|
+
|
11
|
+
require 'rubygems'
|
12
|
+
require 'grit'
|
13
|
+
require 'grit/git-ruby'
|
14
|
+
|
15
|
+
# NOTES:
|
16
|
+
# `git read-tree --prefix=path #{sha}` will read SHA object into git at the
|
17
|
+
# specified path. git-write-tree can then be used to create the tree object
|
18
|
+
# for the entire index. NOTE: `export GIT_INDEX_FILE=/tmp/index` can be used
|
19
|
+
# to specify an index that is NOT the staging index. IMPORTANT!
|
20
|
+
# git-update-index --force-remove
|
21
|
+
# git-update-index --add --cacheinfo 100644 `echo '#{data}' | git-hash-object --stdin` #{path}
|
22
|
+
# echo '#{msg}' | git commit-tree #{sha}
|
23
|
+
# git-ls-files --stage #{path}
|
24
|
+
# git rev-parse --show-toplevel
|
25
|
+
# git rev-parse --show-prefix : path of curr dir from top_level. cdup = inverse.
|
26
|
+
|
27
|
+
# Grit:Git methods:
|
28
|
+
# object_exists? sha
|
29
|
+
# git_dir, work_tree
|
30
|
+
# fs_exist? path [on fs, in git dir]. fs_read|write|delete|move|mkdir|chmod
|
31
|
+
# commit_from_sha sha
|
32
|
+
# raw_git(command, index_filename) : note this is exec_in_git!
|
33
|
+
# get_object_by_sha1 sha
|
34
|
+
# object_exists? sha
|
35
|
+
# cat_file_type sha
|
36
|
+
# cat_file_size sha
|
37
|
+
# cat_file sha
|
38
|
+
# list_tree sha => ['blob'|'tree']['NAME'] = { :mode, :sha }
|
39
|
+
# ls_tree sha, paths, recursive = false -> cat-file output
|
40
|
+
# ls_tree_path(sha, path, append=nil) -> array of tree entries
|
41
|
+
# get_subtree(commit_sha, path) -> tree sha (or parent of, or /)
|
42
|
+
|
43
|
+
class TC_GitGritEquivalenceTest < Test::Unit::TestCase
|
44
|
+
TMP = File.dirname(__FILE__) + File::SEPARATOR + 'tmp'
|
45
|
+
GIT_REPO = 'git_repo'
|
46
|
+
GRIT_REPO = 'grit_repo'
|
47
|
+
|
48
|
+
attr_reader :repo # grit repo object
|
49
|
+
|
50
|
+
def exec_in_dir(dir, &block)
|
51
|
+
curr = Dir.getwd
|
52
|
+
Dir.chdir dir
|
53
|
+
result = yield
|
54
|
+
Dir.chdir curr
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
def git_exec(&block)
|
59
|
+
exec_in_dir(TMP + File::SEPARATOR + GIT_REPO, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
# this allows mimics Grit's use of anonymous (non-stage) indexes
|
63
|
+
def git_index_exec(filename, &block)
|
64
|
+
old_index = ENV[GIT_INDEX_FILE]
|
65
|
+
ENV[GIT_INDEX_FILE] = TMP + File::SEPARATOR + filename
|
66
|
+
rv = git_exec(&block)
|
67
|
+
ENV[GIT_INDEX_FILE] = old_index
|
68
|
+
rv
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create a Git repo and a Grit repo in a temporary directory
|
72
|
+
def setup
|
73
|
+
FileUtils.remove_dir(TMP) if File.exist?(TMP)
|
74
|
+
Dir.mkdir(TMP)
|
75
|
+
|
76
|
+
# init git repo
|
77
|
+
exec_in_dir(TMP) { `git init #{GIT_REPO}` }
|
78
|
+
@git_path = TMP + File::SEPARATOR + GIT_REPO
|
79
|
+
|
80
|
+
# init grit repo
|
81
|
+
@grit_path = TMP + File::SEPARATOR + GRIT_REPO
|
82
|
+
@repo = Grit::Repo.init(@grit_path)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Delete all repos
|
86
|
+
def teardown
|
87
|
+
FileUtils.remove_dir(TMP) if File.exist?(TMP)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Test that initializing a repository produces the same results
|
91
|
+
def test_init
|
92
|
+
sep = File::SEPARATOR
|
93
|
+
assert( File.exist?(TMP + sep + GIT_REPO + sep + '.git'),
|
94
|
+
'git repo was not created!')
|
95
|
+
assert( File.exist?(TMP + sep + GRIT_REPO + sep + '.git'),
|
96
|
+
'Grit repo was not created!')
|
97
|
+
end
|
98
|
+
|
99
|
+
# Test that generating an object SHA produces the same results
|
100
|
+
def test_object_sha
|
101
|
+
data = '01020304050607080900!@#$%^&*()_+='
|
102
|
+
git_sha = git_exec { `echo -n '#{data}' | git hash-object --stdin` }.chomp
|
103
|
+
grit_sha = Grit::GitRuby::Internal::LooseStorage.calculate_sha(data, 'blob')
|
104
|
+
assert_equal( git_sha, grit_sha, 'Git and Grit SHA differ')
|
105
|
+
end
|
106
|
+
|
107
|
+
# Test that adding a Blob object produces the same results
|
108
|
+
def test_add_blob_to_object_database
|
109
|
+
data = '7654321098!@$#%^&*()_-=+'
|
110
|
+
git_sha = git_exec {`echo -n '#{data}' | git hash-object -w --stdin`}.chomp
|
111
|
+
blob_data = git_exec { `git cat-file -p #{git_sha}` }
|
112
|
+
assert_equal(data, blob_data, 'Git cat-file does not match input')
|
113
|
+
|
114
|
+
|
115
|
+
grit_sha = @repo.git.put_raw_object(data, 'blob')
|
116
|
+
assert(@repo.git.object_exists?(grit_sha), 'Grit fails object_exists? call')
|
117
|
+
assert_equal(data, @repo.git.ruby_git.cat_file(grit_sha),
|
118
|
+
'Grit cat_file does not match input')
|
119
|
+
|
120
|
+
assert_equal( git_sha, grit_sha, 'Git and Grit SHA differ')
|
121
|
+
|
122
|
+
sep = File::SEPARATOR
|
123
|
+
path = sep + '.git' + sep + 'objects' + sep + git_sha[0,2] + sep +
|
124
|
+
git_sha[2..-1]
|
125
|
+
assert(File.exist?(@git_path + path), 'Git did not add blob to object DB')
|
126
|
+
assert(File.exist?(@grit_path + path), 'Grit did not add blob to object DB')
|
127
|
+
end
|
128
|
+
|
129
|
+
# Test that adding a Tree object produces the same results
|
130
|
+
def test_add_path_to_object_database
|
131
|
+
bdata = "123454321"
|
132
|
+
bsha = git_exec {`echo -n '#{bdata}' | git hash-object -w --stdin`}.chomp
|
133
|
+
grit_bsha = @repo.git.put_raw_object(bdata, 'blob')
|
134
|
+
|
135
|
+
tdata1 = "100644 blob #{bsha}\ttest_blob"
|
136
|
+
git_sha = git_exec {`echo -n '#{tdata1}' | git mktree`}.chomp
|
137
|
+
|
138
|
+
# Note the different format needed for Grit!
|
139
|
+
tdata1 = "100644 test_blob\0#{[bsha].pack('H*')}"
|
140
|
+
grit_sha = @repo.git.put_raw_object(tdata1, 'tree')
|
141
|
+
assert(@repo.git.object_exists?(grit_sha), 'Grit fails object_exists? call')
|
142
|
+
assert_not_nil( @repo.tree(grit_sha), 'Grit did not create valid tree')
|
143
|
+
|
144
|
+
assert_equal( git_sha, grit_sha, 'Git and Grit SHA differ')
|
145
|
+
end
|
146
|
+
|
147
|
+
# Test that adding a Blob to the (staging) index produces the same results
|
148
|
+
def test_add_blob_to_index
|
149
|
+
data = '....****....'
|
150
|
+
fname = 'test_add_blob'
|
151
|
+
|
152
|
+
# Add BLOB to Git object database
|
153
|
+
git_sha = git_exec {`echo -n '#{data}' | git hash-object -w --stdin`}.chomp
|
154
|
+
# Add BLOB to Git index
|
155
|
+
git_exec {`git update-index --add --cacheinfo 100644 #{git_sha} #{fname}`}
|
156
|
+
# Get SHA for filename in index
|
157
|
+
mode, sha, junk = git_exec { `git ls-files -s #{fname}` }.split(/\s/)
|
158
|
+
assert_equal(git_sha, sha, 'SHA in staging does not match input SHA')
|
159
|
+
|
160
|
+
idx = @repo.index
|
161
|
+
# Add BLOB to Grit index
|
162
|
+
idx.add( fname, data)
|
163
|
+
# Add BLOB to Grit object database and re-read
|
164
|
+
idx.read_tree(idx.write_tree(idx.tree))
|
165
|
+
# Get SHA for filename in index
|
166
|
+
blob = idx.current_tree/fname
|
167
|
+
assert_equal(data, blob.data, 'Grit index data does not match input data')
|
168
|
+
|
169
|
+
assert_equal( git_sha, blob.id, 'Git and Grit SHA differ')
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_add_path_to_index
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_remove_file_from_object_database
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_remove_path_from_object_database
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_remove_file_from_index
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_remove_path_from_index
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_list_tree_in_object_database
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_list_tree_in_index
|
191
|
+
end
|
192
|
+
|
193
|
+
# TODO: branch, commit, ref.
|
194
|
+
end
|
195
|
+
|