git-db 0.1.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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +59 -0
- data/Rakefile +43 -0
- data/VERSION +1 -0
- data/bin/git-db +17 -0
- data/features/git-db.feature +9 -0
- data/features/step_definitions/git-db_steps.rb +0 -0
- data/features/support/env.rb +4 -0
- data/git-db.gemspec +91 -0
- data/lib/git-db/commands/receive-pack.rb +73 -0
- data/lib/git-db/commands/upload-pack.rb +140 -0
- data/lib/git-db/commands.rb +21 -0
- data/lib/git-db/database.rb +134 -0
- data/lib/git-db/objects/base.rb +34 -0
- data/lib/git-db/objects/blob.rb +11 -0
- data/lib/git-db/objects/commit.rb +49 -0
- data/lib/git-db/objects/entry.rb +27 -0
- data/lib/git-db/objects/tag.rb +7 -0
- data/lib/git-db/objects/tree.rb +45 -0
- data/lib/git-db/objects.rb +20 -0
- data/lib/git-db/pack.rb +182 -0
- data/lib/git-db/protocol.rb +73 -0
- data/lib/git-db/utility/counting_io.rb +24 -0
- data/lib/git-db/utility.rb +3 -0
- data/lib/git-db.rb +68 -0
- data/spec/git-db/commands_spec.rb +23 -0
- data/spec/git-db/objects/base_spec.rb +27 -0
- data/spec/git-db/objects/entry_spec.rb +25 -0
- data/spec/git-db/objects/tag_spec.rb +14 -0
- data/spec/git-db/objects/tree_spec.rb +42 -0
- data/spec/git-db/utility/counting_io_spec.rb +30 -0
- data/spec/git-db_spec.rb +45 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +11 -0
- metadata +118 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
class GitDB::Objects::Commit < GitDB::Objects::Base
|
2
|
+
|
3
|
+
def raw
|
4
|
+
"commit #{data.length}\000#{data}"
|
5
|
+
end
|
6
|
+
|
7
|
+
def type
|
8
|
+
GitDB::OBJ_COMMIT
|
9
|
+
end
|
10
|
+
|
11
|
+
def message
|
12
|
+
data.split("\n\n", 2).last
|
13
|
+
end
|
14
|
+
|
15
|
+
def author
|
16
|
+
attributes['author'].first
|
17
|
+
end
|
18
|
+
|
19
|
+
def committer
|
20
|
+
attributes['committer'].first
|
21
|
+
end
|
22
|
+
|
23
|
+
def tree
|
24
|
+
attributes['tree'].first
|
25
|
+
end
|
26
|
+
|
27
|
+
def parents
|
28
|
+
attributes['parent']
|
29
|
+
end
|
30
|
+
|
31
|
+
def properties
|
32
|
+
[:tree, :parents, :author, :committer, :message]
|
33
|
+
end
|
34
|
+
|
35
|
+
private ######################################################################
|
36
|
+
|
37
|
+
def attributes
|
38
|
+
@attributes ||= begin
|
39
|
+
attributes = data.split("\n\n", 2).first
|
40
|
+
attributes.split("\n").inject({}) do |hash, line|
|
41
|
+
key, value = line.split(' ', 2)
|
42
|
+
hash[key] ||= []
|
43
|
+
hash[key] << value
|
44
|
+
hash
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
class GitDB::Objects::Entry < GitDB::Objects::Base
|
4
|
+
|
5
|
+
attr_reader :sha, :permissions, :name
|
6
|
+
|
7
|
+
def initialize(sha, permissions, name)
|
8
|
+
@sha = sha
|
9
|
+
@permissions = permissions
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
|
13
|
+
def properties
|
14
|
+
[:permissions, :name]
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_hash
|
18
|
+
{ :sha => sha, :permissions => permissions, :name => name }
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_json
|
22
|
+
to_hash.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
private ######################################################################
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
class GitDB::Objects::Tree < GitDB::Objects::Base
|
4
|
+
|
5
|
+
# TODO: memoize entries
|
6
|
+
|
7
|
+
def entries
|
8
|
+
entries = []
|
9
|
+
stream = StringIO.new(data)
|
10
|
+
until stream.eof?
|
11
|
+
perms = read_until(stream, ' ').to_i
|
12
|
+
name = read_until(stream, 0.chr)
|
13
|
+
sha = GitDB.sha1_to_hex(stream.read(20))
|
14
|
+
entries << GitDB::Objects::Entry.new(sha, perms, name)
|
15
|
+
end
|
16
|
+
entries
|
17
|
+
end
|
18
|
+
|
19
|
+
def properties
|
20
|
+
[:entries]
|
21
|
+
end
|
22
|
+
|
23
|
+
def raw
|
24
|
+
"tree #{data.length}\000#{data}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def type
|
28
|
+
GitDB::OBJ_TREE
|
29
|
+
end
|
30
|
+
|
31
|
+
private ######################################################################
|
32
|
+
|
33
|
+
def read_until(stream, separator)
|
34
|
+
data = ""
|
35
|
+
char = ""
|
36
|
+
loop do
|
37
|
+
char = stream.read(1)
|
38
|
+
break if char.nil?
|
39
|
+
break if char == separator
|
40
|
+
data << char
|
41
|
+
end
|
42
|
+
data
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GitDB::Objects;
|
2
|
+
|
3
|
+
def self.new_from_type(type, data)
|
4
|
+
case type
|
5
|
+
when GitDB::OBJ_COMMIT then GitDB::Objects::Commit.new(data)
|
6
|
+
when GitDB::OBJ_TREE then GitDB::Objects::Tree.new(data)
|
7
|
+
when GitDB::OBJ_BLOB then GitDB::Objects::Blob.new(data)
|
8
|
+
when GitDB::OBJ_TAG then GitDB::Objects::Tag.new(data)
|
9
|
+
else raise "Unknown object type: #{type}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'git-db/objects/base'
|
16
|
+
require 'git-db/objects/blob'
|
17
|
+
require 'git-db/objects/commit'
|
18
|
+
require 'git-db/objects/entry'
|
19
|
+
require 'git-db/objects/tag'
|
20
|
+
require 'git-db/objects/tree'
|
data/lib/git-db/pack.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'stringio'
|
3
|
+
require 'zlib'
|
4
|
+
|
5
|
+
class GitDB::Pack
|
6
|
+
|
7
|
+
PackObject = Struct.new(:type, :offset, :data)
|
8
|
+
|
9
|
+
attr_reader :io
|
10
|
+
|
11
|
+
def initialize(io)
|
12
|
+
@io = GitDB::Utility::CountingIO.new(io)
|
13
|
+
end
|
14
|
+
|
15
|
+
def read
|
16
|
+
header = io.read(12)
|
17
|
+
return nil unless header
|
18
|
+
|
19
|
+
signature, version, entries = header.unpack("a4NN")
|
20
|
+
raise 'invalid pack signature' unless signature == 'PACK'
|
21
|
+
raise 'invalid version' unless version == 2
|
22
|
+
|
23
|
+
objects = {}
|
24
|
+
|
25
|
+
1.upto(entries) do
|
26
|
+
object_offset = io.offset
|
27
|
+
|
28
|
+
type, size = unpack_pack_header(io)
|
29
|
+
|
30
|
+
object = case type
|
31
|
+
when 1 then
|
32
|
+
GitDB::Objects::Commit.new(read_compressed(io))
|
33
|
+
when 2 then
|
34
|
+
GitDB::Objects::Tree.new(read_compressed(io))
|
35
|
+
when 3 then
|
36
|
+
GitDB::Objects::Blob.new(read_compressed(io))
|
37
|
+
when 4 then
|
38
|
+
GitDB::Objects::Tag.new(read_compressed(io))
|
39
|
+
when 5 then
|
40
|
+
raise 'Invalid Type: 5'
|
41
|
+
when 6 then
|
42
|
+
offset = object_offset - unpack_delta_size(io)
|
43
|
+
patch = read_compressed(io)
|
44
|
+
base = objects[offset]
|
45
|
+
base.class.new(apply_patch(base.data, patch))
|
46
|
+
when 7 then
|
47
|
+
# TODO
|
48
|
+
sha = io.read(20)
|
49
|
+
# base = lookup_by_sha(sha)
|
50
|
+
patch = read_compressed(io)
|
51
|
+
# base.class.new(apply_patch(base.data, patch))
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
objects[object_offset] = object
|
56
|
+
end
|
57
|
+
|
58
|
+
GitDB.log(objects.values.map { |o| o.inspect })
|
59
|
+
|
60
|
+
io.read(20)
|
61
|
+
|
62
|
+
objects.values.compact
|
63
|
+
end
|
64
|
+
|
65
|
+
def write(entries)
|
66
|
+
buffer = ""
|
67
|
+
signature = ["PACK", 2, entries.length].pack("a4NN")
|
68
|
+
#GitDB.log("SIGNATURE: #{signature}")
|
69
|
+
io.write(signature)
|
70
|
+
buffer << signature
|
71
|
+
|
72
|
+
entries.each do |entry|
|
73
|
+
header = pack_pack_header(entry.type, entry.data.length)
|
74
|
+
#GitDB.log("HEADER: #{header.inspect}")
|
75
|
+
io.write(header)
|
76
|
+
buffer << header
|
77
|
+
compressed = Zlib::Deflate.deflate(entry.data)
|
78
|
+
io.write(compressed)
|
79
|
+
buffer << compressed
|
80
|
+
end
|
81
|
+
|
82
|
+
#GitDB.log("BUFFER: #{buffer.inspect}")
|
83
|
+
signature = GitDB::hex_to_sha1(Digest::SHA1.hexdigest(buffer))
|
84
|
+
#GitDB.log("SIGNATURE: #{signature.inspect}")
|
85
|
+
io.write(signature)
|
86
|
+
io.flush
|
87
|
+
end
|
88
|
+
|
89
|
+
private ######################################################################
|
90
|
+
|
91
|
+
def apply_patch(original, patch)
|
92
|
+
patch_stream = StringIO.new(patch)
|
93
|
+
source_size = unpack_size(patch_stream)
|
94
|
+
destination_size = unpack_size(patch_stream)
|
95
|
+
|
96
|
+
data = ""
|
97
|
+
|
98
|
+
until patch_stream.eof?
|
99
|
+
offset = size = 0
|
100
|
+
cmd = patch_stream.read(1)[0]
|
101
|
+
if (cmd & 0x80) != 0
|
102
|
+
offset = (patch_stream.read(1)[0]) if (cmd & 0x01) != 0
|
103
|
+
offset |= (patch_stream.read(1)[0] << 8) if (cmd & 0x02) != 0
|
104
|
+
offset |= (patch_stream.read(1)[0] << 16) if (cmd & 0x04) != 0
|
105
|
+
offset |= (patch_stream.read(1)[0] << 24) if (cmd & 0x08) != 0
|
106
|
+
size = (patch_stream.read(1)[0]) if (cmd & 0x10) != 0
|
107
|
+
size |= (patch_stream.read(1)[0] << 8) if (cmd & 0x20) != 0
|
108
|
+
size |= (patch_stream.read(1)[0] << 16) if (cmd & 0x40) != 0
|
109
|
+
size = 0x10000 if size == 0
|
110
|
+
|
111
|
+
if ((offset + size) < size) ||
|
112
|
+
((offset + size) > source_size) ||
|
113
|
+
(size > destination_size)
|
114
|
+
break
|
115
|
+
end
|
116
|
+
data += original[offset,size]
|
117
|
+
elsif (cmd != 0)
|
118
|
+
data += patch_stream.read(cmd)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
data
|
123
|
+
end
|
124
|
+
|
125
|
+
def read_compressed(stream)
|
126
|
+
zstream = Zlib::Inflate.new
|
127
|
+
data = ""
|
128
|
+
loop do
|
129
|
+
data += zstream.inflate(stream.read(1))
|
130
|
+
break if zstream.finished?
|
131
|
+
end
|
132
|
+
data
|
133
|
+
end
|
134
|
+
|
135
|
+
def pack_pack_header(type, size)
|
136
|
+
data = ""
|
137
|
+
c = (type << 4) | (size & 15);
|
138
|
+
size >>= 4;
|
139
|
+
while (size > 0)
|
140
|
+
data << (c | 0x80).chr
|
141
|
+
c = size & 0x7f;
|
142
|
+
size >>= 7;
|
143
|
+
end
|
144
|
+
data << c.chr
|
145
|
+
end
|
146
|
+
|
147
|
+
def unpack_delta_size(stream)
|
148
|
+
c = stream.read(1)[0]
|
149
|
+
size = (c & 127)
|
150
|
+
while (c & 128) != 0
|
151
|
+
size += 1
|
152
|
+
c = stream.read(1)[0]
|
153
|
+
size = (size << 7) + (c & 127)
|
154
|
+
end
|
155
|
+
size
|
156
|
+
end
|
157
|
+
|
158
|
+
def unpack_pack_header(stream)
|
159
|
+
c = stream.read(1)[0]
|
160
|
+
type = (c >> 4) & 7
|
161
|
+
size = (c & 15)
|
162
|
+
shift = 4
|
163
|
+
while ((c & 0x80) != 0)
|
164
|
+
c = stream.read(1)[0]
|
165
|
+
size += ((c & 0x7f) << shift)
|
166
|
+
shift += 7
|
167
|
+
end
|
168
|
+
[type, size]
|
169
|
+
end
|
170
|
+
|
171
|
+
def unpack_size(stream)
|
172
|
+
size = shift = 0
|
173
|
+
loop do
|
174
|
+
c = stream.read(1)[0]
|
175
|
+
size += (c & 127) << shift
|
176
|
+
shift += 7
|
177
|
+
break if (c & 128) == 0
|
178
|
+
end
|
179
|
+
size
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class GitDB::Protocol
|
2
|
+
|
3
|
+
attr_reader :reader
|
4
|
+
attr_reader :writer
|
5
|
+
|
6
|
+
def initialize(io=nil)
|
7
|
+
if io
|
8
|
+
@reader = io
|
9
|
+
@writer = io
|
10
|
+
else
|
11
|
+
@reader = STDIN
|
12
|
+
@writer = STDOUT
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
## commands ##################################################################
|
17
|
+
|
18
|
+
def flush
|
19
|
+
writer.flush
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_command
|
23
|
+
length = reader.read(4)
|
24
|
+
return nil unless length
|
25
|
+
length = length.to_i(16) - 4
|
26
|
+
if (length == -4)
|
27
|
+
GitDB.log('GOT EOF')
|
28
|
+
return
|
29
|
+
end
|
30
|
+
data = reader.read(length)
|
31
|
+
GitDB.log("GOT DATA: #{data.inspect}")
|
32
|
+
data
|
33
|
+
end
|
34
|
+
|
35
|
+
def write_command(command)
|
36
|
+
raw_command = encode_command(command)
|
37
|
+
GitDB.log("WWRITING COMMAND: #{raw_command.inspect}")
|
38
|
+
writer.print raw_command
|
39
|
+
writer.flush
|
40
|
+
end
|
41
|
+
|
42
|
+
def write(data)
|
43
|
+
writer.write data
|
44
|
+
writer.flush
|
45
|
+
end
|
46
|
+
|
47
|
+
def write_eof
|
48
|
+
#GitDB.log("WRITING EOF")
|
49
|
+
writer.print '0000'
|
50
|
+
writer.flush
|
51
|
+
end
|
52
|
+
|
53
|
+
## packs #####################################################################
|
54
|
+
|
55
|
+
def read_pack
|
56
|
+
GitDB::Pack.new(reader).read
|
57
|
+
end
|
58
|
+
|
59
|
+
def write_pack(entries)
|
60
|
+
GitDB::Pack.new(writer).write(entries)
|
61
|
+
end
|
62
|
+
|
63
|
+
private ######################################################################
|
64
|
+
|
65
|
+
def encode_command(command)
|
66
|
+
length_as_hex(command) << command
|
67
|
+
end
|
68
|
+
|
69
|
+
def length_as_hex(command)
|
70
|
+
hex = (command.length + 4).to_s(16).rjust(4, '0')
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class GitDB::Utility::CountingIO
|
2
|
+
|
3
|
+
attr_reader :io, :offset
|
4
|
+
|
5
|
+
def initialize(io)
|
6
|
+
@io = io
|
7
|
+
@offset = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def flush
|
11
|
+
io.flush
|
12
|
+
end
|
13
|
+
|
14
|
+
def read(n)
|
15
|
+
data = io.read(n)
|
16
|
+
@offset += n
|
17
|
+
data
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(data)
|
21
|
+
io.write(data)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/git-db.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'couchrest'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module GitDB;
|
6
|
+
|
7
|
+
## git constants #############################################################
|
8
|
+
|
9
|
+
OBJ_NONE = 0
|
10
|
+
OBJ_COMMIT = 1
|
11
|
+
OBJ_TREE = 2
|
12
|
+
OBJ_BLOB = 3
|
13
|
+
OBJ_TAG = 4
|
14
|
+
OBJ_OFS_DELTA = 6
|
15
|
+
OBJ_REF_DELTA = 7
|
16
|
+
|
17
|
+
## git utility ###############################################################
|
18
|
+
|
19
|
+
def self.sha1_to_hex(sha)
|
20
|
+
hex = ""
|
21
|
+
sha.split('').each do |char|
|
22
|
+
val = char[0]
|
23
|
+
hex << (val >> 4).to_s(16)
|
24
|
+
hex << (val & 0xf).to_s(16)
|
25
|
+
end
|
26
|
+
hex
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.hex_to_sha1(hex)
|
30
|
+
sha = ""
|
31
|
+
len = 0
|
32
|
+
until (len == hex.length)
|
33
|
+
val = (hex[len, 1].to_i(16) << 4)
|
34
|
+
val += hex[len+1, 1].to_i(16)
|
35
|
+
sha << val.chr
|
36
|
+
len += 2
|
37
|
+
end
|
38
|
+
sha
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.null_sha1
|
42
|
+
"0000000000000000000000000000000000000000"
|
43
|
+
end
|
44
|
+
|
45
|
+
## logging ###################################################################
|
46
|
+
|
47
|
+
def self.logger
|
48
|
+
@logger ||= STDERR
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.log(message)
|
52
|
+
logger.puts message
|
53
|
+
end
|
54
|
+
|
55
|
+
## database ##################################################################
|
56
|
+
|
57
|
+
def self.database(repository)
|
58
|
+
GitDB::Database.database(repository)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
require 'git-db/commands'
|
64
|
+
require 'git-db/database'
|
65
|
+
require 'git-db/objects'
|
66
|
+
require 'git-db/pack'
|
67
|
+
require 'git-db/protocol'
|
68
|
+
require 'git-db/utility'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "GitDB::Commands" do
|
4
|
+
|
5
|
+
it "has a receive-pack command" do
|
6
|
+
GitDB::Commands.commands['receive-pack'].should_not be_nil
|
7
|
+
end
|
8
|
+
|
9
|
+
it "has an upload-pack command" do
|
10
|
+
end
|
11
|
+
|
12
|
+
it "executes a command" do
|
13
|
+
@command = mock
|
14
|
+
@name = 'command'
|
15
|
+
@args = ['Test Repository']
|
16
|
+
|
17
|
+
GitDB::Commands.should_receive(:commands).at_least(:once).and_return({ @name => @command })
|
18
|
+
@command.should_receive(:execute).with(@args)
|
19
|
+
|
20
|
+
GitDB::Commands.execute(@name, @args)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe "GitDB::Objects::Base" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@data = "Test Data"
|
7
|
+
@base = GitDB::Objects::Base.new(@data)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "initializes with data" do
|
11
|
+
@base.data.should == @data
|
12
|
+
end
|
13
|
+
|
14
|
+
it "inspects its own properties" do
|
15
|
+
@base.should_receive(:properties).and_return([:data])
|
16
|
+
@base.inspect
|
17
|
+
end
|
18
|
+
|
19
|
+
it "has default properties" do
|
20
|
+
@base.properties.should == [:data]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "has default raw" do
|
24
|
+
@base.raw.should == @data
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe "GitDB::Objects::Entry" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@sha = "1111111111111111111111111111111111111111"
|
7
|
+
@perms = 100644
|
8
|
+
@name = "test name"
|
9
|
+
@entry = GitDB::Objects::Entry.new(@sha, @perms, @name)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "has properties" do
|
13
|
+
@entry.properties.should == [:permissions, :name]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "converts to a hash" do
|
17
|
+
@entry.to_hash[:sha].should == @sha
|
18
|
+
@entry.to_hash[:permissions].should == @perms
|
19
|
+
@entry.to_hash[:name].should == @name
|
20
|
+
end
|
21
|
+
|
22
|
+
it "converts to json" do
|
23
|
+
@entry.to_json.should == @entry.to_hash.to_json
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe "GitDB::Objects::Tag" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
# TODO: real tag data
|
7
|
+
@data = "test-tag"
|
8
|
+
@tag = GitDB::Objects::Tag.new(@data)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "has a type" do
|
12
|
+
@tag.type.should == GitDB::OBJ_TAG
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe "GitDB::Objects::Tree" do
|
4
|
+
|
5
|
+
class TreeEntry
|
6
|
+
attr_reader :perms, :name, :sha
|
7
|
+
|
8
|
+
def initialize(perms, name, sha)
|
9
|
+
@perms = perms
|
10
|
+
@name = name
|
11
|
+
@sha = sha
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_entry
|
15
|
+
"#{perms} #{name}\000#{GitDB.hex_to_sha1(sha)}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
@entry1 = TreeEntry.new(100644, "entry1", "1111111111111111111111111111111111111111")
|
21
|
+
@entry2 = TreeEntry.new(100444, "entry2", "2222222222222222222222222222222222222222")
|
22
|
+
@data = [ @entry1.to_entry, @entry2.to_entry ].join('')
|
23
|
+
@tree = GitDB::Objects::Tree.new(@data)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "has entries" do
|
27
|
+
@tree.entries.first.name.should == @entry1.name
|
28
|
+
@tree.entries.last.name.should == @entry2.name
|
29
|
+
end
|
30
|
+
|
31
|
+
it "has properties" do
|
32
|
+
@tree.properties.should == [:entries]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "has a raw value" do
|
36
|
+
@tree.raw.should == "tree #{@data.length}\000#{@data}"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "has a type" do
|
40
|
+
@tree.type.should == GitDB::OBJ_TREE
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe "GitDB::Utility::CountingIO" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@base = StringIO.new
|
7
|
+
@io = GitDB::Utility::CountingIO.new(@base)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "can flush" do
|
11
|
+
@base.should_receive(:flush)
|
12
|
+
@io.flush
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can read" do
|
16
|
+
@data = "00000"
|
17
|
+
@bytes = @data.length
|
18
|
+
|
19
|
+
@base.should_receive(:read).with(@bytes).and_return(@data)
|
20
|
+
@io.read(@bytes).should == @data
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can write" do
|
24
|
+
@data = "00000"
|
25
|
+
|
26
|
+
@base.should_receive(:write).with(@data)
|
27
|
+
@io.write(@data)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|