Skip to content

Commit ad86038

Browse files
committed
Added fast-import streaming functionality (stream.rb). Just basic support at this point. Updated the author class to support direct creation in addition to parsing.
1 parent 2e937ac commit ad86038

File tree

4 files changed

+268
-0
lines changed

4 files changed

+268
-0
lines changed

lib/git.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
require 'git/stashes'
2727
require 'git/stash'
2828

29+
require 'git/stream'
30+
2931

3032
# Git/Ruby Library
3133
#

lib/git/author.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,10 @@ def initialize(author_string)
1010
end
1111
end
1212

13+
def initialize(name, email, date = Time.now)
14+
@name = name
15+
@email = email
16+
@date = date
17+
end
1318
end
1419
end

lib/git/stream.rb

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
module Git
2+
3+
require 'time'
4+
5+
#====================
6+
# Stream Classes
7+
#
8+
# These classes must support the following methods
9+
#
10+
# to_s - write the command to the git protocol stream
11+
#====================
12+
13+
class StreamCommit
14+
15+
16+
attr_accessor :branch, :mark, :author, :committer, :message, :ancestor, :changes
17+
18+
def initialize()
19+
@branch = nil
20+
@mark = StreamMark.new
21+
@author = nil
22+
@committer = nil
23+
@message = nil
24+
@ancestor = nil
25+
@changes = []
26+
end
27+
28+
def to_s
29+
out = "commit refs/heads/#{branch.to_s}\n"
30+
out << "mark #{mark}\n"
31+
out << "author #{author.name} <#{author.email}> #{author.date.rfc2822}\n" unless author == nil
32+
out << "committer #{committer.name} <#{committer.email}> #{committer.date.rfc2822}\n" unless committer == nil
33+
if (message == nil)
34+
out << StreamData.emit_empty_data
35+
else
36+
out << StreamData.emit_inline_data(message)
37+
end
38+
out << "from #{ancestor}\n" unless ancestor == nil
39+
changes.each do |c|
40+
out << c.to_s
41+
end
42+
out << "\n"
43+
end
44+
end
45+
46+
class StreamMark
47+
48+
@@mark_counter = 1
49+
50+
def initialize(id = (@@mark_counter += 1))
51+
@id = id
52+
end
53+
54+
def to_s
55+
":#{@id}"
56+
end
57+
end
58+
59+
# This class is used in the filemodify change on the commit stream
60+
# At this time only the inline mode data stream is supported
61+
class StreamFileModify
62+
63+
attr_accessor :mode, :repository_path, :inline_data
64+
65+
def initialize(repository_path, data)
66+
@mode = 100644
67+
@repository_path = repository_path
68+
@inline_data = data
69+
end
70+
71+
def to_s
72+
"M #{mode} inline #{repository_path}\n#{StreamData.emit_inline_data(inline_data)}"
73+
end
74+
end
75+
76+
class StreamFileDelete
77+
78+
attr_accessor :repository_path
79+
80+
def initialize(repository_path)
81+
@repository_path = repository_path
82+
end
83+
84+
def to_s
85+
"D #{repository_path}\n"
86+
end
87+
end
88+
89+
class StreamFileCopy
90+
91+
attr_accessor :repository_path_from, :repository_path_to
92+
93+
def initialize(repository_path_from, repository_path_to)
94+
@repository_path_from = repository_path_from
95+
@repository_path_to = repository_path_to
96+
end
97+
98+
def to_s
99+
"C #{repository_path_from} #{repository_path_to}\n"
100+
end
101+
102+
end
103+
104+
class StreamFileRename
105+
106+
attr_accessor :repository_path_from, :repository_path_to
107+
108+
def initialize(repository_path_from,repository_path_to)
109+
@repository_path_from = repository_path_from
110+
@repository_path_to = repository_path_to
111+
end
112+
113+
def to_s
114+
"R #{repository_path_from} #{repository_path_to}\n"
115+
end
116+
117+
end
118+
119+
class StreamFileDeleteAll
120+
121+
def to_s
122+
"deleteall\n"
123+
end
124+
end
125+
126+
# Represents a stream of data bytes in the git stream
127+
class StreamData
128+
129+
def self.emit_inline_data(data_string)
130+
"data #{data_string.length}\n#{data_string}\n"
131+
end
132+
133+
def self.emit_empty_data
134+
"data 0\n\n"
135+
end
136+
end
137+
138+
#====================
139+
# Stream Implementation
140+
#====================
141+
142+
# This is an initial implementation of git fast-import/export streams
143+
# It is not complete!
144+
class Stream
145+
146+
147+
end
148+
149+
end

tests/units/test_stream.rb

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env ruby
2+
3+
require File.dirname(__FILE__) + '/../test_helper'
4+
5+
class TestStream < Test::Unit::TestCase
6+
def setup
7+
set_file_paths
8+
end
9+
10+
def test_minimal_commit_stream
11+
t = Time.now
12+
13+
commit = Git::StreamCommit.new
14+
commit.branch = "master"
15+
commit.committer = Git::Author.new("Arthur Developer","arthur@example.com",t)
16+
17+
str = "commit refs/heads/master\n"
18+
str << "mark #{commit.mark}\n"
19+
str << "committer Arthur Developer <arthur@example.com> #{t.rfc2822}\n"
20+
str << "data 0\n"
21+
str << "\n\n"
22+
23+
assert_equal str, commit.to_s
24+
end
25+
26+
def test_single_file_add
27+
t = Time.now
28+
29+
commit = Git::StreamCommit.new
30+
commit.branch = "master"
31+
commit.author = Git::Author.new("Arthur Developer","arthur@example.com",t)
32+
commit.committer = Git::Author.new("Jane Developer","jane@example.com",t+10)
33+
commit.message = "Adding a single file."
34+
commit.ancestor = "2e937ac5d5a6e95f4abb9f636273eaa6528f5dae"
35+
commit.changes << Git::StreamFileModify.new("p/e/added-file.txt","This is the contents of the\nadded file.")
36+
37+
str = "commit refs/heads/master\n"
38+
str << "mark #{commit.mark}\n"
39+
str << "author Arthur Developer <arthur@example.com> #{t.rfc2822}\n"
40+
str << "committer Jane Developer <jane@example.com> #{(t+10).rfc2822}\n"
41+
str << "data 21\n"
42+
str << "Adding a single file.\n"
43+
str << "from 2e937ac5d5a6e95f4abb9f636273eaa6528f5dae\n"
44+
str << "M 100644 inline p/e/added-file.txt\n"
45+
str << "data 39\n"
46+
str << "This is the contents of the\nadded file.\n"
47+
str << "\n"
48+
49+
assert_equal str, commit.to_s
50+
end
51+
52+
def test_single_file_add
53+
t = Time.now
54+
55+
commit = Git::StreamCommit.new
56+
commit.branch = "master"
57+
commit.author = Git::Author.new("Arthur Developer","arthur@example.com",t)
58+
commit.committer = Git::Author.new("Jane Developer","jane@example.com",t+10)
59+
commit.message = "Adding a single file."
60+
commit.ancestor = "2e937ac5d5a6e95f4abb9f636273eaa6528f5dae"
61+
commit.changes << Git::StreamFileModify.new("p/e/added-file.txt","This is the contents of the\nadded file.")
62+
63+
str = "commit refs/heads/master\n"
64+
str << "mark #{commit.mark}\n"
65+
str << "author Arthur Developer <arthur@example.com> #{t.rfc2822}\n"
66+
str << "committer Jane Developer <jane@example.com> #{(t+10).rfc2822}\n"
67+
str << "data 21\n"
68+
str << "Adding a single file.\n"
69+
str << "from 2e937ac5d5a6e95f4abb9f636273eaa6528f5dae\n"
70+
str << "M 100644 inline p/e/added-file.txt\n"
71+
str << "data 39\n"
72+
str << "This is the contents of the\nadded file.\n"
73+
str << "\n"
74+
75+
assert_equal str, commit.to_s
76+
end
77+
78+
def test_multiple_changes
79+
t = Time.now
80+
81+
commit = Git::StreamCommit.new
82+
commit.branch = "master"
83+
commit.author = Git::Author.new("Arthur Developer","arthur@example.com",t)
84+
commit.committer = Git::Author.new("Jane Developer","jane@example.com",t+10)
85+
commit.message = "Add/Delete/Rename/Copy/DeleteAll."
86+
commit.ancestor = "2e937ac5d5a6e95f4abb9f636273eaa6528f5dae"
87+
commit.changes << Git::StreamFileModify.new("p/e/added-file.txt","This is the contents of the\nadded file.")
88+
commit.changes << Git::StreamFileDelete.new("del-file.txt")
89+
commit.changes << Git::StreamFileRename.new("file1.txt","file2.txt")
90+
commit.changes << Git::StreamFileCopy.new("file2.txt","file3.txt")
91+
commit.changes << Git::StreamFileDeleteAll.new
92+
93+
str = "commit refs/heads/master\n"
94+
str << "mark #{commit.mark}\n"
95+
str << "author Arthur Developer <arthur@example.com> #{t.rfc2822}\n"
96+
str << "committer Jane Developer <jane@example.com> #{(t+10).rfc2822}\n"
97+
str << "data 33\n"
98+
str << "Add/Delete/Rename/Copy/DeleteAll.\n"
99+
str << "from 2e937ac5d5a6e95f4abb9f636273eaa6528f5dae\n"
100+
str << "M 100644 inline p/e/added-file.txt\n"
101+
str << "data 39\n"
102+
str << "This is the contents of the\nadded file.\n"
103+
str << "D del-file.txt\n"
104+
str << "R file1.txt file2.txt\n"
105+
str << "C file2.txt file3.txt\n"
106+
str << "deleteall\n"
107+
str << "\n"
108+
109+
assert_equal str, commit.to_s
110+
end
111+
112+
end

0 commit comments

Comments
 (0)