Skip to content
This repository
Newer
Older
100644 324 lines (277 sloc) 8.938 kb
4e694b9a »
2009-07-23 further file system abstractions
1 require 'tempfile'
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
2 module Grit
18ec70e9 »
2009-10-27 massive whitespace removal
3
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
4 class Git
30e367ce »
2008-03-30 timeout code and tests
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
e631529f »
2008-01-10 add fork_bare
14 undef_method :clone
18ec70e9 »
2009-10-27 massive whitespace removal
15
2d22f889 »
2008-06-24 added a pure-ruby alternative to diff
16 include GitRuby
4e694b9a »
2009-07-23 further file system abstractions
17
18 def exist?
19 File.exist?(self.git_dir)
20 end
21
e976f760 »
2009-05-13 refactor more methods into git-ruby
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
0bd0c5ff »
2010-03-03 implement select_existing_objects
30 def select_existing_objects(object_ids)
31 object_ids.select do |object_id|
32 object_exists?(object_id)
33 end
34 end
35
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
36 class << self
1ab3ab76 »
2009-01-30 Make the number of bytes to be read from git's stdout configurable.
37 attr_accessor :git_binary, :git_timeout, :git_max_size
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
38 end
18ec70e9 »
2009-10-27 massive whitespace removal
39
d5cde35b »
2009-07-23 windows support
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
1ab3ab76 »
2009-01-30 Make the number of bytes to be read from git's stdout configurable.
45 self.git_timeout = 10
46 self.git_max_size = 5242880 # 5.megabytes
18ec70e9 »
2009-10-27 massive whitespace removal
47
1c002dd4 »
2008-12-11 added some blame and merge stuff
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
18ec70e9 »
2009-10-27 massive whitespace removal
54
8c4ec139 »
2009-06-20 sets --work-tree so that adds work
55 attr_accessor :git_dir, :bytes_read, :work_tree
18ec70e9 »
2009-10-27 massive whitespace removal
56
2c6af5a4 »
2007-10-10 implement Repo.commits
57 def initialize(git_dir)
30e367ce »
2008-03-30 timeout code and tests
58 self.git_dir = git_dir
a88d1d96 »
2009-06-20 more terse and more correct
59 self.work_tree = git_dir.gsub(/\/\.git$/,'')
30e367ce »
2008-03-30 timeout code and tests
60 self.bytes_read = 0
2c6af5a4 »
2007-10-10 implement Repo.commits
61 end
18ec70e9 »
2009-10-27 massive whitespace removal
62
ed763978 »
2009-02-13 do some mild shell escaping when running commands
63 def shell_escape(str)
64 str.to_s.gsub("'", "\\\\'").gsub(";", '\\;')
65 end
66 alias_method :e, :shell_escape
18ec70e9 »
2009-10-27 massive whitespace removal
67
4e694b9a »
2009-07-23 further file system abstractions
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
18ec70e9 »
2009-10-27 massive whitespace removal
75
afe9c149 »
2009-04-20 abstract all file system calls into git class
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)
d7d2eb5e »
2010-02-08 close open files as soon as possible
81 File.read(File.join(self.git_dir, file))
afe9c149 »
2009-04-20 abstract all file system calls into git class
82 end
18ec70e9 »
2009-10-27 massive whitespace removal
83
afe9c149 »
2009-04-20 abstract all file system calls into git class
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
18ec70e9 »
2009-10-27 massive whitespace removal
96
afe9c149 »
2009-04-20 abstract all file system calls into git class
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)
4e694b9a »
2009-07-23 further file system abstractions
102 FileUtils.rm_rf(File.join(self.git_dir, file))
103 end
18ec70e9 »
2009-10-27 massive whitespace removal
104
4e694b9a »
2009-07-23 further file system abstractions
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
18ec70e9 »
2009-10-27 massive whitespace removal
113
4e694b9a »
2009-07-23 further file system abstractions
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
18ec70e9 »
2009-10-27 massive whitespace removal
121
4e694b9a »
2009-07-23 further file system abstractions
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
18ec70e9 »
2009-10-27 massive whitespace removal
139
4e694b9a »
2009-07-23 further file system abstractions
140 def create_tempfile(seed, unlink = false)
141 path = Tempfile.new(seed).path
142 File.unlink(path) if unlink
143 return path
144 end
18ec70e9 »
2009-10-27 massive whitespace removal
145
4fe0ec01 »
2009-10-27 fix tags
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
18ec70e9 »
2009-10-27 massive whitespace removal
158
4e694b9a »
2009-07-23 further file system abstractions
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
18ec70e9 »
2009-10-27 massive whitespace removal
165
4e694b9a »
2009-07-23 further file system abstractions
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
afe9c149 »
2009-04-20 abstract all file system calls into git class
170 end
18ec70e9 »
2009-10-27 massive whitespace removal
171
4e694b9a »
2009-07-23 further file system abstractions
172 def apply_patch(head_sha, patch)
173 git_index = create_tempfile('index', true)
18ec70e9 »
2009-10-27 massive whitespace removal
174
4e694b9a »
2009-07-23 further file system abstractions
175 git_patch = create_tempfile('patch')
176 File.open(git_patch, 'w+') { |f| f.print patch }
18ec70e9 »
2009-10-27 massive whitespace removal
177
4e694b9a »
2009-07-23 further file system abstractions
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
18ec70e9 »
2009-10-27 massive whitespace removal
185
4e694b9a »
2009-07-23 further file system abstractions
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
18ec70e9 »
2009-10-27 massive whitespace removal
207
208
209
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
210 # Run the given git command with the specified arguments and return
34a87f9a »
2007-10-13 implement Blob.data and Blob.size
211 # the result as a String
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
212 # +cmd+ is the command
917522c4 »
2007-10-13 more code comments throughout
213 # +options+ is a hash of Ruby style options
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
214 # +args+ is the list of arguments (to be joined by spaces)
215 #
216 # Examples
917522c4 »
2007-10-13 more code comments throughout
217 # git.rev_list({:max_count => 10, :header => true}, "master")
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
218 #
219 # Returns String
74fd6651 »
2007-10-13 add Blob
220 def method_missing(cmd, options = {}, *args)
823a9d9b »
2008-07-31 cleared out errors by adding in Grit::Git#run method
221 run('', cmd, '', options, args)
222 end
223
e976f760 »
2009-05-13 refactor more methods into git-ruby
224 # Bypass any pure Ruby implementations and go straight to the native Git command
225 #
226 # Returns String
227 def native(cmd, options = {}, *args)
228 method_missing(cmd, options, *args)
229 end
230
823a9d9b »
2008-07-31 cleared out errors by adding in Grit::Git#run method
231 def run(prefix, cmd, postfix, options, args)
1c002dd4 »
2008-12-11 added some blame and merge stuff
232 timeout = options.delete(:timeout) rescue nil
30e367ce »
2008-03-30 timeout code and tests
233 timeout = true if timeout.nil?
234
3b193020 »
2007-10-13 big refactor to do lazy loading
235 opt_args = transform_options(options)
18ec70e9 »
2009-10-27 massive whitespace removal
236
d5cde35b »
2009-07-23 windows support
237 if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
238 ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|') ? a : "\"#{e(a)}\"" }
2613204e »
2009-10-27 back out work-tree change, it was breaking github
239 call = "#{prefix}#{Git.git_binary} --git-dir=\"#{self.git_dir}\" #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
d5cde35b »
2009-07-23 windows support
240 else
241 ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|') ? a : "'#{e(a)}'" }
2613204e »
2009-10-27 back out work-tree change, it was breaking github
242 call = "#{prefix}#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
d5cde35b »
2009-07-23 windows support
243 end
18ec70e9 »
2009-10-27 massive whitespace removal
244
3dabb6af »
2008-06-27 allow sending debug messages to a user defined logger if provided; te…
245 Grit.log(call) if Grit.debug
06bae5ad »
2008-07-07 capture stderr and log it if debug is true when running commands
246 response, err = timeout ? sh(call) : wild_sh(call)
3dabb6af »
2008-06-27 allow sending debug messages to a user defined logger if provided; te…
247 Grit.log(response) if Grit.debug
06bae5ad »
2008-07-07 capture stderr and log it if debug is true when running commands
248 Grit.log(err) if Grit.debug
b6e1b765 »
2007-10-19 implement Repo.init_bare
249 response
3b193020 »
2007-10-13 big refactor to do lazy loading
250 end
5a094312 »
2008-03-30 add timeout protection to grit
251
252 def sh(command)
5b4583d6 »
2008-10-23 Use Open3 instead of Open4
253 ret, err = '', ''
254 Open3.popen3(command) do |_, stdout, stderr|
255 Timeout.timeout(self.class.git_timeout) do
256 while tmp = stdout.read(1024)
257 ret += tmp
1ab3ab76 »
2009-01-30 Make the number of bytes to be read from git's stdout configurable.
258 if (@bytes_read += tmp.size) > self.class.git_max_size
5b4583d6 »
2008-10-23 Use Open3 instead of Open4
259 bytes = @bytes_read
260 @bytes_read = 0
261 raise GitTimeout.new(command, bytes)
262 end
263 end
264 end
30e367ce »
2008-03-30 timeout code and tests
265
5b4583d6 »
2008-10-23 Use Open3 instead of Open4
266 while tmp = stderr.read(1024)
267 err += tmp
4d6b69cc »
2008-05-24 Fixed to close opened file description.
268 end
30e367ce »
2008-03-30 timeout code and tests
269 end
06bae5ad »
2008-07-07 capture stderr and log it if debug is true when running commands
270 [ret, err]
6b42301f »
2008-10-22 just rescue the timeout errors, problem solved
271 rescue Timeout::Error, Grit::Git::GitTimeout
30e367ce »
2008-03-30 timeout code and tests
272 bytes = @bytes_read
273 @bytes_read = 0
6b42301f »
2008-10-22 just rescue the timeout errors, problem solved
274 raise GitTimeout.new(command, bytes)
30e367ce »
2008-03-30 timeout code and tests
275 end
276
277 def wild_sh(command)
5b4583d6 »
2008-10-23 Use Open3 instead of Open4
278 ret, err = '', ''
279 Open3.popen3(command) do |_, stdout, stderr|
280 while tmp = stdout.read(1024)
281 ret += tmp
282 end
283
284 while tmp = stderr.read(1024)
285 err += tmp
286 end
495678f7 »
2008-09-04 Remove Process.kill and trap(CHLD), users can handle their own proces…
287 end
06bae5ad »
2008-07-07 capture stderr and log it if debug is true when running commands
288 [ret, err]
5a094312 »
2008-03-30 add timeout protection to grit
289 end
30e367ce »
2008-03-30 timeout code and tests
290
917522c4 »
2007-10-13 more code comments throughout
291 # Transform Ruby style options into git command line options
292 # +options+ is a hash of Ruby style options
293 #
294 # Returns String[]
295 # e.g. ["--max-count=10", "--header"]
3b193020 »
2007-10-13 big refactor to do lazy loading
296 def transform_options(options)
297 args = []
298 options.keys.each do |opt|
8c7f4e1d »
2007-10-25 dynamically rewrite ruby style git options
299 if opt.to_s.size == 1
300 if options[opt] == true
301 args << "-#{opt}"
82cac1a8 »
2009-07-18 allow setting of options to false to override true defaults
302 elsif options[opt] == false
303 # ignore
8c7f4e1d »
2007-10-25 dynamically rewrite ruby style git options
304 else
305 val = options.delete(opt)
ed763978 »
2009-02-13 do some mild shell escaping when running commands
306 args << "-#{opt.to_s} '#{e(val)}'"
8c7f4e1d »
2007-10-25 dynamically rewrite ruby style git options
307 end
308 else
3b193020 »
2007-10-13 big refactor to do lazy loading
309 if options[opt] == true
8c7f4e1d »
2007-10-25 dynamically rewrite ruby style git options
310 args << "--#{opt.to_s.gsub(/_/, '-')}"
82cac1a8 »
2009-07-18 allow setting of options to false to override true defaults
311 elsif options[opt] == false
312 # ignore
3b193020 »
2007-10-13 big refactor to do lazy loading
313 else
314 val = options.delete(opt)
ed763978 »
2009-02-13 do some mild shell escaping when running commands
315 args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'"
3b193020 »
2007-10-13 big refactor to do lazy loading
316 end
317 end
318 end
319 args
d01a4cfa »
2007-10-10 convert to Grit module, refactor to be more OO
320 end
321 end # Git
18ec70e9 »
2009-10-27 massive whitespace removal
322
5a094312 »
2008-03-30 add timeout protection to grit
323 end # Grit
Something went wrong with that request. Please try again.