ruby-git-lacravate 0.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/lib/git/lib.rb ADDED
@@ -0,0 +1,765 @@
1
+ require 'tempfile'
2
+
3
+ module Git
4
+
5
+ class GitExecuteError < StandardError
6
+ end
7
+
8
+ class Lib
9
+
10
+ def initialize(base = nil, logger = nil)
11
+ @git_dir = nil
12
+ @git_index_file = nil
13
+ @git_work_dir = nil
14
+ @path = nil
15
+
16
+ if base.is_a?(Git::Base)
17
+ @git_dir = base.repo.path
18
+ @git_index_file = base.index.path if base.index
19
+ @git_work_dir = base.dir.path if base.dir
20
+ elsif base.is_a?(Hash)
21
+ @git_dir = base[:repository]
22
+ @git_index_file = base[:index]
23
+ @git_work_dir = base[:working_directory]
24
+ end
25
+ @logger = logger
26
+ end
27
+
28
+ def init
29
+ command('init')
30
+ end
31
+
32
+ # tries to clone the given repo
33
+ #
34
+ # returns {:repository} (if bare)
35
+ # {:working_directory} otherwise
36
+ #
37
+ # accepts options:
38
+ # :remote:: name of remote (rather than 'origin')
39
+ # :bare:: no working directory
40
+ # :depth:: the number of commits back to pull
41
+ #
42
+ # TODO - make this work with SSH password or auth_key
43
+ #
44
+ def clone(repository, name, opts = {})
45
+ @path = opts[:path] || '.'
46
+ clone_dir = opts[:path] ? File.join(@path, name) : name
47
+
48
+ arr_opts = []
49
+ arr_opts << "--bare" if opts[:bare]
50
+ arr_opts << "-o" << opts[:remote] if opts[:remote]
51
+ arr_opts << "--depth" << opts[:depth].to_i if opts[:depth] && opts[:depth].to_i > 0
52
+
53
+ # -- allow processing of switches added as array elements
54
+ Array(opts[:switches]).each { |switch| arr_opts << switch }
55
+ #
56
+
57
+ arr_opts << '--'
58
+ arr_opts << repository
59
+ arr_opts << clone_dir
60
+
61
+ command('clone', arr_opts)
62
+
63
+ opts[:bare] ? {:repository => clone_dir} : {:working_directory => clone_dir}
64
+ end
65
+
66
+
67
+ ## READ COMMANDS ##
68
+
69
+
70
+ def log_commits(opts = {})
71
+ arr_opts = ['--pretty=oneline']
72
+ arr_opts << "-#{opts[:count]}" if opts[:count]
73
+ arr_opts << "--since=#{opts[:since]}" if opts[:since].is_a? String
74
+ arr_opts << "--until=#{opts[:until]}" if opts[:until].is_a? String
75
+ arr_opts << "--grep=#{opts[:grep]}" if opts[:grep].is_a? String
76
+ arr_opts << "--author=#{opts[:author]}" if opts[:author].is_a? String
77
+ arr_opts << "#{opts[:between][0].to_s}..#{opts[:between][1].to_s}" if (opts[:between] && opts[:between].size == 2)
78
+ arr_opts << opts[:object] if opts[:object].is_a? String
79
+
80
+ # -- always add '--' at the end of command line to allow git to
81
+ # understand commands like 'git log `branch`'
82
+ arr_opts << '--'
83
+ arr_opts << opts[:path_limiter] if opts[:path_limiter].is_a? String
84
+ #
85
+
86
+ command_lines('log', arr_opts, true).map { |l| l.split.first }
87
+ end
88
+
89
+ def full_log_commits(opts = {})
90
+ arr_opts = ['--pretty=raw']
91
+ arr_opts << "-#{opts[:count]}" if opts[:count]
92
+ arr_opts << "--skip=#{opts[:skip]}" if opts[:skip]
93
+ arr_opts << "--since=#{opts[:since]}" if opts[:since].is_a? String
94
+ arr_opts << "--until=#{opts[:until]}" if opts[:until].is_a? String
95
+ arr_opts << "--grep=#{opts[:grep]}" if opts[:grep].is_a? String
96
+ arr_opts << "--author=#{opts[:author]}" if opts[:author].is_a? String
97
+ arr_opts << "#{opts[:between][0].to_s}..#{opts[:between][1].to_s}" if (opts[:between] && opts[:between].size == 2)
98
+ arr_opts << opts[:object] if opts[:object].is_a? String
99
+
100
+ #
101
+ arr_opts << '--'
102
+ arr_opts << opts[:path_limiter] if opts[:path_limiter].is_a? String
103
+ #
104
+
105
+ full_log = command_lines('log', arr_opts, true)
106
+ process_commit_data(full_log)
107
+ end
108
+
109
+ def revparse(string)
110
+ return string if string =~ /[A-Fa-f0-9]{40}/ # passing in a sha - just no-op it
111
+ rev = ['head', 'remotes', 'tags'].map do |d|
112
+ File.join(@git_dir, 'refs', d, string)
113
+ end.find do |path|
114
+ File.file?(path)
115
+ end
116
+ return File.read(rev).chomp if rev
117
+ command('rev-parse', string)
118
+ end
119
+
120
+ def namerev(string)
121
+ command('name-rev', string).split[1]
122
+ end
123
+
124
+ def object_type(sha)
125
+ command('cat-file', ['-t', sha])
126
+ end
127
+
128
+ def object_size(sha)
129
+ command('cat-file', ['-s', sha]).to_i
130
+ end
131
+
132
+ # returns useful array of raw commit object data
133
+ def commit_data(sha)
134
+ sha = sha.to_s
135
+ cdata = command_lines('cat-file', ['commit', sha])
136
+ process_commit_data(cdata, sha, 0)
137
+ end
138
+
139
+ def process_commit_data(data, sha = nil, indent = 4)
140
+ in_message = false
141
+
142
+ if sha
143
+ hsh = {'sha' => sha, 'message' => '', 'parent' => []}
144
+ else
145
+ hsh_array = []
146
+ end
147
+
148
+ data.each do |line|
149
+ line = line.chomp
150
+ if line == ''
151
+ in_message = !in_message
152
+ elsif in_message
153
+ hsh['message'] << line[indent..-1] << "\n"
154
+ else
155
+ data = line.split
156
+ key = data.shift
157
+ value = data.join(' ')
158
+ if key == 'commit'
159
+ sha = value
160
+ hsh_array << hsh if hsh
161
+ hsh = {'sha' => sha, 'message' => '', 'parent' => []}
162
+ end
163
+ if key == 'parent'
164
+ hsh[key] << value
165
+ else
166
+ hsh[key] = value
167
+ end
168
+ end
169
+ end
170
+
171
+ if hsh_array
172
+ hsh_array << hsh if hsh
173
+ hsh_array
174
+ else
175
+ hsh
176
+ end
177
+ end
178
+
179
+ def object_contents(sha, &block)
180
+ command('cat-file', ['-p', sha], &block)
181
+ end
182
+
183
+ def ls_tree(sha, options={})
184
+ # -- implement recursive ls-tree
185
+ command_args = []
186
+ command_args << '-r' if options[:recursive]
187
+ command_args << sha
188
+ #
189
+ data = {'blob' => {}, 'tree' => {}}
190
+
191
+ #
192
+ command_lines('ls-tree', command_args).each do |line|
193
+ #
194
+ (info, filenm) = line.split("\t")
195
+ (mode, type, sha) = info.split
196
+ data[type][filenm] = {:mode => mode, :sha => sha}
197
+ end
198
+
199
+ data
200
+ end
201
+
202
+ def mv(file1, file2)
203
+ command_lines('mv', ['--', file1, file2])
204
+ end
205
+
206
+ def full_tree(sha)
207
+ command_lines('ls-tree', ['-r', sha])
208
+ end
209
+
210
+ def tree_depth(sha)
211
+ full_tree(sha).size
212
+ end
213
+
214
+ def change_head_branch(branch_name)
215
+ command('symbolic-ref', ['HEAD', "refs/heads/#{branch_name}"])
216
+ end
217
+
218
+ def branches_all
219
+ arr = []
220
+ command_lines('branch', '-a').each do |b|
221
+ current = (b[0, 2] == '* ')
222
+ arr << [b.gsub('* ', '').strip, current]
223
+ end
224
+ arr
225
+ end
226
+
227
+ def list_files(ref_dir)
228
+ dir = File.join(@git_dir, 'refs', ref_dir)
229
+ files = []
230
+ Dir.chdir(dir) { files = Dir.glob('**/*').select { |f| File.file?(f) } } rescue nil
231
+ files
232
+ end
233
+
234
+ def branch_current
235
+ branches_all.select { |b| b[1] }.first[0] rescue nil
236
+ end
237
+
238
+
239
+ # returns hash
240
+ # [tree-ish] = [[line_no, match], [line_no, match2]]
241
+ # [tree-ish] = [[line_no, match], [line_no, match2]]
242
+ def grep(string, opts = {})
243
+ opts[:object] ||= 'HEAD'
244
+
245
+ grep_opts = ['-n']
246
+ grep_opts << '-i' if opts[:ignore_case]
247
+ grep_opts << '-v' if opts[:invert_match]
248
+ grep_opts << '-e'
249
+ grep_opts << string
250
+ grep_opts << opts[:object] if opts[:object].is_a?(String)
251
+ grep_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
252
+
253
+ hsh = {}
254
+ command_lines('grep', grep_opts).each do |line|
255
+ if m = /(.*)\:(\d+)\:(.*)/.match(line)
256
+ hsh[m[1]] ||= []
257
+ hsh[m[1]] << [m[2].to_i, m[3]]
258
+ end
259
+ end
260
+ hsh
261
+ end
262
+
263
+ def diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})
264
+ diff_opts = ['-p']
265
+ diff_opts << obj1
266
+ diff_opts << obj2 if obj2.is_a?(String)
267
+ diff_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
268
+
269
+ command('diff', diff_opts)
270
+ end
271
+
272
+ def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
273
+ diff_opts = ['--numstat']
274
+ diff_opts << obj1
275
+ diff_opts << obj2 if obj2.is_a?(String)
276
+ diff_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
277
+
278
+ hsh = {:total => {:insertions => 0, :deletions => 0, :lines => 0, :files => 0}, :files => {}}
279
+
280
+ command_lines('diff', diff_opts).each do |file|
281
+ (insertions, deletions, filename) = file.split("\t")
282
+ hsh[:total][:insertions] += insertions.to_i
283
+ hsh[:total][:deletions] += deletions.to_i
284
+ hsh[:total][:lines] = (hsh[:total][:deletions] + hsh[:total][:insertions])
285
+ hsh[:total][:files] += 1
286
+ hsh[:files][filename] = {:insertions => insertions.to_i, :deletions => deletions.to_i}
287
+ end
288
+
289
+ hsh
290
+ end
291
+
292
+ # compares the index and the working directory
293
+ def diff_files
294
+ hsh = {}
295
+ command_lines('diff-files').each do |line|
296
+ (info, file) = line.split("\t")
297
+ (mode_src, mode_dest, sha_src, sha_dest, type) = info.split
298
+ hsh[file] = {:path => file, :mode_file => mode_src.to_s[1, 7], :mode_index => mode_dest,
299
+ :sha_file => sha_src, :sha_index => sha_dest, :type => type}
300
+ end
301
+ hsh
302
+ end
303
+
304
+ # compares the index and the repository
305
+ def diff_index(treeish)
306
+ hsh = {}
307
+ command_lines('diff-index', treeish).each do |line|
308
+ (info, file) = line.split("\t")
309
+ (mode_src, mode_dest, sha_src, sha_dest, type) = info.split
310
+ type = 'A' if type == 'M' && sha_dest !~ /^0+$/
311
+ hsh[file] = {:path => file, :mode_repo => mode_src.to_s[1, 7], :mode_index => mode_dest,
312
+ :sha_repo => sha_src, :sha_index => sha_dest, :type => type}
313
+ end
314
+ hsh
315
+ end
316
+
317
+ def ls_files(location=nil)
318
+ hsh = {}
319
+ command_lines('ls-files', ['--stage', location]).each do |line|
320
+ (info, file) = line.split("\t")
321
+ (mode, sha, stage) = info.split
322
+ file = eval(file) if file =~ /^\".*\"$/ # This takes care of quoted strings returned from git
323
+ hsh[file] = {:path => file, :mode_index => mode, :sha_index => sha, :stage => stage}
324
+ end
325
+ hsh
326
+ end
327
+
328
+
329
+ def ignored_files
330
+ command_lines('ls-files', ['--others', '-i', '--exclude-standard'])
331
+ end
332
+
333
+
334
+ def config_remote(name)
335
+ hsh = {}
336
+ config_list.each do |key, value|
337
+ if /remote.#{name}/.match(key)
338
+ hsh[key.gsub("remote.#{name}.", '')] = value
339
+ end
340
+ end
341
+ hsh
342
+ end
343
+
344
+ def config_get(name)
345
+ do_get = lambda do
346
+ command('config', ['--get', name])
347
+ end
348
+
349
+ if @git_dir
350
+ Dir.chdir(@git_dir, &do_get)
351
+ else
352
+ build_list.call
353
+ end
354
+ end
355
+
356
+ def global_config_get(name)
357
+ command('config', ['--global', '--get', name], false)
358
+ end
359
+
360
+ def config_list
361
+ build_list = lambda do |path|
362
+ parse_config_list command_lines('config', ['--list'])
363
+ end
364
+
365
+ if @git_dir
366
+ Dir.chdir(@git_dir, &build_list)
367
+ else
368
+ build_list.call
369
+ end
370
+ end
371
+
372
+ def global_config_list
373
+ parse_config_list command_lines('config', ['--global', '--list'], false)
374
+ end
375
+
376
+ def parse_config_list(lines)
377
+ hsh = {}
378
+ lines.each do |line|
379
+ (key, *values) = line.split('=')
380
+ hsh[key] = values.join('=')
381
+ end
382
+ hsh
383
+ end
384
+
385
+ def parse_config(file)
386
+ hsh = {}
387
+ parse_config_list command_lines('config', ['--list', '--file', file], false)
388
+ #hsh = {}
389
+ #file = File.expand_path(file)
390
+ #if File.file?(file)
391
+ # current_section = nil
392
+ # File.readlines(file).each do |line|
393
+ # if m = /\[(\w+)\]/.match(line)
394
+ # current_section = m[1]
395
+ # elsif m = /\[(\w+?) "(.*?)"\]/.match(line)
396
+ # current_section = "#{m[1]}.#{m[2]}"
397
+ # elsif m = /(\w+?) = (.*)/.match(line)
398
+ # key = "#{current_section}.#{m[1]}"
399
+ # hsh[key] = m[2]
400
+ # end
401
+ # end
402
+ #end
403
+ #hsh
404
+ end
405
+
406
+ ## WRITE COMMANDS ##
407
+
408
+ def config_set(name, value)
409
+ command('config', [name, value])
410
+ end
411
+
412
+ def global_config_set(name, value)
413
+ command('config', ['--global', name, value], false)
414
+ end
415
+
416
+ def add(path = '.')
417
+ arr_opts = ['--']
418
+ if path.is_a?(Array)
419
+ arr_opts += path
420
+ else
421
+ arr_opts << path
422
+ end
423
+ command('add', arr_opts)
424
+ end
425
+
426
+ def remove(path = '.', opts = {})
427
+ arr_opts = ['-f'] # overrides the up-to-date check by default
428
+ arr_opts << ['-r'] if opts[:recursive]
429
+ arr_opts << '--'
430
+ if path.is_a?(Array)
431
+ arr_opts += path
432
+ else
433
+ arr_opts << path
434
+ end
435
+
436
+ command('rm', arr_opts)
437
+ end
438
+
439
+ #
440
+ def commit(message, opts = {})
441
+ arr_opts = []
442
+ arr_opts << '-m' << message unless !!opts[:reuse_message]
443
+ arr_opts << '-C' << opts[:reuse_message] if !!opts[:reuse_message]
444
+ arr_opts << '-a' if opts[:add_all]
445
+ arr_opts << '--allow-empty' if opts[:allow_empty]
446
+ arr_opts << "--author" << opts[:author] if opts[:author]
447
+ command('commit', arr_opts)
448
+ end
449
+ #
450
+
451
+ def reset(commit, opts = {})
452
+ arr_opts = []
453
+ arr_opts << '--hard' if opts[:hard]
454
+ arr_opts << commit if commit
455
+ command('reset', arr_opts)
456
+ end
457
+
458
+ def apply(patch_file)
459
+ arr_opts = []
460
+ arr_opts << '--' << patch_file if patch_file
461
+ command('apply', arr_opts)
462
+ end
463
+
464
+ def apply_mail(patch_file)
465
+ arr_opts = []
466
+ arr_opts << '--' << patch_file if patch_file
467
+ command('am', arr_opts)
468
+ end
469
+
470
+ def stashes_all
471
+ arr = []
472
+ filename = File.join(@git_dir, 'logs/refs/stash')
473
+ if File.exist?(filename)
474
+ File.open(filename).each_with_index { |line, i|
475
+ m = line.match(/:(.*)$/)
476
+ arr << [i, m[1].strip]
477
+ }
478
+ end
479
+ arr
480
+ end
481
+
482
+ def stash_save(message)
483
+ output = command('stash save', ['--', message])
484
+ output =~ /HEAD is now at/
485
+ end
486
+
487
+ def stash_apply(id = nil)
488
+ if id
489
+ command('stash apply', [id])
490
+ else
491
+ command('stash apply')
492
+ end
493
+ end
494
+
495
+ def stash_clear
496
+ command('stash clear')
497
+ end
498
+
499
+ def stash_list
500
+ command('stash list')
501
+ end
502
+
503
+ # -- implement --t switch on git branch command
504
+ def branch_new(branch, track=nil)
505
+ options = [branch]
506
+ options << '--t' << track if track
507
+ command('branch', options)
508
+ end
509
+ #
510
+
511
+ def branch_delete(branch)
512
+ command('branch', ['-D', branch])
513
+ end
514
+
515
+ def checkout(branch, opts = {})
516
+ arr_opts = []
517
+ arr_opts << '-f' if opts[:force]
518
+
519
+ # -- implementation of a working -b switch
520
+ # for git checkout command
521
+ arr_opts << '-b' if opts[:new_branch]
522
+ # -- this push is legacy
523
+ # i don't understand it and congratulate
524
+ # myself not to try to and just leave it here
525
+ arr_opts << opts[:new_branch] if opts[:new_branch] && !opts[:new_branch].is_a?(TrueClass)
526
+ #
527
+
528
+ arr_opts << branch if branch
529
+
530
+ # -- we can 'git checkout `sha`' now
531
+ arr_opts << opts[:commit] if opts[:commit]
532
+ #
533
+
534
+ # -- checkout paths
535
+ arr_opts.push '--', *opts[:files] if opts[:files]
536
+ #
537
+
538
+ command('checkout', arr_opts)
539
+ end
540
+
541
+ def checkout_file(version, file)
542
+ arr_opts = []
543
+ arr_opts << version
544
+ arr_opts << file
545
+ command('checkout', arr_opts)
546
+ end
547
+
548
+ def merge(branch, message = nil)
549
+ arr_opts = []
550
+ arr_opts << '-m' << message if message
551
+ arr_opts += [branch]
552
+ command('merge', arr_opts)
553
+ end
554
+
555
+ def unmerged
556
+ unmerged = []
557
+ command_lines('diff', ["--cached"]).each do |line|
558
+ unmerged << $1 if line =~ /^\* Unmerged path (.*)/
559
+ end
560
+ unmerged
561
+ end
562
+
563
+ def conflicts # :yields: file, your, their
564
+ self.unmerged.each do |f|
565
+ your = Tempfile.new("YOUR-#{File.basename(f)}").path
566
+ command('show', ":2:#{f}", true, "> #{escape your}")
567
+
568
+ their = Tempfile.new("THEIR-#{File.basename(f)}").path
569
+ command('show', ":3:#{f}", true, "> #{escape their}")
570
+ yield(f, your, their)
571
+ end
572
+ end
573
+
574
+ def remote_add(name, url, opts = {})
575
+ arr_opts = ['add']
576
+ arr_opts << '-f' if opts[:with_fetch]
577
+ arr_opts << '--'
578
+ arr_opts << name
579
+ arr_opts << url
580
+
581
+ command('remote', arr_opts)
582
+ end
583
+
584
+ # this is documented as such, but seems broken for some reason
585
+ # i'll try to get around it some other way later
586
+ def remote_remove(name)
587
+ command('remote', ['rm', '--', name])
588
+ end
589
+
590
+ def remotes
591
+ command_lines('remote')
592
+ end
593
+
594
+ def tags
595
+ command_lines('tag')
596
+ end
597
+
598
+ def tag(tag)
599
+ command('tag', tag)
600
+ end
601
+
602
+
603
+ def fetch(remote)
604
+ command('fetch', remote)
605
+ end
606
+
607
+ def push(remote, branch = 'master', tags = false)
608
+ command('push', [remote, branch])
609
+ command('push', ['--tags', remote]) if tags
610
+ end
611
+
612
+ def tag_sha(tag_name)
613
+ head = File.join(@git_dir, 'refs', 'tags', tag_name)
614
+ return File.read(head).chomp if File.exists?(head)
615
+
616
+ command('show-ref', ['--tags', '-s', tag_name])
617
+ end
618
+
619
+ def repack
620
+ command('repack', ['-a', '-d'])
621
+ end
622
+
623
+ def gc
624
+ command('gc', ['--prune', '--aggressive', '--auto'])
625
+ end
626
+
627
+ # reads a tree into the current index file
628
+ def read_tree(treeish, opts = {})
629
+ arr_opts = []
630
+ arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
631
+ arr_opts += [treeish]
632
+ command('read-tree', arr_opts)
633
+ end
634
+
635
+ def write_tree
636
+ command('write-tree')
637
+ end
638
+
639
+ def commit_tree(tree, opts = {})
640
+ opts[:message] ||= "commit tree #{tree}"
641
+ t = Tempfile.new('commit-message')
642
+ t.write(opts[:message])
643
+ t.close
644
+
645
+ arr_opts = []
646
+ arr_opts << tree
647
+ arr_opts << '-p' << opts[:parent] if opts[:parent]
648
+ arr_opts += [opts[:parents]].map { |p| ['-p', p] }.flatten if opts[:parents]
649
+ command('commit-tree', arr_opts, true, "< #{escape t.path}")
650
+ end
651
+
652
+ def update_ref(branch, commit)
653
+ command('update-ref', [branch, commit])
654
+ end
655
+
656
+ def checkout_index(opts = {})
657
+ arr_opts = []
658
+ arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
659
+ arr_opts << "--force" if opts[:force]
660
+ arr_opts << "--all" if opts[:all]
661
+ arr_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
662
+
663
+ command('checkout-index', arr_opts)
664
+ end
665
+
666
+ # creates an archive file
667
+ #
668
+ # options
669
+ # :format (zip, tar)
670
+ # :prefix
671
+ # :remote
672
+ # :path
673
+ def archive(sha, file = nil, opts = {})
674
+ opts[:format] ||= 'zip'
675
+
676
+ if opts[:format] == 'tgz'
677
+ opts[:format] = 'tar'
678
+ opts[:add_gzip] = true
679
+ end
680
+
681
+ file ||= Tempfile.new('archive').path
682
+
683
+ arr_opts = []
684
+ arr_opts << "--format=#{opts[:format]}" if opts[:format]
685
+ arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
686
+ arr_opts << "--remote=#{opts[:remote]}" if opts[:remote]
687
+ arr_opts << sha
688
+ arr_opts << '--' << opts[:path] if opts[:path]
689
+ command('archive', arr_opts, true, (opts[:add_gzip] ? '| gzip' : '') + " > #{escape file}")
690
+ return file
691
+ end
692
+
693
+ # returns the current version of git, as an Array of Fixnums.
694
+ def current_command_version
695
+ output = command('version', [], false)
696
+ version = output[/\d+\.\d+(\.\d+)+/]
697
+ version.split('.').collect {|i| i.to_i}
698
+ end
699
+
700
+ def required_command_version
701
+ [1, 6, 0, 0]
702
+ end
703
+
704
+ def meets_required_version?
705
+ current_version = self.current_command_version
706
+ required_version = self.required_command_version
707
+
708
+ return current_version[0] >= required_version[0] &&
709
+ current_version[1] >= required_version[1] &&
710
+ (current_version[2] ? current_version[2] >= required_version[2] : true) &&
711
+ (current_version[3] ? current_version[3] >= required_version[3] : true)
712
+ end
713
+
714
+
715
+ private
716
+
717
+ def command_lines(cmd, opts = [], chdir = true, redirect = '')
718
+ command(cmd, opts, chdir).split("\n")
719
+ end
720
+
721
+ def command(cmd, opts = [], chdir = true, redirect = '', &block)
722
+ ENV['GIT_DIR'] = @git_dir
723
+ ENV['GIT_INDEX_FILE'] = @git_index_file
724
+ ENV['GIT_WORK_TREE'] = @git_work_dir
725
+ path = @git_work_dir || @git_dir || @path
726
+
727
+ opts = [opts].flatten.map {|s| escape(s) }.join(' ')
728
+ git_cmd = "git #{cmd} #{opts} #{redirect} 2>&1"
729
+
730
+ out = nil
731
+ if chdir && (Dir.getwd != path)
732
+ Dir.chdir(path) { out = run_command(git_cmd, &block) }
733
+ else
734
+ out = run_command(git_cmd, &block)
735
+ end
736
+
737
+ if @logger
738
+ @logger.info(git_cmd)
739
+ @logger.debug(out)
740
+ end
741
+
742
+ if $?.exitstatus > 0
743
+ if $?.exitstatus == 1 && out == ''
744
+ return ''
745
+ end
746
+ raise Git::GitExecuteError.new(git_cmd + ':' + out.to_s)
747
+ end
748
+ out
749
+ end
750
+
751
+ def run_command(git_cmd, &block)
752
+ if block_given?
753
+ IO.popen(git_cmd, &block)
754
+ else
755
+ `#{git_cmd}`.chomp
756
+ end
757
+ end
758
+
759
+ def escape(s)
760
+ escaped = s.to_s.gsub('\'', '\'\\\'\'')
761
+ %Q{"#{escaped}"}
762
+ end
763
+
764
+ end
765
+ end