cucumber_fm-core 0.1
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/LICENCE +20 -0
- data/lib/cucumber_f_m/aggregator.rb +65 -0
- data/lib/cucumber_f_m/comment_module/comment.rb +7 -0
- data/lib/cucumber_f_m/config.rb +37 -0
- data/lib/cucumber_f_m/cvs/git.rb +7 -0
- data/lib/cucumber_f_m/feature.rb +141 -0
- data/lib/cucumber_f_m/feature_element/background.rb +10 -0
- data/lib/cucumber_f_m/feature_element/comment.rb +13 -0
- data/lib/cucumber_f_m/feature_element/component/comments.rb +21 -0
- data/lib/cucumber_f_m/feature_element/component/information/component.rb +16 -0
- data/lib/cucumber_f_m/feature_element/component/tags.rb +108 -0
- data/lib/cucumber_f_m/feature_element/component/title.rb +26 -0
- data/lib/cucumber_f_m/feature_element/component/total_estimation.rb +42 -0
- data/lib/cucumber_f_m/feature_element/example.rb +7 -0
- data/lib/cucumber_f_m/feature_element/info.rb +13 -0
- data/lib/cucumber_f_m/feature_element/narrative.rb +7 -0
- data/lib/cucumber_f_m/feature_element/scenario.rb +15 -0
- data/lib/cucumber_f_m/feature_element/scenario_outline.rb +23 -0
- data/lib/cucumber_f_m/feature_element/step.rb +7 -0
- data/lib/cucumber_f_m/statistic.rb +31 -0
- data/lib/cucumber_f_m/tag_filter.rb +85 -0
- data/lib/cucumber_feature_manager.rb +164 -0
- data/lib/grit/lib/grit.rb +75 -0
- data/lib/grit/lib/grit/actor.rb +36 -0
- data/lib/grit/lib/grit/blame.rb +61 -0
- data/lib/grit/lib/grit/blob.rb +126 -0
- data/lib/grit/lib/grit/commit.rb +247 -0
- data/lib/grit/lib/grit/commit_stats.rb +128 -0
- data/lib/grit/lib/grit/config.rb +44 -0
- data/lib/grit/lib/grit/diff.rb +70 -0
- data/lib/grit/lib/grit/errors.rb +7 -0
- data/lib/grit/lib/grit/git-ruby.rb +267 -0
- data/lib/grit/lib/grit/git-ruby/commit_db.rb +52 -0
- data/lib/grit/lib/grit/git-ruby/file_index.rb +193 -0
- data/lib/grit/lib/grit/git-ruby/git_object.rb +350 -0
- data/lib/grit/lib/grit/git-ruby/internal/file_window.rb +58 -0
- data/lib/grit/lib/grit/git-ruby/internal/loose.rb +137 -0
- data/lib/grit/lib/grit/git-ruby/internal/pack.rb +384 -0
- data/lib/grit/lib/grit/git-ruby/internal/raw_object.rb +37 -0
- data/lib/grit/lib/grit/git-ruby/object.rb +325 -0
- data/lib/grit/lib/grit/git-ruby/repository.rb +767 -0
- data/lib/grit/lib/grit/git.rb +323 -0
- data/lib/grit/lib/grit/index.rb +122 -0
- data/lib/grit/lib/grit/lazy.rb +33 -0
- data/lib/grit/lib/grit/merge.rb +45 -0
- data/lib/grit/lib/grit/ref.rb +74 -0
- data/lib/grit/lib/grit/repo.rb +482 -0
- data/lib/grit/lib/grit/ruby1.9.rb +7 -0
- data/lib/grit/lib/grit/status.rb +151 -0
- data/lib/grit/lib/grit/submodule.rb +88 -0
- data/lib/grit/lib/grit/tag.rb +16 -0
- data/lib/grit/lib/grit/tree.rb +123 -0
- data/lib/grit/lib/open3_detach.rb +46 -0
- data/spec/cucumber_f_m/aggregator_spec.rb +210 -0
- data/spec/cucumber_f_m/comment_module/comment_spec.rb +4 -0
- data/spec/cucumber_f_m/config_spec.rb +27 -0
- data/spec/cucumber_f_m/cvs/git_spec.rb +40 -0
- data/spec/cucumber_f_m/feature_all_tags_to_scenario_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_file_manipulation_spec.rb +29 -0
- data/spec/cucumber_f_m/feature_module/background_spec.rb +30 -0
- data/spec/cucumber_f_m/feature_module/comment_spec.rb +23 -0
- data/spec/cucumber_f_m/feature_module/example_spec.rb +5 -0
- data/spec/cucumber_f_m/feature_module/info_spec.rb +30 -0
- data/spec/cucumber_f_m/feature_module/narrative_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_module/scenario_outline_spec.rb +39 -0
- data/spec/cucumber_f_m/feature_module/scenario_spec.rb +33 -0
- data/spec/cucumber_f_m/feature_module/step_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_module/tag_spec.rb +96 -0
- data/spec/cucumber_f_m/feature_spec.rb +229 -0
- data/spec/cucumber_f_m/tag_filter_spec.rb +191 -0
- data/spec/cucumber_feature_manager_spec.rb +59 -0
- data/spec/data/feature_manager/some_ruby_file.rb +0 -0
- data/spec/spec_helper.rb +1 -0
- metadata +141 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# converted from the gitrb project
|
3
|
+
#
|
4
|
+
# authors:
|
5
|
+
# Matthias Lederhofer <matled@gmx.net>
|
6
|
+
# Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
|
7
|
+
#
|
8
|
+
# provides native ruby access to git objects and pack files
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'digest/sha1'
|
12
|
+
|
13
|
+
module Grit
|
14
|
+
module GitRuby
|
15
|
+
module Internal
|
16
|
+
OBJ_NONE = 0
|
17
|
+
OBJ_COMMIT = 1
|
18
|
+
OBJ_TREE = 2
|
19
|
+
OBJ_BLOB = 3
|
20
|
+
OBJ_TAG = 4
|
21
|
+
|
22
|
+
OBJ_TYPES = [nil, :commit, :tree, :blob, :tag].freeze
|
23
|
+
|
24
|
+
class RawObject
|
25
|
+
attr_accessor :type, :content
|
26
|
+
def initialize(type, content)
|
27
|
+
@type = type
|
28
|
+
@content = content
|
29
|
+
end
|
30
|
+
|
31
|
+
def sha1
|
32
|
+
Digest::SHA1.digest("%s %d\0" % [@type, @content.length] + @content)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,325 @@
|
|
1
|
+
#
|
2
|
+
# converted from the gitrb project
|
3
|
+
#
|
4
|
+
# authors:
|
5
|
+
# Matthias Lederhofer <matled@gmx.net>
|
6
|
+
# Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
|
7
|
+
# Scott Chacon <schacon@gmail.com>
|
8
|
+
#
|
9
|
+
# provides native ruby access to git objects and pack files
|
10
|
+
#
|
11
|
+
|
12
|
+
# These classes translate the raw binary data kept in the sha encoded files
|
13
|
+
# into parsed data that can then be used in another fashion
|
14
|
+
require 'stringio'
|
15
|
+
|
16
|
+
module Grit
|
17
|
+
module GitRuby
|
18
|
+
|
19
|
+
# class for author/committer/tagger lines
|
20
|
+
class UserInfo
|
21
|
+
attr_accessor :name, :email, :date, :offset
|
22
|
+
|
23
|
+
def initialize(str)
|
24
|
+
m = /^(.*?) <(.*)> (\d+) ([+-])0*(\d+?)$/.match(str)
|
25
|
+
if !m
|
26
|
+
raise RuntimeError, "invalid header '%s' in commit" % str
|
27
|
+
end
|
28
|
+
@name = m[1]
|
29
|
+
@email = m[2]
|
30
|
+
@date = Time.at(Integer(m[3]))
|
31
|
+
@offset = (m[4] == "-" ? -1 : 1)*Integer(m[5])
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"%s <%s> %s %+05d" % [@name, @email, @date.to_i, @offset]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# base class for all git objects (blob, tree, commit, tag)
|
40
|
+
class Object
|
41
|
+
attr_accessor :repository
|
42
|
+
|
43
|
+
def Object.from_raw(rawobject, repository = nil)
|
44
|
+
case rawobject.type
|
45
|
+
when :blob
|
46
|
+
return Blob.from_raw(rawobject, repository)
|
47
|
+
when :tree
|
48
|
+
return Tree.from_raw(rawobject, repository)
|
49
|
+
when :commit
|
50
|
+
return Commit.from_raw(rawobject, repository)
|
51
|
+
when :tag
|
52
|
+
return Tag.from_raw(rawobject, repository)
|
53
|
+
else
|
54
|
+
raise RuntimeError, "got invalid object-type"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize
|
59
|
+
raise NotImplemented, "abstract class"
|
60
|
+
end
|
61
|
+
|
62
|
+
def type
|
63
|
+
raise NotImplemented, "abstract class"
|
64
|
+
end
|
65
|
+
|
66
|
+
def raw_content
|
67
|
+
raise NotImplemented, "abstract class"
|
68
|
+
end
|
69
|
+
|
70
|
+
def sha1
|
71
|
+
Digest::SHA1.hexdigest("%s %d\0" % \
|
72
|
+
[self.type, self.raw_content.length] + \
|
73
|
+
self.raw_content)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Blob < Object
|
78
|
+
attr_accessor :content
|
79
|
+
|
80
|
+
def self.from_raw(rawobject, repository)
|
81
|
+
new(rawobject.content)
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize(content, repository=nil)
|
85
|
+
@content = content
|
86
|
+
@repository = repository
|
87
|
+
end
|
88
|
+
|
89
|
+
def type
|
90
|
+
:blob
|
91
|
+
end
|
92
|
+
|
93
|
+
def raw_content
|
94
|
+
@content
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class DirectoryEntry
|
99
|
+
S_IFMT = 00170000
|
100
|
+
S_IFLNK = 0120000
|
101
|
+
S_IFREG = 0100000
|
102
|
+
S_IFDIR = 0040000
|
103
|
+
|
104
|
+
attr_accessor :mode, :name, :sha1
|
105
|
+
def initialize(mode, filename, sha1o)
|
106
|
+
@mode = 0
|
107
|
+
mode.each_byte do |i|
|
108
|
+
@mode = (@mode << 3) | (i-'0'[0])
|
109
|
+
end
|
110
|
+
@name = filename
|
111
|
+
@sha1 = sha1o
|
112
|
+
if ![S_IFLNK, S_IFDIR, S_IFREG].include?(@mode & S_IFMT)
|
113
|
+
raise RuntimeError, "unknown type for directory entry"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def type
|
118
|
+
case @mode & S_IFMT
|
119
|
+
when S_IFLNK
|
120
|
+
@type = :link
|
121
|
+
when S_IFDIR
|
122
|
+
@type = :directory
|
123
|
+
when S_IFREG
|
124
|
+
@type = :file
|
125
|
+
else
|
126
|
+
raise RuntimeError, "unknown type for directory entry"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def type=(type)
|
131
|
+
case @type
|
132
|
+
when :link
|
133
|
+
@mode = (@mode & ~S_IFMT) | S_IFLNK
|
134
|
+
when :directory
|
135
|
+
@mode = (@mode & ~S_IFMT) | S_IFDIR
|
136
|
+
when :file
|
137
|
+
@mode = (@mode & ~S_IFMT) | S_IFREG
|
138
|
+
else
|
139
|
+
raise RuntimeError, "invalid type"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def format_type
|
144
|
+
case type
|
145
|
+
when :link
|
146
|
+
'link'
|
147
|
+
when :directory
|
148
|
+
'tree'
|
149
|
+
when :file
|
150
|
+
'blob'
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def format_mode
|
155
|
+
"%06o" % @mode
|
156
|
+
end
|
157
|
+
|
158
|
+
def raw
|
159
|
+
"%o %s\0%s" % [@mode, @name, [@sha1].pack("H*")]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
def self.read_bytes_until(io, char)
|
165
|
+
string = ''
|
166
|
+
if RUBY_VERSION > '1.9'
|
167
|
+
while ((next_char = io.getc) != char) && !io.eof
|
168
|
+
string += next_char
|
169
|
+
end
|
170
|
+
else
|
171
|
+
while ((next_char = io.getc.chr) != char) && !io.eof
|
172
|
+
string += next_char
|
173
|
+
end
|
174
|
+
end
|
175
|
+
string
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
class Tree < Object
|
180
|
+
attr_accessor :entry
|
181
|
+
|
182
|
+
def self.from_raw(rawobject, repository=nil)
|
183
|
+
raw = StringIO.new(rawobject.content)
|
184
|
+
|
185
|
+
entries = []
|
186
|
+
while !raw.eof?
|
187
|
+
mode = Grit::GitRuby.read_bytes_until(raw, ' ')
|
188
|
+
file_name = Grit::GitRuby.read_bytes_until(raw, "\0")
|
189
|
+
raw_sha = raw.read(20)
|
190
|
+
sha = raw_sha.unpack("H*").first
|
191
|
+
|
192
|
+
entries << DirectoryEntry.new(mode, file_name, sha)
|
193
|
+
end
|
194
|
+
new(entries, repository)
|
195
|
+
end
|
196
|
+
|
197
|
+
def initialize(entries=[], repository = nil)
|
198
|
+
@entry = entries
|
199
|
+
@repository = repository
|
200
|
+
end
|
201
|
+
|
202
|
+
def type
|
203
|
+
:tree
|
204
|
+
end
|
205
|
+
|
206
|
+
def raw_content
|
207
|
+
# TODO: sort correctly
|
208
|
+
#@entry.sort { |a,b| a.name <=> b.name }.
|
209
|
+
@entry.collect { |e| [[e.format_mode, e.format_type, e.sha1].join(' '), e.name].join("\t") }.join("\n")
|
210
|
+
end
|
211
|
+
|
212
|
+
def actual_raw
|
213
|
+
#@entry.collect { |e| e.raw.join(' '), e.name].join("\t") }.join("\n")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
class Commit < Object
|
218
|
+
attr_accessor :author, :committer, :tree, :parent, :message, :headers
|
219
|
+
|
220
|
+
def self.from_raw(rawobject, repository=nil)
|
221
|
+
parent = []
|
222
|
+
tree = author = committer = nil
|
223
|
+
|
224
|
+
headers, message = rawobject.content.split(/\n\n/, 2)
|
225
|
+
all_headers = headers.split(/\n/).map { |header| header.split(/ /, 2) }
|
226
|
+
all_headers.each do |key, value|
|
227
|
+
case key
|
228
|
+
when "tree"
|
229
|
+
tree = value
|
230
|
+
when "parent"
|
231
|
+
parent.push(value)
|
232
|
+
when "author"
|
233
|
+
author = UserInfo.new(value)
|
234
|
+
when "committer"
|
235
|
+
committer = UserInfo.new(value)
|
236
|
+
else
|
237
|
+
warn "unknown header '%s' in commit %s" % \
|
238
|
+
[key, rawobject.sha1.unpack("H*")[0]]
|
239
|
+
end
|
240
|
+
end
|
241
|
+
if not tree && author && committer
|
242
|
+
raise RuntimeError, "incomplete raw commit object"
|
243
|
+
end
|
244
|
+
new(tree, parent, author, committer, message, headers, repository)
|
245
|
+
end
|
246
|
+
|
247
|
+
def initialize(tree, parent, author, committer, message, headers, repository=nil)
|
248
|
+
@tree = tree
|
249
|
+
@author = author
|
250
|
+
@parent = parent
|
251
|
+
@committer = committer
|
252
|
+
@message = message
|
253
|
+
@headers = headers
|
254
|
+
@repository = repository
|
255
|
+
end
|
256
|
+
|
257
|
+
def type
|
258
|
+
:commit
|
259
|
+
end
|
260
|
+
|
261
|
+
def raw_content
|
262
|
+
"tree %s\n%sauthor %s\ncommitter %s\n\n" % [
|
263
|
+
@tree,
|
264
|
+
@parent.collect { |i| "parent %s\n" % i }.join,
|
265
|
+
@author, @committer] + @message
|
266
|
+
end
|
267
|
+
|
268
|
+
def raw_log(sha)
|
269
|
+
output = "commit #{sha}\n"
|
270
|
+
output += @headers + "\n\n"
|
271
|
+
output += @message.split("\n").map { |l| ' ' + l }.join("\n") + "\n\n"
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
class Tag < Object
|
277
|
+
attr_accessor :object, :type, :tag, :tagger, :message
|
278
|
+
|
279
|
+
def self.from_raw(rawobject, repository=nil)
|
280
|
+
headers, message = rawobject.content.split(/\n\n/, 2)
|
281
|
+
headers = headers.split(/\n/).map { |header| header.split(/ /, 2) }
|
282
|
+
headers.each do |key, value|
|
283
|
+
case key
|
284
|
+
when "object"
|
285
|
+
object = value
|
286
|
+
when "type"
|
287
|
+
if !["blob", "tree", "commit", "tag"].include?(value)
|
288
|
+
raise RuntimeError, "invalid type in tag"
|
289
|
+
end
|
290
|
+
type = value.to_sym
|
291
|
+
when "tag"
|
292
|
+
tag = value
|
293
|
+
when "tagger"
|
294
|
+
tagger = UserInfo.new(value)
|
295
|
+
else
|
296
|
+
warn "unknown header '%s' in tag" % \
|
297
|
+
[key, rawobject.sha1.unpack("H*")[0]]
|
298
|
+
end
|
299
|
+
if not object && type && tag && tagger
|
300
|
+
raise RuntimeError, "incomplete raw tag object"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
new(object, type, tag, tagger, repository)
|
304
|
+
end
|
305
|
+
|
306
|
+
def initialize(object, type, tag, tagger, repository=nil)
|
307
|
+
@object = object
|
308
|
+
@type = type
|
309
|
+
@tag = tag
|
310
|
+
@tagger = tagger
|
311
|
+
@repository = repository
|
312
|
+
end
|
313
|
+
|
314
|
+
def raw_content
|
315
|
+
"object %s\ntype %s\ntag %s\ntagger %s\n\n" % \
|
316
|
+
[@object, @type, @tag, @tagger] + @message
|
317
|
+
end
|
318
|
+
|
319
|
+
def type
|
320
|
+
:tag
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|
325
|
+
end
|
@@ -0,0 +1,767 @@
|
|
1
|
+
#
|
2
|
+
# converted from the gitrb project
|
3
|
+
#
|
4
|
+
# authors:
|
5
|
+
# Matthias Lederhofer <matled@gmx.net>
|
6
|
+
# Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
|
7
|
+
# Scott Chacon <schacon@gmail.com>
|
8
|
+
#
|
9
|
+
# provides native ruby access to git objects and pack files
|
10
|
+
#
|
11
|
+
require 'grit/git-ruby/internal/raw_object'
|
12
|
+
require 'grit/git-ruby/internal/pack'
|
13
|
+
require 'grit/git-ruby/internal/loose'
|
14
|
+
require 'grit/git-ruby/git_object'
|
15
|
+
|
16
|
+
require 'rubygems'
|
17
|
+
require 'diff/lcs'
|
18
|
+
require 'diff/lcs/hunk'
|
19
|
+
|
20
|
+
# have to do this so it doesn't interfere with Grit::Diff
|
21
|
+
module Difference
|
22
|
+
include Diff
|
23
|
+
end
|
24
|
+
|
25
|
+
module Grit
|
26
|
+
module GitRuby
|
27
|
+
class Repository
|
28
|
+
|
29
|
+
class NoSuchShaFound < StandardError
|
30
|
+
end
|
31
|
+
|
32
|
+
class NoSuchPath < StandardError
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :git_dir, :options
|
36
|
+
|
37
|
+
def initialize(git_dir, options = {})
|
38
|
+
@git_dir = git_dir
|
39
|
+
@options = options
|
40
|
+
@packs = []
|
41
|
+
end
|
42
|
+
|
43
|
+
# returns the loose objects object lazily
|
44
|
+
def loose
|
45
|
+
@loose ||= initloose
|
46
|
+
end
|
47
|
+
|
48
|
+
# returns the array of pack list objects
|
49
|
+
def packs
|
50
|
+
@packs ||= initpacks
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# prints out the type, shas and content of all of the pack files
|
55
|
+
def show
|
56
|
+
packs.each do |p|
|
57
|
+
puts p.name
|
58
|
+
puts
|
59
|
+
p.each_sha1 do |s|
|
60
|
+
puts "**#{p[s].type}**"
|
61
|
+
if p[s].type.to_s == 'commit'
|
62
|
+
puts s.unpack('H*')
|
63
|
+
puts p[s].content
|
64
|
+
end
|
65
|
+
end
|
66
|
+
puts
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# returns a raw object given a SHA1
|
72
|
+
def get_raw_object_by_sha1(sha1o)
|
73
|
+
raise NoSuchShaFound if sha1o.nil? || sha1o.empty? || !sha1o.is_a?(String)
|
74
|
+
|
75
|
+
sha1 = [sha1o.chomp].pack("H*")
|
76
|
+
# try packs
|
77
|
+
packs.each do |pack|
|
78
|
+
o = pack[sha1]
|
79
|
+
return pack[sha1] if o
|
80
|
+
end
|
81
|
+
|
82
|
+
# try loose storage
|
83
|
+
loose.each do |lsobj|
|
84
|
+
o = lsobj[sha1]
|
85
|
+
return o if o
|
86
|
+
end
|
87
|
+
|
88
|
+
# try packs again, maybe the object got packed in the meantime
|
89
|
+
initpacks
|
90
|
+
packs.each do |pack|
|
91
|
+
o = pack[sha1]
|
92
|
+
return o if o
|
93
|
+
end
|
94
|
+
|
95
|
+
# puts "*#{sha1o}*"
|
96
|
+
raise NoSuchShaFound
|
97
|
+
end
|
98
|
+
|
99
|
+
def cached(key, object, do_cache = true)
|
100
|
+
object
|
101
|
+
end
|
102
|
+
|
103
|
+
# returns GitRuby object of any type given a SHA1
|
104
|
+
def get_object_by_sha1(sha1)
|
105
|
+
r = get_raw_object_by_sha1(sha1)
|
106
|
+
return nil if !r
|
107
|
+
GitObject.from_raw(r)
|
108
|
+
end
|
109
|
+
|
110
|
+
# writes a raw object into the git repo
|
111
|
+
def put_raw_object(content, type)
|
112
|
+
loose.first.put_raw_object(content, type)
|
113
|
+
end
|
114
|
+
|
115
|
+
# returns true or false if that sha exists in the db
|
116
|
+
def object_exists?(sha1)
|
117
|
+
sha_hex = [sha1].pack("H*")
|
118
|
+
return true if in_packs?(sha_hex)
|
119
|
+
return true if in_loose?(sha_hex)
|
120
|
+
initpacks
|
121
|
+
return true if in_packs?(sha_hex) #maybe the object got packed in the meantime
|
122
|
+
false
|
123
|
+
end
|
124
|
+
|
125
|
+
# returns true if the hex-packed sha is in the packfiles
|
126
|
+
def in_packs?(sha_hex)
|
127
|
+
# try packs
|
128
|
+
packs.each do |pack|
|
129
|
+
return true if pack[sha_hex]
|
130
|
+
end
|
131
|
+
false
|
132
|
+
end
|
133
|
+
|
134
|
+
# returns true if the hex-packed sha is in the loose objects
|
135
|
+
def in_loose?(sha_hex)
|
136
|
+
loose.each do |lsobj|
|
137
|
+
return true if lsobj[sha_hex]
|
138
|
+
end
|
139
|
+
false
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
# returns the file type (as a symbol) of this sha
|
144
|
+
def cat_file_type(sha)
|
145
|
+
get_raw_object_by_sha1(sha).type
|
146
|
+
end
|
147
|
+
|
148
|
+
# returns the file size (as an int) of this sha
|
149
|
+
def cat_file_size(sha)
|
150
|
+
get_raw_object_by_sha1(sha).content.size
|
151
|
+
end
|
152
|
+
|
153
|
+
# returns the raw file contents of this sha
|
154
|
+
def cat_file(sha)
|
155
|
+
get_object_by_sha1(sha).raw_content
|
156
|
+
end
|
157
|
+
|
158
|
+
# returns a 2-d hash of the tree
|
159
|
+
# ['blob']['FILENAME'] = {:mode => '100644', :sha => SHA}
|
160
|
+
# ['tree']['DIRNAME'] = {:mode => '040000', :sha => SHA}
|
161
|
+
def list_tree(sha)
|
162
|
+
data = {'blob' => {}, 'tree' => {}, 'link' => {}, 'commit' => {}}
|
163
|
+
get_object_by_sha1(sha).entry.each do |e|
|
164
|
+
data[e.format_type][e.name] = {:mode => e.format_mode, :sha => e.sha1}
|
165
|
+
end
|
166
|
+
data
|
167
|
+
end
|
168
|
+
|
169
|
+
# returns the raw (cat-file) output for a tree
|
170
|
+
# if given a commit sha, it will print the tree of that commit
|
171
|
+
# if given a path limiter array, it will limit the output to those
|
172
|
+
# if asked for recrusive trees, will traverse trees
|
173
|
+
def ls_tree(sha, paths = [], recursive = false)
|
174
|
+
if paths.size > 0
|
175
|
+
# pathing
|
176
|
+
part = []
|
177
|
+
paths.each do |path|
|
178
|
+
part += ls_tree_path(sha, path)
|
179
|
+
end
|
180
|
+
return part.join("\n")
|
181
|
+
else
|
182
|
+
get_raw_tree(sha, recursive)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_raw_tree(sha, recursive = false)
|
187
|
+
o = get_raw_object_by_sha1(sha)
|
188
|
+
if o.type == :commit
|
189
|
+
tree = get_object_by_sha1(sha).tree
|
190
|
+
elsif o.type == :tag
|
191
|
+
commit_sha = get_object_by_sha1(sha).object
|
192
|
+
tree = get_object_by_sha1(commit_sha).tree
|
193
|
+
elsif o.type == :tree
|
194
|
+
tree = sha
|
195
|
+
else
|
196
|
+
return nil
|
197
|
+
end
|
198
|
+
|
199
|
+
recursive ? get_raw_trees(tree) : cat_file(tree)
|
200
|
+
end
|
201
|
+
|
202
|
+
# Grabs tree contents recursively,
|
203
|
+
# e.g. `git ls-tree -r sha`
|
204
|
+
def get_raw_trees(sha, path = '')
|
205
|
+
out = ''
|
206
|
+
cat_file(sha).split("\n").each do |line|
|
207
|
+
mode, type, sha, name = line.split(/\s/)
|
208
|
+
|
209
|
+
if type == 'tree'
|
210
|
+
full_name = path.empty? ? name : "#{path}/#{name}"
|
211
|
+
out << get_raw_trees(sha, full_name)
|
212
|
+
elsif path.empty?
|
213
|
+
out << line + "\n"
|
214
|
+
else
|
215
|
+
out << line.gsub(name, "#{path}/#{name}") + "\n"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
out
|
220
|
+
end
|
221
|
+
|
222
|
+
# return array of tree entries
|
223
|
+
## TODO : refactor this to remove the fugly
|
224
|
+
def ls_tree_path(sha, path, append = nil)
|
225
|
+
tree = get_raw_tree(sha)
|
226
|
+
if path =~ /\//
|
227
|
+
paths = path.split('/')
|
228
|
+
last = path[path.size - 1, 1]
|
229
|
+
if (last == '/') && (paths.size == 1)
|
230
|
+
append = append ? File.join(append, paths.first) : paths.first
|
231
|
+
dir_name = tree.split("\n").select { |p| p.split("\t")[1] == paths.first }.first
|
232
|
+
raise NoSuchPath if !dir_name
|
233
|
+
next_sha = dir_name.split(' ')[2]
|
234
|
+
tree = get_raw_tree(next_sha)
|
235
|
+
tree = tree.split("\n")
|
236
|
+
if append
|
237
|
+
mod_tree = []
|
238
|
+
tree.each do |ent|
|
239
|
+
(info, fpath) = ent.split("\t")
|
240
|
+
mod_tree << [info, File.join(append, fpath)].join("\t")
|
241
|
+
end
|
242
|
+
mod_tree
|
243
|
+
else
|
244
|
+
tree
|
245
|
+
end
|
246
|
+
else
|
247
|
+
raise NoSuchPath if tree.nil?
|
248
|
+
next_path = paths.shift
|
249
|
+
dir_name = tree.split("\n").select { |p| p.split("\t")[1] == next_path }.first
|
250
|
+
raise NoSuchPath if !dir_name
|
251
|
+
next_sha = dir_name.split(' ')[2]
|
252
|
+
next_path = append ? File.join(append, next_path) : next_path
|
253
|
+
if (last == '/')
|
254
|
+
ls_tree_path(next_sha, paths.join("/") + '/', next_path)
|
255
|
+
else
|
256
|
+
ls_tree_path(next_sha, paths.join("/"), next_path)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
else
|
260
|
+
raise NoSuchPath if tree.nil?
|
261
|
+
tree = tree.split("\n")
|
262
|
+
tree = tree.select { |p| p.split("\t")[1] == path }
|
263
|
+
if append
|
264
|
+
mod_tree = []
|
265
|
+
tree.each do |ent|
|
266
|
+
(info, fpath) = ent.split("\t")
|
267
|
+
mod_tree << [info, File.join(append, fpath)].join("\t")
|
268
|
+
end
|
269
|
+
mod_tree
|
270
|
+
else
|
271
|
+
tree
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# returns an array of GitRuby Commit objects
|
277
|
+
# [ [sha, raw_output], [sha, raw_output], [sha, raw_output] ... ]
|
278
|
+
#
|
279
|
+
# takes the following options:
|
280
|
+
# :since - Time object specifying that you don't want commits BEFORE this
|
281
|
+
# :until - Time object specifying that you don't want commit AFTER this
|
282
|
+
# :first_parent - tells log to only walk first parent
|
283
|
+
# :path_limiter - string or array of strings to limit path
|
284
|
+
# :max_count - number to limit the output
|
285
|
+
def log(sha, options = {})
|
286
|
+
@already_searched = {}
|
287
|
+
walk_log(sha, options)
|
288
|
+
end
|
289
|
+
|
290
|
+
def truncate_arr(arr, sha)
|
291
|
+
new_arr = []
|
292
|
+
arr.each do |a|
|
293
|
+
if a[0] == sha
|
294
|
+
return new_arr
|
295
|
+
end
|
296
|
+
new_arr << a
|
297
|
+
end
|
298
|
+
return new_arr
|
299
|
+
end
|
300
|
+
|
301
|
+
def rev_list(sha, options)
|
302
|
+
if sha.is_a? Array
|
303
|
+
(end_sha, sha) = sha
|
304
|
+
end
|
305
|
+
|
306
|
+
log = log(sha, options)
|
307
|
+
log = log.sort { |a, b| a[2] <=> b[2] }.reverse
|
308
|
+
|
309
|
+
if end_sha
|
310
|
+
log = truncate_arr(log, end_sha)
|
311
|
+
end
|
312
|
+
|
313
|
+
# shorten the list if it's longer than max_count (had to get everything in branches)
|
314
|
+
if options[:max_count]
|
315
|
+
if (opt_len = options[:max_count].to_i) < log.size
|
316
|
+
log = log[0, opt_len]
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
if options[:pretty] == 'raw'
|
321
|
+
log.map {|k, v| v }.join('')
|
322
|
+
else
|
323
|
+
log.map {|k, v| k }.join("\n")
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
# called by log() to recursively walk the tree
|
328
|
+
def walk_log(sha, opts, total_size = 0)
|
329
|
+
return [] if @already_searched[sha] # to prevent rechecking branches
|
330
|
+
@already_searched[sha] = true
|
331
|
+
|
332
|
+
array = []
|
333
|
+
if (sha)
|
334
|
+
o = get_raw_object_by_sha1(sha)
|
335
|
+
if o.type == :tag
|
336
|
+
commit_sha = get_object_by_sha1(sha).object
|
337
|
+
c = get_object_by_sha1(commit_sha)
|
338
|
+
else
|
339
|
+
c = GitObject.from_raw(o)
|
340
|
+
end
|
341
|
+
|
342
|
+
return [] if c.type != :commit
|
343
|
+
|
344
|
+
add_sha = true
|
345
|
+
|
346
|
+
if opts[:since] && opts[:since].is_a?(Time) && (opts[:since] > c.committer.date)
|
347
|
+
add_sha = false
|
348
|
+
end
|
349
|
+
if opts[:until] && opts[:until].is_a?(Time) && (opts[:until] < c.committer.date)
|
350
|
+
add_sha = false
|
351
|
+
end
|
352
|
+
|
353
|
+
# follow all parents unless '--first-parent' is specified #
|
354
|
+
subarray = []
|
355
|
+
|
356
|
+
if !c.parent.first && opts[:path_limiter] # check for the last commit
|
357
|
+
add_sha = false
|
358
|
+
end
|
359
|
+
|
360
|
+
if (!opts[:max_count] || ((array.size + total_size) < opts[:max_count]))
|
361
|
+
|
362
|
+
if !opts[:path_limiter]
|
363
|
+
output = c.raw_log(sha)
|
364
|
+
array << [sha, output, c.committer.date]
|
365
|
+
end
|
366
|
+
|
367
|
+
if (opts[:max_count] && (array.size + total_size) >= opts[:max_count])
|
368
|
+
return array
|
369
|
+
end
|
370
|
+
|
371
|
+
c.parent.each do |psha|
|
372
|
+
if psha && !files_changed?(c.tree, get_object_by_sha1(psha).tree,
|
373
|
+
opts[:path_limiter])
|
374
|
+
add_sha = false
|
375
|
+
end
|
376
|
+
subarray += walk_log(psha, opts, (array.size + total_size))
|
377
|
+
next if opts[:first_parent]
|
378
|
+
end
|
379
|
+
|
380
|
+
if opts[:path_limiter] && add_sha
|
381
|
+
output = c.raw_log(sha)
|
382
|
+
array << [sha, output, c.committer.date]
|
383
|
+
end
|
384
|
+
|
385
|
+
if add_sha
|
386
|
+
array += subarray
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
end
|
391
|
+
|
392
|
+
array
|
393
|
+
end
|
394
|
+
|
395
|
+
def diff(commit1, commit2, options = {})
|
396
|
+
patch = ''
|
397
|
+
|
398
|
+
commit_obj1 = get_object_by_sha1(commit1)
|
399
|
+
tree1 = commit_obj1.tree
|
400
|
+
if commit2
|
401
|
+
tree2 = get_object_by_sha1(commit2).tree
|
402
|
+
else
|
403
|
+
tree2 = get_object_by_sha1(commit_obj1.parent.first).tree
|
404
|
+
end
|
405
|
+
|
406
|
+
qdiff = quick_diff(tree1, tree2)
|
407
|
+
|
408
|
+
qdiff.sort.each do |diff_arr|
|
409
|
+
path, status, treeSHA1, treeSHA2 = *diff_arr
|
410
|
+
format, lines, output = :unified, 3, ''
|
411
|
+
file_length_difference = 0
|
412
|
+
|
413
|
+
fileA = treeSHA1 ? cat_file(treeSHA1) : ''
|
414
|
+
fileB = treeSHA2 ? cat_file(treeSHA2) : ''
|
415
|
+
|
416
|
+
sha1 = treeSHA1 || '0000000000000000000000000000000000000000'
|
417
|
+
sha2 = treeSHA2 || '0000000000000000000000000000000000000000'
|
418
|
+
|
419
|
+
data_old = fileA.split(/\n/).map! { |e| e.chomp }
|
420
|
+
data_new = fileB.split(/\n/).map! { |e| e.chomp }
|
421
|
+
|
422
|
+
diffs = Difference::LCS.diff(data_old, data_new)
|
423
|
+
next if diffs.empty?
|
424
|
+
|
425
|
+
a_path = "a/#{path.gsub('./', '')}"
|
426
|
+
b_path = "b/#{path.gsub('./', '')}"
|
427
|
+
|
428
|
+
header = "diff --git #{a_path} #{b_path}"
|
429
|
+
if options[:full_index]
|
430
|
+
header << "\n" + 'index ' + sha1 + '..' + sha2
|
431
|
+
header << ' 100644' if treeSHA2 # hard coding this because i don't think we use it
|
432
|
+
else
|
433
|
+
header << "\n" + 'index ' + sha1[0,7] + '..' + sha2[0,7]
|
434
|
+
header << ' 100644' if treeSHA2 # hard coding this because i don't think we use it
|
435
|
+
end
|
436
|
+
header << "\n--- " + (treeSHA1 ? a_path : '/dev/null')
|
437
|
+
header << "\n+++ " + (treeSHA2 ? b_path : '/dev/null')
|
438
|
+
header += "\n"
|
439
|
+
|
440
|
+
oldhunk = hunk = nil
|
441
|
+
|
442
|
+
diffs.each do |piece|
|
443
|
+
begin
|
444
|
+
hunk = Difference::LCS::Hunk.new(data_old, data_new, piece, lines, file_length_difference)
|
445
|
+
file_length_difference = hunk.file_length_difference
|
446
|
+
|
447
|
+
next unless oldhunk
|
448
|
+
|
449
|
+
if lines > 0 && hunk.overlaps?(oldhunk)
|
450
|
+
hunk.unshift(oldhunk)
|
451
|
+
else
|
452
|
+
output << oldhunk.diff(format)
|
453
|
+
end
|
454
|
+
ensure
|
455
|
+
oldhunk = hunk
|
456
|
+
output << "\n"
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
output << oldhunk.diff(format)
|
461
|
+
output << "\n"
|
462
|
+
|
463
|
+
patch << header + output.lstrip
|
464
|
+
end
|
465
|
+
patch
|
466
|
+
rescue
|
467
|
+
'' # one of the trees was bad or lcs isn't there - no diff
|
468
|
+
end
|
469
|
+
|
470
|
+
# takes 2 tree shas and recursively walks them to find out what
|
471
|
+
# files or directories have been modified in them and returns an
|
472
|
+
# array of changes
|
473
|
+
# [ [full_path, 'added', tree1_hash, nil],
|
474
|
+
# [full_path, 'removed', nil, tree2_hash],
|
475
|
+
# [full_path, 'modified', tree1_hash, tree2_hash]
|
476
|
+
# ]
|
477
|
+
def quick_diff(tree1, tree2, path = '.', recurse = true)
|
478
|
+
# handle empty trees
|
479
|
+
changed = []
|
480
|
+
return changed if tree1 == tree2
|
481
|
+
|
482
|
+
t1 = list_tree(tree1) if tree1
|
483
|
+
t2 = list_tree(tree2) if tree2
|
484
|
+
|
485
|
+
# finding files that are different
|
486
|
+
t1['blob'].each do |file, hsh|
|
487
|
+
t2_file = t2['blob'][file] rescue nil
|
488
|
+
full = File.join(path, file)
|
489
|
+
if !t2_file
|
490
|
+
changed << [full, 'added', hsh[:sha], nil] # not in parent
|
491
|
+
elsif (hsh[:sha] != t2_file[:sha])
|
492
|
+
changed << [full, 'modified', hsh[:sha], t2_file[:sha]] # file changed
|
493
|
+
end
|
494
|
+
end if t1
|
495
|
+
t2['blob'].each do |file, hsh|
|
496
|
+
if !t1 || !t1['blob'][file]
|
497
|
+
changed << [File.join(path, file), 'removed', nil, hsh[:sha]]
|
498
|
+
end
|
499
|
+
end if t2
|
500
|
+
|
501
|
+
t1['tree'].each do |dir, hsh|
|
502
|
+
t2_tree = t2['tree'][dir] rescue nil
|
503
|
+
full = File.join(path, dir)
|
504
|
+
if !t2_tree
|
505
|
+
if recurse
|
506
|
+
changed += quick_diff(hsh[:sha], nil, full, true)
|
507
|
+
else
|
508
|
+
changed << [full, 'added', hsh[:sha], nil] # not in parent
|
509
|
+
end
|
510
|
+
elsif (hsh[:sha] != t2_tree[:sha])
|
511
|
+
if recurse
|
512
|
+
changed += quick_diff(hsh[:sha], t2_tree[:sha], full, true)
|
513
|
+
else
|
514
|
+
changed << [full, 'modified', hsh[:sha], t2_tree[:sha]] # file changed
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end if t1
|
518
|
+
t2['tree'].each do |dir, hsh|
|
519
|
+
t1_tree = t1['tree'][dir] rescue nil
|
520
|
+
full = File.join(path, dir)
|
521
|
+
if !t1_tree
|
522
|
+
if recurse
|
523
|
+
changed += quick_diff(nil, hsh[:sha], full, true)
|
524
|
+
else
|
525
|
+
changed << [full, 'removed', nil, hsh[:sha]]
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end if t2
|
529
|
+
|
530
|
+
changed
|
531
|
+
end
|
532
|
+
|
533
|
+
# returns true if the files in path_limiter were changed, or no path limiter
|
534
|
+
# used by the log() function when passed with a path_limiter
|
535
|
+
def files_changed?(tree_sha1, tree_sha2, path_limiter = nil)
|
536
|
+
if path_limiter
|
537
|
+
mod = quick_diff(tree_sha1, tree_sha2)
|
538
|
+
files = mod.map { |c| c.first }
|
539
|
+
path_limiter.to_a.each do |filepath|
|
540
|
+
if files.include?(filepath)
|
541
|
+
return true
|
542
|
+
end
|
543
|
+
end
|
544
|
+
return false
|
545
|
+
end
|
546
|
+
true
|
547
|
+
end
|
548
|
+
|
549
|
+
def get_subtree(commit_sha, path)
|
550
|
+
tree_sha = get_object_by_sha1(commit_sha).tree
|
551
|
+
|
552
|
+
if path && !(path == '' || path == '.' || path == './')
|
553
|
+
paths = path.split('/')
|
554
|
+
paths.each do |path|
|
555
|
+
tree = get_object_by_sha1(tree_sha)
|
556
|
+
if entry = tree.entry.select { |e| e.name == path }.first
|
557
|
+
tree_sha = entry.sha1 rescue nil
|
558
|
+
else
|
559
|
+
return false
|
560
|
+
end
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
564
|
+
tree_sha
|
565
|
+
end
|
566
|
+
|
567
|
+
def blame_tree(commit_sha, path)
|
568
|
+
# find subtree
|
569
|
+
tree_sha = get_subtree(commit_sha, path)
|
570
|
+
return {} if !tree_sha
|
571
|
+
|
572
|
+
looking_for = []
|
573
|
+
get_object_by_sha1(tree_sha).entry.each do |e|
|
574
|
+
looking_for << File.join('.', e.name)
|
575
|
+
end
|
576
|
+
|
577
|
+
@already_searched = {}
|
578
|
+
commits = look_for_commits(commit_sha, path, looking_for)
|
579
|
+
|
580
|
+
# cleaning up array
|
581
|
+
arr = {}
|
582
|
+
commits.each do |commit_array|
|
583
|
+
key = commit_array[0].gsub('./', '')
|
584
|
+
arr[key] = commit_array[1]
|
585
|
+
end
|
586
|
+
arr
|
587
|
+
end
|
588
|
+
|
589
|
+
def look_for_commits(commit_sha, path, looking_for, options = {})
|
590
|
+
return [] if @already_searched[commit_sha] # to prevent rechecking branches
|
591
|
+
|
592
|
+
@already_searched[commit_sha] = true
|
593
|
+
|
594
|
+
commit = get_object_by_sha1(commit_sha)
|
595
|
+
tree_sha = get_subtree(commit_sha, path)
|
596
|
+
|
597
|
+
found_data = []
|
598
|
+
|
599
|
+
# at the beginning of the branch
|
600
|
+
if commit.parent.size == 0
|
601
|
+
looking_for.each do |search|
|
602
|
+
# prevents the rare case of multiple branch starting points with
|
603
|
+
# files that have never changed
|
604
|
+
if found_data.assoc(search)
|
605
|
+
found_data << [search, commit_sha]
|
606
|
+
end
|
607
|
+
end
|
608
|
+
return found_data
|
609
|
+
end
|
610
|
+
|
611
|
+
# go through the parents recursively, looking for somewhere this has been changed
|
612
|
+
commit.parent.each do |pc|
|
613
|
+
diff = quick_diff(tree_sha, get_subtree(pc, path), '.', false)
|
614
|
+
|
615
|
+
# remove anything found
|
616
|
+
looking_for.each do |search|
|
617
|
+
if match = diff.assoc(search)
|
618
|
+
found_data << [search, commit_sha, match]
|
619
|
+
looking_for.delete(search)
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
if looking_for.size <= 0 # we're done
|
624
|
+
return found_data
|
625
|
+
end
|
626
|
+
|
627
|
+
found_data += look_for_commits(pc, path, looking_for) # recurse into parent
|
628
|
+
return found_data if options[:first_parent]
|
629
|
+
end
|
630
|
+
|
631
|
+
## TODO : find most recent commit with change in any parent
|
632
|
+
found_data
|
633
|
+
end
|
634
|
+
|
635
|
+
# initialize a git repository
|
636
|
+
def self.init(dir, bare = true)
|
637
|
+
|
638
|
+
FileUtils.mkdir_p(dir) if !File.exists?(dir)
|
639
|
+
|
640
|
+
FileUtils.cd(dir) do
|
641
|
+
if(File.exists?('objects'))
|
642
|
+
return false # already initialized
|
643
|
+
else
|
644
|
+
# initialize directory
|
645
|
+
create_initial_config(bare)
|
646
|
+
FileUtils.mkdir_p('refs/heads')
|
647
|
+
FileUtils.mkdir_p('refs/tags')
|
648
|
+
FileUtils.mkdir_p('objects/info')
|
649
|
+
FileUtils.mkdir_p('objects/pack')
|
650
|
+
FileUtils.mkdir_p('branches')
|
651
|
+
add_file('description', 'Unnamed repository; edit this file to name it for gitweb.')
|
652
|
+
add_file('HEAD', "ref: refs/heads/master\n")
|
653
|
+
FileUtils.mkdir_p('hooks')
|
654
|
+
FileUtils.cd('hooks') do
|
655
|
+
add_file('applypatch-msg', '# add shell script and make executable to enable')
|
656
|
+
add_file('post-commit', '# add shell script and make executable to enable')
|
657
|
+
add_file('post-receive', '# add shell script and make executable to enable')
|
658
|
+
add_file('post-update', '# add shell script and make executable to enable')
|
659
|
+
add_file('pre-applypatch', '# add shell script and make executable to enable')
|
660
|
+
add_file('pre-commit', '# add shell script and make executable to enable')
|
661
|
+
add_file('pre-rebase', '# add shell script and make executable to enable')
|
662
|
+
add_file('update', '# add shell script and make executable to enable')
|
663
|
+
end
|
664
|
+
FileUtils.mkdir_p('info')
|
665
|
+
add_file('info/exclude', "# *.[oa]\n# *~")
|
666
|
+
end
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
def self.create_initial_config(bare = false)
|
671
|
+
bare ? bare_status = 'true' : bare_status = 'false'
|
672
|
+
config = "[core]\n\trepositoryformatversion = 0\n\tfilemode = true\n\tbare = #{bare_status}\n\tlogallrefupdates = true"
|
673
|
+
add_file('config', config)
|
674
|
+
end
|
675
|
+
|
676
|
+
def self.add_file(name, contents)
|
677
|
+
File.open(name, 'w') do |f|
|
678
|
+
f.write contents
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
def close
|
683
|
+
@packs.each do |pack|
|
684
|
+
pack.close
|
685
|
+
end if @packs
|
686
|
+
end
|
687
|
+
|
688
|
+
protected
|
689
|
+
|
690
|
+
def git_path(path)
|
691
|
+
return "#@git_dir/#{path}"
|
692
|
+
end
|
693
|
+
|
694
|
+
private
|
695
|
+
|
696
|
+
def initloose
|
697
|
+
@loaded = []
|
698
|
+
@loose = []
|
699
|
+
load_loose(git_path('objects'))
|
700
|
+
load_alternate_loose(git_path('objects'))
|
701
|
+
@loose
|
702
|
+
end
|
703
|
+
|
704
|
+
def load_alternate_loose(path)
|
705
|
+
# load alternate loose, too
|
706
|
+
alt = File.join(path, 'info/alternates')
|
707
|
+
if File.exists?(alt)
|
708
|
+
File.readlines(alt).each do |line|
|
709
|
+
next if @loaded.include?(line.chomp)
|
710
|
+
if line[0, 2] == '..'
|
711
|
+
line = File.expand_path(File.join(@git_dir, line))
|
712
|
+
end
|
713
|
+
load_loose(line.chomp)
|
714
|
+
load_alternate_loose(line.chomp)
|
715
|
+
end
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
def load_loose(path)
|
720
|
+
@loaded << path
|
721
|
+
return if !File.exists?(path)
|
722
|
+
@loose << Grit::GitRuby::Internal::LooseStorage.new(path)
|
723
|
+
end
|
724
|
+
|
725
|
+
def initpacks
|
726
|
+
close
|
727
|
+
@loaded_packs = []
|
728
|
+
@packs = []
|
729
|
+
load_packs(git_path("objects/pack"))
|
730
|
+
load_alternate_packs(git_path('objects'))
|
731
|
+
@packs
|
732
|
+
end
|
733
|
+
|
734
|
+
def load_alternate_packs(path)
|
735
|
+
alt = File.join(path, 'info/alternates')
|
736
|
+
if File.exists?(alt)
|
737
|
+
File.readlines(alt).each do |line|
|
738
|
+
if line[0, 2] == '..'
|
739
|
+
line = File.expand_path(File.join(@git_dir, line))
|
740
|
+
end
|
741
|
+
full_pack = File.join(line.chomp, 'pack')
|
742
|
+
next if @loaded_packs.include?(full_pack)
|
743
|
+
load_packs(full_pack)
|
744
|
+
load_alternate_packs(File.join(line.chomp))
|
745
|
+
end
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
def load_packs(path)
|
750
|
+
@loaded_packs << path
|
751
|
+
return if !File.exists?(path)
|
752
|
+
Dir.open(path) do |dir|
|
753
|
+
dir.each do |entry|
|
754
|
+
next if !(entry =~ /\.pack$/i)
|
755
|
+
pack = Grit::GitRuby::Internal::PackStorage.new(File.join(path,entry))
|
756
|
+
if @options[:map_packfile]
|
757
|
+
pack.cache_objects
|
758
|
+
end
|
759
|
+
@packs << pack
|
760
|
+
end
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
end
|
765
|
+
|
766
|
+
end
|
767
|
+
end
|