Class: Grit::Git

Inherits:
Object
  • Object
show all
Includes:
GitRuby
Defined in:
lib/grit/git.rb

Defined Under Namespace

Classes: GitTimeout

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes included from GitRuby

#git_file_index, #ruby_git_repo

Class Method Summary collapse

Instance Method Summary collapse

Methods included from GitRuby

#blame_tree, #cat_file, #cat_ref, #diff, #file_index, #file_size, #file_type, #init, #ls_tree, read_bytes_until, #refs, #rev_list, #rev_parse, #ruby_git, #tags

Constructor Details

#initialize(git_dir) ⇒ Git

Returns a new instance of Git.



57
58
59
60
61
# File 'lib/grit/git.rb', line 57

def initialize(git_dir)
  self.git_dir    = git_dir
  self.work_tree  = git_dir.gsub(/\/\.git$/,'')
  self.bytes_read = 0
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(cmd, options = {}, *args, &block) ⇒ Object

Run the given git command with the specified arguments and return the result as a String cmd is the command options is a hash of Ruby style options args is the list of arguments (to be joined by spaces)

Examples git.rev_list(=> 10, :header => true, "master")

Returns String



220
221
222
# File 'lib/grit/git.rb', line 220

def method_missing(cmd, options = {}, *args, &block)
  run('', cmd, '', options, args, &block)
end

Class Attribute Details

.git_binaryObject

Returns the value of attribute git_binary.



37
38
39
# File 'lib/grit/git.rb', line 37

def git_binary
  @git_binary
end

.git_max_sizeObject

Returns the value of attribute git_max_size.



37
38
39
# File 'lib/grit/git.rb', line 37

def git_max_size
  @git_max_size
end

.git_timeoutObject

Returns the value of attribute git_timeout.



37
38
39
# File 'lib/grit/git.rb', line 37

def git_timeout
  @git_timeout
end

Instance Attribute Details

#bytes_readObject

Returns the value of attribute bytes_read.



55
56
57
# File 'lib/grit/git.rb', line 55

def bytes_read
  @bytes_read
end

#git_dirObject

Returns the value of attribute git_dir.



55
56
57
# File 'lib/grit/git.rb', line 55

def git_dir
  @git_dir
end

#work_treeObject

Returns the value of attribute work_tree.



55
56
57
# File 'lib/grit/git.rb', line 55

def work_tree
  @work_tree
end

Class Method Details

.with_timeout(timeout = 10.seconds) ⇒ Object



48
49
50
51
52
53
# File 'lib/grit/git.rb', line 48

def self.with_timeout(timeout = 10.seconds)
  old_timeout = Grit::Git.git_timeout
  Grit::Git.git_timeout = timeout
  yield
  Grit::Git.git_timeout = old_timeout
end

Instance Method Details

#apply_patch(head_sha, patch) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/grit/git.rb', line 172

def apply_patch(head_sha, patch)
  git_index = create_tempfile('index', true)

  git_patch = create_tempfile('patch')
  File.open(git_patch, 'w+') { |f| f.print patch }

  raw_git("git read-tree #{head_sha} 2>/dev/null", git_index)
  (op, exit) = raw_git("git apply --cached < #{git_patch}", git_index)
  if exit == 0
    return raw_git("git write-tree", git_index).first.chomp
  end
  false
end

#check_applies(head_sha, applies_sha) ⇒ Object



159
160
161
162
163
164
# File 'lib/grit/git.rb', line 159

def check_applies(head_sha, applies_sha)
  git_index = create_tempfile('index', true)
  (o1, exit1) = raw_git("git read-tree #{head_sha} 2>/dev/null", git_index)
  (o2, exit2) = raw_git("git diff #{applies_sha}^ #{applies_sha} | git apply --check --cached >/dev/null 2>/dev/null", git_index)
  return (exit1 + exit2)
end

#commit_from_sha(id) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/grit/git.rb', line 146

def commit_from_sha(id)
  git_ruby_repo = GitRuby::Repository.new(self.git_dir)
  object = git_ruby_repo.get_object_by_sha1(id)

  if object.type == :commit
    id
  elsif object.type == :tag
    object.object
  else
    ''
  end
end

#create_tempfile(seed, unlink = false) ⇒ Object



140
141
142
143
144
# File 'lib/grit/git.rb', line 140

def create_tempfile(seed, unlink = false)
  path = Tempfile.new(seed).path
  File.unlink(path) if unlink
  return path
end

#exist?Boolean

Returns:

  • (Boolean)


18
19
20
# File 'lib/grit/git.rb', line 18

def exist?
  File.exist?(self.git_dir)
end

#fs_chmod(mode, file = '/') ⇒ Object

Chmod the the file or dir and everything beneath file is the relative path from the Git dir

Returns nothing



126
127
128
# File 'lib/grit/git.rb', line 126

def fs_chmod(mode, file = '/')
  FileUtils.chmod_R(mode, File.join(self.git_dir, file))
end

#fs_delete(file) ⇒ Object

Delete a normal file from the filesystem file is the relative path from the Git dir

Returns nothing



101
102
103
# File 'lib/grit/git.rb', line 101

def fs_delete(file)
  FileUtils.rm_rf(File.join(self.git_dir, file))
end

#fs_exist?(file) ⇒ Boolean

Check if a normal file exists on the filesystem file is the relative path from the Git dir

Returns Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/grit/git.rb', line 72

def fs_exist?(file)
  File.exist?(File.join(self.git_dir, file))
end

#fs_mkdir(dir) ⇒ Object

Make a directory dir is the relative path to the directory to create

Returns nothing



118
119
120
# File 'lib/grit/git.rb', line 118

def fs_mkdir(dir)
  FileUtils.mkdir_p(File.join(self.git_dir, dir))
end

#fs_move(from, to) ⇒ Object

Move a normal file from is the relative path to the current file to is the relative path to the destination file

Returns nothing



110
111
112
# File 'lib/grit/git.rb', line 110

def fs_move(from, to)
  FileUtils.mv(File.join(self.git_dir, from), File.join(self.git_dir, to))
end

#fs_read(file) ⇒ Object

Read a normal file from the filesystem. file is the relative path from the Git dir

Returns the String contents of the file



80
81
82
# File 'lib/grit/git.rb', line 80

def fs_read(file)
  File.read(File.join(self.git_dir, file))
end

#fs_write(file, contents) ⇒ Object

Write a normal file to the filesystem. file is the relative path from the Git dir contents is the String content to be written

Returns nothing



89
90
91
92
93
94
95
# File 'lib/grit/git.rb', line 89

def fs_write(file, contents)
  path = File.join(self.git_dir, file)
  FileUtils.mkdir_p(File.dirname(path))
  File.open(path, 'w') do |f|
    f.write(contents)
  end
end

#get_patch(applies_sha) ⇒ Object



166
167
168
169
170
# File 'lib/grit/git.rb', line 166

def get_patch(applies_sha)
  git_index = create_tempfile('index', true)
  (patch, exit2) = raw_git("git diff #{applies_sha}^ #{applies_sha}", git_index)
  patch
end

#list_remotesObject



130
131
132
133
134
135
136
137
138
# File 'lib/grit/git.rb', line 130

def list_remotes
  remotes = []
  Dir.chdir(File.join(self.git_dir, 'refs/remotes')) do
    remotes = Dir.glob('*')
  end
  remotes
rescue
  []
end

#native(cmd, options = {}, *args, &block) ⇒ Object

Bypass any pure Ruby implementations and go straight to the native Git command

Returns String



227
228
229
# File 'lib/grit/git.rb', line 227

def native(cmd, options = {}, *args, &block)
  method_missing(cmd, options, *args, &block)
end

#object_exists?(object_id) ⇒ Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/grit/git.rb', line 26

def object_exists?(object_id)
  ruby_git.object_exists?(object_id)
end

#put_raw_object(content, type) ⇒ Object



22
23
24
# File 'lib/grit/git.rb', line 22

def put_raw_object(content, type)
  ruby_git.put_raw_object(content, type)
end

#raw_git(command, index) ⇒ Object



199
200
201
202
203
204
205
# File 'lib/grit/git.rb', line 199

def raw_git(command, index)
  output = nil
  Dir.chdir(self.git_dir) do
    output = raw_git_call(command, index)
  end
  output
end

#raw_git_call(command, index) ⇒ Object

RAW CALLS WITH ENV SETTINGS



187
188
189
190
191
192
193
194
195
196
197
# File 'lib/grit/git.rb', line 187

def raw_git_call(command, index)
  tmp = ENV['GIT_INDEX_FILE']
  ENV['GIT_INDEX_FILE'] = index
  out = `#{command}`
  after = ENV['GIT_INDEX_FILE'] # someone fucking with us ??
  ENV['GIT_INDEX_FILE'] = tmp
  if after != index
    raise 'environment was changed for the git call'
  end
  [out, $?.exitstatus]
end

#run(prefix, cmd, postfix, options, args, &block) ⇒ Object



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/grit/git.rb', line 231

def run(prefix, cmd, postfix, options, args, &block)
  timeout  = options.delete(:timeout) rescue nil
  timeout  = true if timeout.nil?

  base     = options.delete(:base) rescue nil
  base     = true if base.nil?

  opt_args = transform_options(options)

  if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
    ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|' || Grit.no_quote) ? a : "\"#{e(a)}\"" }
    gitdir = base ? "--git-dir=\"#{self.git_dir}\"" : ""
    call = "#{prefix}#{Git.git_binary} #{gitdir} #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
  else
    ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|' || Grit.no_quote) ? a : "'#{e(a)}'" }
    gitdir = base ? "--git-dir='#{self.git_dir}'" : ""
    call = "#{prefix}#{Git.git_binary} #{gitdir} #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
  end
  Grit.log(call) if Grit.debug
  response, err = timeout ? sh(call, &block) : wild_sh(call, &block)
  Grit.log(response) if Grit.debug
  Grit.log(err) if Grit.debug
  response
end

#select_existing_objects(object_ids) ⇒ Object



30
31
32
33
34
# File 'lib/grit/git.rb', line 30

def select_existing_objects(object_ids)
  object_ids.select do |object_id|
    object_exists?(object_id)
  end
end

#sh(command, &block) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/grit/git.rb', line 256

def sh(command, &block)
  ret, err = '', ''
  max = self.class.git_max_size
  Open3.popen3(command) do |stdin, stdout, stderr|
    block.call(stdin) if block
    Timeout.timeout(self.class.git_timeout) do
      while tmp = stdout.read(8192)
        ret << tmp
        raise GitTimeout.new(command, ret.size) if ret.size > max
      end
    end

    while tmp = stderr.read(8192)
      err << tmp
    end
  end
  [ret, err]
rescue Timeout::Error, Grit::Git::GitTimeout
  raise GitTimeout.new(command, ret.size)
end

#shell_escape(str) ⇒ Object Also known as: e



63
64
65
# File 'lib/grit/git.rb', line 63

def shell_escape(str)
  str.to_s.gsub("'", "\\\\'").gsub(";", '\\;')
end

#transform_options(options) ⇒ Object

Transform Ruby style options into git command line options options is a hash of Ruby style options

Returns String e.g. ["--max-count=10", "--header"]



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/grit/git.rb', line 297

def transform_options(options)
  args = []
  options.keys.each do |opt|
    if opt.to_s.size == 1
      if options[opt] == true
        args << "-#{opt}"
      elsif options[opt] == false
        # ignore
      else
        val = options.delete(opt)
        args << "-#{opt.to_s} '#{e(val)}'"
      end
    else
      if options[opt] == true
        args << "--#{opt.to_s.gsub(/_/, '-')}"
      elsif options[opt] == false
        # ignore
      else
        val = options.delete(opt)
        args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'"
      end
    end
  end
  args
end

#wild_sh(command, &block) ⇒ Object



277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/grit/git.rb', line 277

def wild_sh(command, &block)
  ret, err = '', ''
  Open3.popen3(command) do |stdin, stdout, stderr|
    block.call(stdin) if block
    while tmp = stdout.read(8192)
      ret << tmp
    end

    while tmp = stderr.read(8192)
      err << tmp
    end
  end
  [ret, err]
end