git-db 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|