schleyfox-grit 2.3.0
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/API.txt +101 -0
- data/History.txt +117 -0
- data/LICENSE +22 -0
- data/PURE_TODO +35 -0
- data/README.md +242 -0
- data/Rakefile +149 -0
- data/benchmarks.rb +129 -0
- data/benchmarks.txt +21 -0
- data/examples/ex_add_commit.rb +13 -0
- data/examples/ex_index.rb +21 -0
- data/lib/grit.rb +83 -0
- data/lib/grit/actor.rb +52 -0
- data/lib/grit/blame.rb +61 -0
- data/lib/grit/blob.rb +126 -0
- data/lib/grit/commit.rb +294 -0
- data/lib/grit/commit_stats.rb +128 -0
- data/lib/grit/config.rb +44 -0
- data/lib/grit/diff.rb +79 -0
- data/lib/grit/errors.rb +10 -0
- data/lib/grit/git-ruby.rb +272 -0
- data/lib/grit/git-ruby/commit_db.rb +52 -0
- data/lib/grit/git-ruby/file_index.rb +193 -0
- data/lib/grit/git-ruby/git_object.rb +350 -0
- data/lib/grit/git-ruby/internal/file_window.rb +58 -0
- data/lib/grit/git-ruby/internal/loose.rb +137 -0
- data/lib/grit/git-ruby/internal/pack.rb +384 -0
- data/lib/grit/git-ruby/internal/raw_object.rb +37 -0
- data/lib/grit/git-ruby/object.rb +325 -0
- data/lib/grit/git-ruby/repository.rb +775 -0
- data/lib/grit/git.rb +324 -0
- data/lib/grit/index.rb +197 -0
- data/lib/grit/lazy.rb +35 -0
- data/lib/grit/merge.rb +45 -0
- data/lib/grit/open3_detach.rb +46 -0
- data/lib/grit/ref.rb +78 -0
- data/lib/grit/repo.rb +657 -0
- data/lib/grit/ruby1.9.rb +7 -0
- data/lib/grit/status.rb +153 -0
- data/lib/grit/submodule.rb +88 -0
- data/lib/grit/tag.rb +71 -0
- data/lib/grit/tree.rb +125 -0
- metadata +141 -0
data/lib/grit/git.rb
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
module Grit
|
3
|
+
|
4
|
+
class Git
|
5
|
+
class GitTimeout < RuntimeError
|
6
|
+
attr_reader :command, :bytes_read
|
7
|
+
|
8
|
+
def initialize(command = nil, bytes_read = nil)
|
9
|
+
@command = command
|
10
|
+
@bytes_read = bytes_read
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
undef_method :clone
|
15
|
+
|
16
|
+
include GitRuby
|
17
|
+
|
18
|
+
def exist?
|
19
|
+
File.exist?(self.git_dir)
|
20
|
+
end
|
21
|
+
|
22
|
+
def put_raw_object(content, type)
|
23
|
+
ruby_git.put_raw_object(content, type)
|
24
|
+
end
|
25
|
+
|
26
|
+
def object_exists?(object_id)
|
27
|
+
ruby_git.object_exists?(object_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def select_existing_objects(object_ids)
|
31
|
+
object_ids.select do |object_id|
|
32
|
+
object_exists?(object_id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class << self
|
37
|
+
attr_accessor :git_binary, :git_timeout, :git_max_size
|
38
|
+
end
|
39
|
+
|
40
|
+
if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
|
41
|
+
self.git_binary = "git" # using search path
|
42
|
+
else
|
43
|
+
self.git_binary = "/usr/bin/env git"
|
44
|
+
end
|
45
|
+
self.git_timeout = 10
|
46
|
+
self.git_max_size = 5242880 # 5.megabytes
|
47
|
+
|
48
|
+
def self.with_timeout(timeout = 10.seconds)
|
49
|
+
old_timeout = Grit::Git.git_timeout
|
50
|
+
Grit::Git.git_timeout = timeout
|
51
|
+
yield
|
52
|
+
Grit::Git.git_timeout = old_timeout
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_accessor :git_dir, :bytes_read, :work_tree
|
56
|
+
|
57
|
+
def initialize(git_dir)
|
58
|
+
self.git_dir = git_dir
|
59
|
+
self.work_tree = git_dir.gsub(/\/\.git$/,'')
|
60
|
+
self.bytes_read = 0
|
61
|
+
end
|
62
|
+
|
63
|
+
def shell_escape(str)
|
64
|
+
str.to_s.gsub("'", "\\\\'").gsub(";", '\\;')
|
65
|
+
end
|
66
|
+
alias_method :e, :shell_escape
|
67
|
+
|
68
|
+
# Check if a normal file exists on the filesystem
|
69
|
+
# +file+ is the relative path from the Git dir
|
70
|
+
#
|
71
|
+
# Returns Boolean
|
72
|
+
def fs_exist?(file)
|
73
|
+
File.exist?(File.join(self.git_dir, file))
|
74
|
+
end
|
75
|
+
|
76
|
+
# Read a normal file from the filesystem.
|
77
|
+
# +file+ is the relative path from the Git dir
|
78
|
+
#
|
79
|
+
# Returns the String contents of the file
|
80
|
+
def fs_read(file)
|
81
|
+
File.read(File.join(self.git_dir, file))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Write a normal file to the filesystem.
|
85
|
+
# +file+ is the relative path from the Git dir
|
86
|
+
# +contents+ is the String content to be written
|
87
|
+
#
|
88
|
+
# Returns nothing
|
89
|
+
def fs_write(file, contents)
|
90
|
+
path = File.join(self.git_dir, file)
|
91
|
+
FileUtils.mkdir_p(File.dirname(path))
|
92
|
+
File.open(path, 'w') do |f|
|
93
|
+
f.write(contents)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Delete a normal file from the filesystem
|
98
|
+
# +file+ is the relative path from the Git dir
|
99
|
+
#
|
100
|
+
# Returns nothing
|
101
|
+
def fs_delete(file)
|
102
|
+
FileUtils.rm_rf(File.join(self.git_dir, file))
|
103
|
+
end
|
104
|
+
|
105
|
+
# Move a normal file
|
106
|
+
# +from+ is the relative path to the current file
|
107
|
+
# +to+ is the relative path to the destination file
|
108
|
+
#
|
109
|
+
# Returns nothing
|
110
|
+
def fs_move(from, to)
|
111
|
+
FileUtils.mv(File.join(self.git_dir, from), File.join(self.git_dir, to))
|
112
|
+
end
|
113
|
+
|
114
|
+
# Make a directory
|
115
|
+
# +dir+ is the relative path to the directory to create
|
116
|
+
#
|
117
|
+
# Returns nothing
|
118
|
+
def fs_mkdir(dir)
|
119
|
+
FileUtils.mkdir_p(File.join(self.git_dir, dir))
|
120
|
+
end
|
121
|
+
|
122
|
+
# Chmod the the file or dir and everything beneath
|
123
|
+
# +file+ is the relative path from the Git dir
|
124
|
+
#
|
125
|
+
# Returns nothing
|
126
|
+
def fs_chmod(mode, file = '/')
|
127
|
+
FileUtils.chmod_R(mode, File.join(self.git_dir, file))
|
128
|
+
end
|
129
|
+
|
130
|
+
def list_remotes
|
131
|
+
remotes = []
|
132
|
+
Dir.chdir(File.join(self.git_dir, 'refs/remotes')) do
|
133
|
+
remotes = Dir.glob('*')
|
134
|
+
end
|
135
|
+
remotes
|
136
|
+
rescue
|
137
|
+
[]
|
138
|
+
end
|
139
|
+
|
140
|
+
def create_tempfile(seed, unlink = false)
|
141
|
+
path = Tempfile.new(seed).path
|
142
|
+
File.unlink(path) if unlink
|
143
|
+
return path
|
144
|
+
end
|
145
|
+
|
146
|
+
def commit_from_sha(id)
|
147
|
+
git_ruby_repo = GitRuby::Repository.new(self.git_dir)
|
148
|
+
object = git_ruby_repo.get_object_by_sha1(id)
|
149
|
+
|
150
|
+
if object.type == :commit
|
151
|
+
id
|
152
|
+
elsif object.type == :tag
|
153
|
+
object.object
|
154
|
+
else
|
155
|
+
''
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def check_applies(head_sha, applies_sha)
|
160
|
+
git_index = create_tempfile('index', true)
|
161
|
+
(o1, exit1) = raw_git("git read-tree #{head_sha} 2>/dev/null", git_index)
|
162
|
+
(o2, exit2) = raw_git("git diff #{applies_sha}^ #{applies_sha} | git apply --check --cached >/dev/null 2>/dev/null", git_index)
|
163
|
+
return (exit1 + exit2)
|
164
|
+
end
|
165
|
+
|
166
|
+
def get_patch(applies_sha)
|
167
|
+
git_index = create_tempfile('index', true)
|
168
|
+
(patch, exit2) = raw_git("git diff #{applies_sha}^ #{applies_sha}", git_index)
|
169
|
+
patch
|
170
|
+
end
|
171
|
+
|
172
|
+
def apply_patch(head_sha, patch)
|
173
|
+
git_index = create_tempfile('index', true)
|
174
|
+
|
175
|
+
git_patch = create_tempfile('patch')
|
176
|
+
File.open(git_patch, 'w+') { |f| f.print patch }
|
177
|
+
|
178
|
+
raw_git("git read-tree #{head_sha} 2>/dev/null", git_index)
|
179
|
+
(op, exit) = raw_git("git apply --cached < #{git_patch}", git_index)
|
180
|
+
if exit == 0
|
181
|
+
return raw_git("git write-tree", git_index).first.chomp
|
182
|
+
end
|
183
|
+
false
|
184
|
+
end
|
185
|
+
|
186
|
+
# RAW CALLS WITH ENV SETTINGS
|
187
|
+
def raw_git_call(command, index)
|
188
|
+
tmp = ENV['GIT_INDEX_FILE']
|
189
|
+
ENV['GIT_INDEX_FILE'] = index
|
190
|
+
out = `#{command}`
|
191
|
+
after = ENV['GIT_INDEX_FILE'] # someone fucking with us ??
|
192
|
+
ENV['GIT_INDEX_FILE'] = tmp
|
193
|
+
if after != index
|
194
|
+
raise 'environment was changed for the git call'
|
195
|
+
end
|
196
|
+
[out, $?.exitstatus]
|
197
|
+
end
|
198
|
+
|
199
|
+
def raw_git(command, index)
|
200
|
+
output = nil
|
201
|
+
Dir.chdir(self.git_dir) do
|
202
|
+
output = raw_git_call(command, index)
|
203
|
+
end
|
204
|
+
output
|
205
|
+
end
|
206
|
+
# RAW CALLS WITH ENV SETTINGS END
|
207
|
+
|
208
|
+
|
209
|
+
|
210
|
+
# Run the given git command with the specified arguments and return
|
211
|
+
# the result as a String
|
212
|
+
# +cmd+ is the command
|
213
|
+
# +options+ is a hash of Ruby style options
|
214
|
+
# +args+ is the list of arguments (to be joined by spaces)
|
215
|
+
#
|
216
|
+
# Examples
|
217
|
+
# git.rev_list({:max_count => 10, :header => true}, "master")
|
218
|
+
#
|
219
|
+
# Returns String
|
220
|
+
def method_missing(cmd, options = {}, *args, &block)
|
221
|
+
run('', cmd, '', options, args, &block)
|
222
|
+
end
|
223
|
+
|
224
|
+
# Bypass any pure Ruby implementations and go straight to the native Git command
|
225
|
+
#
|
226
|
+
# Returns String
|
227
|
+
def native(cmd, options = {}, *args, &block)
|
228
|
+
method_missing(cmd, options, *args, &block)
|
229
|
+
end
|
230
|
+
|
231
|
+
def run(prefix, cmd, postfix, options, args, &block)
|
232
|
+
timeout = options.delete(:timeout) rescue nil
|
233
|
+
timeout = true if timeout.nil?
|
234
|
+
|
235
|
+
base = options.delete(:base) rescue nil
|
236
|
+
base = true if base.nil?
|
237
|
+
|
238
|
+
opt_args = transform_options(options)
|
239
|
+
|
240
|
+
if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
|
241
|
+
ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|' || Grit.no_quote) ? a : "\"#{e(a)}\"" }
|
242
|
+
gitdir = base ? "--git-dir=\"#{self.git_dir}\"" : ""
|
243
|
+
call = "#{prefix}#{Git.git_binary} #{gitdir} #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
|
244
|
+
else
|
245
|
+
ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|' || Grit.no_quote) ? a : "'#{e(a)}'" }
|
246
|
+
gitdir = base ? "--git-dir='#{self.git_dir}'" : ""
|
247
|
+
call = "#{prefix}#{Git.git_binary} #{gitdir} #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
|
248
|
+
end
|
249
|
+
Grit.log(call) if Grit.debug
|
250
|
+
response, err = timeout ? sh(call, &block) : wild_sh(call, &block)
|
251
|
+
Grit.log(response) if Grit.debug
|
252
|
+
Grit.log(err) if Grit.debug
|
253
|
+
response
|
254
|
+
end
|
255
|
+
|
256
|
+
def sh(command, &block)
|
257
|
+
ret, err = '', ''
|
258
|
+
max = self.class.git_max_size
|
259
|
+
Open3.popen3(command) do |stdin, stdout, stderr|
|
260
|
+
block.call(stdin) if block
|
261
|
+
Timeout.timeout(self.class.git_timeout) do
|
262
|
+
while tmp = stdout.read(8192)
|
263
|
+
ret << tmp
|
264
|
+
raise GitTimeout.new(command, ret.size) if ret.size > max
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
while tmp = stderr.read(8192)
|
269
|
+
err << tmp
|
270
|
+
end
|
271
|
+
end
|
272
|
+
[ret, err]
|
273
|
+
rescue Timeout::Error, Grit::Git::GitTimeout
|
274
|
+
raise GitTimeout.new(command, ret.size)
|
275
|
+
end
|
276
|
+
|
277
|
+
def wild_sh(command, &block)
|
278
|
+
ret, err = '', ''
|
279
|
+
Open3.popen3(command) do |stdin, stdout, stderr|
|
280
|
+
block.call(stdin) if block
|
281
|
+
while tmp = stdout.read(8192)
|
282
|
+
ret << tmp
|
283
|
+
end
|
284
|
+
|
285
|
+
while tmp = stderr.read(8192)
|
286
|
+
err << tmp
|
287
|
+
end
|
288
|
+
end
|
289
|
+
[ret, err]
|
290
|
+
end
|
291
|
+
|
292
|
+
# Transform Ruby style options into git command line options
|
293
|
+
# +options+ is a hash of Ruby style options
|
294
|
+
#
|
295
|
+
# Returns String[]
|
296
|
+
# e.g. ["--max-count=10", "--header"]
|
297
|
+
def transform_options(options)
|
298
|
+
args = []
|
299
|
+
options.keys.each do |opt|
|
300
|
+
if opt.to_s.size == 1
|
301
|
+
if options[opt] == true
|
302
|
+
args << "-#{opt}"
|
303
|
+
elsif options[opt] == false
|
304
|
+
# ignore
|
305
|
+
else
|
306
|
+
val = options.delete(opt)
|
307
|
+
args << "-#{opt.to_s} '#{e(val)}'"
|
308
|
+
end
|
309
|
+
else
|
310
|
+
if options[opt] == true
|
311
|
+
args << "--#{opt.to_s.gsub(/_/, '-')}"
|
312
|
+
elsif options[opt] == false
|
313
|
+
# ignore
|
314
|
+
else
|
315
|
+
val = options.delete(opt)
|
316
|
+
args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'"
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
args
|
321
|
+
end
|
322
|
+
end # Git
|
323
|
+
|
324
|
+
end # Grit
|
data/lib/grit/index.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Index
|
4
|
+
# Public: Gets/Sets the Grit::Repo to which this index belongs.
|
5
|
+
attr_accessor :repo
|
6
|
+
|
7
|
+
# Public: Gets/Sets the Hash tree map that holds the changes to be made
|
8
|
+
# in the next commit.
|
9
|
+
attr_accessor :tree
|
10
|
+
|
11
|
+
# Public: Gets/Sets the Grit::Tree object representing the tree upon
|
12
|
+
# which the next commit will be based.
|
13
|
+
attr_accessor :current_tree
|
14
|
+
|
15
|
+
# Initialize a new Index object.
|
16
|
+
#
|
17
|
+
# repo - The Grit::Repo to which the index belongs.
|
18
|
+
#
|
19
|
+
# Returns the newly initialized Grit::Index.
|
20
|
+
def initialize(repo)
|
21
|
+
self.repo = repo
|
22
|
+
self.tree = {}
|
23
|
+
self.current_tree = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# Public: Add a file to the index.
|
27
|
+
#
|
28
|
+
# path - The String file path including filename (no slash prefix).
|
29
|
+
# data - The String binary contents of the file.
|
30
|
+
#
|
31
|
+
# Returns nothing.
|
32
|
+
def add(path, data)
|
33
|
+
path = path.split('/')
|
34
|
+
filename = path.pop
|
35
|
+
|
36
|
+
current = self.tree
|
37
|
+
|
38
|
+
path.each do |dir|
|
39
|
+
current[dir] ||= {}
|
40
|
+
node = current[dir]
|
41
|
+
current = node
|
42
|
+
end
|
43
|
+
|
44
|
+
current[filename] = data
|
45
|
+
end
|
46
|
+
|
47
|
+
# Public: Delete the given file from the index.
|
48
|
+
#
|
49
|
+
# path - The String file path including filename (no slash prefix).
|
50
|
+
#
|
51
|
+
# Returns nothing.
|
52
|
+
def delete(path)
|
53
|
+
add(path, false)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Public: Read the contents of the given Tree into the index to use as a
|
57
|
+
# starting point for the index.
|
58
|
+
#
|
59
|
+
# tree - The String branch/tag/sha of the Git tree object.
|
60
|
+
#
|
61
|
+
# Returns nothing.
|
62
|
+
def read_tree(tree)
|
63
|
+
self.current_tree = self.repo.tree(tree)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Public: Commit the contents of the index. This method supports two
|
67
|
+
# formats for arguments:
|
68
|
+
#
|
69
|
+
# message - The String commit message.
|
70
|
+
# options - An optional Hash of index options.
|
71
|
+
# :parents - Array of String commit SHA1s or Grit::Commit
|
72
|
+
# objects to attach this commit to to form a
|
73
|
+
# new head (default: nil).
|
74
|
+
# :actor - The Grit::Actor details of the user making
|
75
|
+
# the commit (default: nil).
|
76
|
+
# :last_tree - The String SHA1 of a tree to compare with
|
77
|
+
# in order to avoid making empty commits
|
78
|
+
# (default: nil).
|
79
|
+
# :head - The String branch name to write this head to
|
80
|
+
# (default: "master").
|
81
|
+
# :committed_date - The Time that the commit was made.
|
82
|
+
# (Default: Time.now)
|
83
|
+
# :authored_date - The Time that the commit was authored.
|
84
|
+
# (Default: committed_date)
|
85
|
+
#
|
86
|
+
# The legacy argument style looks like:
|
87
|
+
#
|
88
|
+
# message - The String commit message.
|
89
|
+
# parents - Array of String commit SHA1s or Grit::Commit objects to
|
90
|
+
# attach this commit to to form a new head (default: nil).
|
91
|
+
# actor - The Grit::Actor details of the user making the commit
|
92
|
+
# (default: nil).
|
93
|
+
# last_tree - The String SHA1 of a tree to compare with in order to avoid
|
94
|
+
# making empty commits (default: nil).
|
95
|
+
# head - The String branch name to write this head to
|
96
|
+
# (default: "master").
|
97
|
+
#
|
98
|
+
# Returns a String of the SHA1 of the new commit.
|
99
|
+
def commit(message, parents = nil, actor = nil, last_tree = nil, head = 'master')
|
100
|
+
if parents.is_a?(Hash)
|
101
|
+
actor = parents[:actor]
|
102
|
+
committer = parents[:committer]
|
103
|
+
author = parents[:author]
|
104
|
+
last_tree = parents[:last_tree]
|
105
|
+
head = parents[:head]
|
106
|
+
committed_date = parents[:committed_date]
|
107
|
+
authored_date = parents[:authored_date]
|
108
|
+
parents = parents[:parents]
|
109
|
+
end
|
110
|
+
|
111
|
+
committer ||= actor
|
112
|
+
author ||= committer
|
113
|
+
|
114
|
+
tree_sha1 = write_tree(self.tree, self.current_tree)
|
115
|
+
|
116
|
+
# don't write identical commits
|
117
|
+
return false if tree_sha1 == last_tree
|
118
|
+
|
119
|
+
contents = []
|
120
|
+
contents << ['tree', tree_sha1].join(' ')
|
121
|
+
parents.each do |p|
|
122
|
+
contents << ['parent', p].join(' ')
|
123
|
+
end if parents
|
124
|
+
|
125
|
+
committer ||= begin
|
126
|
+
config = Config.new(self.repo)
|
127
|
+
Actor.new(config['user.name'], config['user.email'])
|
128
|
+
end
|
129
|
+
author ||= committer
|
130
|
+
committed_date ||= Time.now
|
131
|
+
authored_date ||= committed_date
|
132
|
+
|
133
|
+
contents << ['author', author.output(authored_date)].join(' ')
|
134
|
+
contents << ['committer', committer.output(committed_date)].join(' ')
|
135
|
+
contents << ''
|
136
|
+
contents << message
|
137
|
+
|
138
|
+
commit_sha1 = self.repo.git.put_raw_object(contents.join("\n"), 'commit')
|
139
|
+
|
140
|
+
self.repo.update_ref(head, commit_sha1)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Recursively write a tree to the index.
|
144
|
+
#
|
145
|
+
# tree - The Hash tree map:
|
146
|
+
# key - The String directory or filename.
|
147
|
+
# val - The Hash submap or the String contents of the file.
|
148
|
+
# now_tree - The Grit::Tree representing the a previous tree upon which
|
149
|
+
# this tree will be based (default: nil).
|
150
|
+
#
|
151
|
+
# Returns the String SHA1 String of the tree.
|
152
|
+
def write_tree(tree, now_tree = nil)
|
153
|
+
tree_contents = {}
|
154
|
+
|
155
|
+
# fill in original tree
|
156
|
+
now_tree.contents.each do |obj|
|
157
|
+
sha = [obj.id].pack("H*")
|
158
|
+
k = obj.name
|
159
|
+
k += '/' if (obj.class == Grit::Tree)
|
160
|
+
tmode = obj.mode.to_i.to_s ## remove zero-padding
|
161
|
+
tree_contents[k] = "%s %s\0%s" % [tmode, obj.name, sha]
|
162
|
+
end if now_tree
|
163
|
+
|
164
|
+
# overwrite with new tree contents
|
165
|
+
tree.each do |k, v|
|
166
|
+
case v
|
167
|
+
when String
|
168
|
+
sha = write_blob(v)
|
169
|
+
sha = [sha].pack("H*")
|
170
|
+
str = "%s %s\0%s" % ['100644', k, sha]
|
171
|
+
tree_contents[k] = str
|
172
|
+
when Hash
|
173
|
+
ctree = now_tree/k if now_tree
|
174
|
+
sha = write_tree(v, ctree)
|
175
|
+
sha = [sha].pack("H*")
|
176
|
+
str = "%s %s\0%s" % ['40000', k, sha]
|
177
|
+
tree_contents[k + '/'] = str
|
178
|
+
when false
|
179
|
+
tree_contents.delete(k)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
tr = tree_contents.sort.map { |k, v| v }.join('')
|
184
|
+
self.repo.git.put_raw_object(tr, 'tree')
|
185
|
+
end
|
186
|
+
|
187
|
+
# Write a blob to the index.
|
188
|
+
#
|
189
|
+
# data - The String data to write.
|
190
|
+
#
|
191
|
+
# Returns the String SHA1 of the new blob.
|
192
|
+
def write_blob(data)
|
193
|
+
self.repo.git.put_raw_object(data, 'blob')
|
194
|
+
end
|
195
|
+
end # Index
|
196
|
+
|
197
|
+
end # Grit
|