Skip to content

Commit c9fe649

Browse files
author
Daniel Mendler
committed
very important!!! shell command escaping added
1 parent db1c2c9 commit c9fe649

File tree

1 file changed

+104
-61
lines changed

1 file changed

+104
-61
lines changed

lib/git/lib.rb

+104-61
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,14 @@ def clone(repository, name, opts = {})
4949

5050
arr_opts = []
5151
arr_opts << "--bare" if opts[:bare]
52-
arr_opts << "-o #{opts[:remote]}" if opts[:remote]
53-
arr_opts << "--depth #{opts[:depth].to_i}" if opts[:depth] && opts[:depth].to_i > 0
52+
if opts[:remote]
53+
arr_opts << "-o"
54+
arr_opts << opts[:remote]
55+
end
56+
if opts[:depth] && opts[:depth].to_i > 0
57+
arr_opts << "--depth"
58+
arr_opts << opts[:depth].to_i
59+
end
5460
arr_opts << repository
5561
arr_opts << clone_dir
5662

@@ -66,35 +72,41 @@ def clone(repository, name, opts = {})
6672
def log_commits(opts = {})
6773
arr_opts = ['--pretty=oneline']
6874
arr_opts << "-#{opts[:count]}" if opts[:count]
69-
arr_opts << "--since=\"#{opts[:since]}\"" if opts[:since].is_a? String
70-
arr_opts << "--until=\"#{opts[:until]}\"" if opts[:until].is_a? String
71-
arr_opts << "--grep=\"#{opts[:grep]}\"" if opts[:grep].is_a? String
72-
arr_opts << "--author=\"#{opts[:author]}\"" if opts[:author].is_a? String
75+
arr_opts << "--since=#{opts[:since]}" if opts[:since].is_a? String
76+
arr_opts << "--until=#{opts[:until]}" if opts[:until].is_a? String
77+
arr_opts << "--grep=#{opts[:grep]}" if opts[:grep].is_a? String
78+
arr_opts << "--author=#{opts[:author]}" if opts[:author].is_a? String
7379
arr_opts << "#{opts[:between][0].to_s}..#{opts[:between][1].to_s}" if (opts[:between] && opts[:between].size == 2)
7480
arr_opts << opts[:object] if opts[:object].is_a? String
75-
arr_opts << '-- ' + opts[:path_limiter] if opts[:path_limiter].is_a? String
76-
81+
if opts[:path_limiter].is_a? String
82+
arr_opts << '--'
83+
arr_opts << opts[:path_limiter]
84+
end
85+
7786
command_lines('log', arr_opts, true).map { |l| l.split.first }
7887
end
7988

8089
def full_log_commits(opts = {})
8190
arr_opts = ['--pretty=raw']
8291
arr_opts << "-#{opts[:count]}" if opts[:count]
83-
arr_opts << "--skip=\"#{opts[:skip]}\"" if opts[:skip]
84-
arr_opts << "--since=\"#{opts[:since]}\"" if opts[:since].is_a? String
85-
arr_opts << "--until=\"#{opts[:until]}\"" if opts[:until].is_a? String
86-
arr_opts << "--grep=\"#{opts[:grep]}\"" if opts[:grep].is_a? String
87-
arr_opts << "--author=\"#{opts[:author]}\"" if opts[:author].is_a? String
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
8897
arr_opts << "#{opts[:between][0].to_s}..#{opts[:between][1].to_s}" if (opts[:between] && opts[:between].size == 2)
8998
arr_opts << opts[:object] if opts[:object].is_a? String
90-
arr_opts << '-- ' + opts[:path_limiter] if opts[:path_limiter].is_a? String
99+
if opts[:path_limiter].is_a? String
100+
arr_opts << '--'
101+
arr_opts << opts[:path_limiter]
102+
end
91103

92104
full_log = command_lines('log', arr_opts, true)
93105
process_commit_data(full_log)
94106
end
95107

96108
def revparse(string)
97-
return string if string =~ /\w{40}/ # passing in a sha - just no-op it
109+
return string if string =~ /[A-Fa-f0-9]{40}/ # passing in a sha - just no-op it
98110
rev = ['head', 'remotes', 'tags'].map do |d|
99111
File.join(@git_dir, 'refs', d, string)
100112
end.find do |path|
@@ -170,7 +182,7 @@ def object_contents(sha, &block)
170182
def ls_tree(sha)
171183
data = {'blob' => {}, 'tree' => {}}
172184

173-
command_lines('ls-tree', sha.to_s).each do |line|
185+
command_lines('ls-tree', sha).each do |line|
174186
(info, filenm) = line.split("\t")
175187
(mode, type, sha) = info.split
176188
data[type][filenm] = {:mode => mode, :sha => sha}
@@ -184,7 +196,7 @@ def mv(file1, file2)
184196
end
185197

186198
def full_tree(sha)
187-
command_lines('ls-tree', ['-r', sha.to_s])
199+
command_lines('ls-tree', ['-r', sha])
188200
end
189201

190202
def tree_depth(sha)
@@ -225,9 +237,15 @@ def grep(string, opts = {})
225237
grep_opts = ['-n']
226238
grep_opts << '-i' if opts[:ignore_case]
227239
grep_opts << '-v' if opts[:invert_match]
228-
grep_opts << "-e '#{string}'"
240+
grep_opts << '-e'
241+
grep_opts << string
229242
grep_opts << opts[:object] if opts[:object].is_a?(String)
230-
grep_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
243+
244+
if opts[:path_limiter].is_a? String
245+
grep_opts << '--'
246+
grep_opts << opts[:path_limiter]
247+
end
248+
231249
hsh = {}
232250
command_lines('grep', grep_opts).each do |line|
233251
if m = /(.*)\:(\d+)\:(.*)/.match(line)
@@ -242,17 +260,25 @@ def diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})
242260
diff_opts = ['-p']
243261
diff_opts << obj1
244262
diff_opts << obj2 if obj2.is_a?(String)
245-
diff_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
246-
263+
264+
if opts[:path_limiter].is_a? String
265+
diff_opts << '--'
266+
diff_opts << opts[:path_limiter]
267+
end
268+
247269
command('diff', diff_opts)
248270
end
249271

250272
def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
251273
diff_opts = ['--numstat']
252274
diff_opts << obj1
253275
diff_opts << obj2 if obj2.is_a?(String)
254-
diff_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
255-
276+
277+
if opts[:path_limiter].is_a? String
278+
diff_opts << '--'
279+
diff_opts << opts[:path_limiter]
280+
end
281+
256282
hsh = {:total => {:insertions => 0, :deletions => 0, :lines => 0, :files => 0}, :files => {}}
257283

258284
command_lines('diff', diff_opts).each do |file|
@@ -351,48 +377,52 @@ def parse_config(file)
351377
## WRITE COMMANDS ##
352378

353379
def config_set(name, value)
354-
command('config', [name, "'#{value}'"])
380+
command('config', [name, value])
355381
end
356382

357383
def add(path = '.')
358-
path = path.join(' ') if path.is_a?(Array)
359384
command('add', path)
360385
end
361386

362387
def remove(path = '.', opts = {})
363-
path = path.join(' ') if path.is_a?(Array)
364-
365388
arr_opts = ['-f'] # overrides the up-to-date check by default
366389
arr_opts << ['-r'] if opts[:recursive]
367-
arr_opts << path
390+
if path.is_a?(Array)
391+
arr_opts += path
392+
else
393+
arr_opts << path
394+
end
368395

369396
command('rm', arr_opts)
370397
end
371398

372399
def commit(message, opts = {})
373-
arr_opts = ["-m '#{message}'"]
400+
arr_opts = ['-m', message]
374401
arr_opts << '-a' if opts[:add_all]
375402
arr_opts << '--allow-empty' if opts[:allow_empty]
376-
arr_opts << "--author '#{opts[:author]}'" if opts[:author]
403+
if opts[:author]
404+
arr_opts << "--author"
405+
arr_opts << opts[:author]
406+
end
377407
command('commit', arr_opts)
378408
end
379409

380410
def reset(commit, opts = {})
381411
arr_opts = []
382412
arr_opts << '--hard' if opts[:hard]
383-
arr_opts << commit.to_s if commit
413+
arr_opts << commit if commit
384414
command('reset', arr_opts)
385415
end
386416

387417
def apply(patch_file)
388418
arr_opts = []
389-
arr_opts << patch_file.to_s if patch_file
419+
arr_opts << patch_file if patch_file
390420
command('apply', arr_opts)
391421
end
392422

393423
def apply_mail(patch_file)
394424
arr_opts = []
395-
arr_opts << patch_file.to_s if patch_file
425+
arr_opts << patch_file if patch_file
396426
command('am', arr_opts)
397427
end
398428

@@ -437,23 +467,29 @@ def branch_delete(branch)
437467
def checkout(branch, opts = {})
438468
arr_opts = []
439469
arr_opts << '-f' if opts[:force]
440-
arr_opts << ["-b '#{opts[:new_branch]}'"] if opts[:new_branch]
441-
arr_opts << branch.to_s
470+
if opts[:new_branch]
471+
arr_opts << '-b'
472+
arr_opts << opts[:new_branch]
473+
end
474+
arr_opts << branch
442475

443476
command('checkout', arr_opts)
444477
end
445478

446479
def checkout_file(version, file)
447480
arr_opts = []
448-
arr_opts << version.to_s
449-
arr_opts << file.to_s
481+
arr_opts << version
482+
arr_opts << file
450483
command('checkout', arr_opts)
451484
end
452485

453486
def merge(branch, message = nil)
454487
arr_opts = []
455-
arr_opts << ["-m '#{message}'"] if message
456-
arr_opts << branch.to_a.join(' ')
488+
if message
489+
arr_opts << '-m'
490+
arr_opts << message
491+
end
492+
arr_opts += branch.to_a
457493
command('merge', arr_opts)
458494
end
459495

@@ -468,12 +504,10 @@ def unmerged
468504
def conflicts # :yields: file, your, their
469505
self.unmerged.each do |f|
470506
your = Tempfile.new("YOUR-#{File.basename(f)}").path
471-
arr_opts = [":2:#{f}", ">#{your}"]
472-
command('show', arr_opts)
507+
command('show', ":2:#{f}", true, "> #{escape your}")
473508

474509
their = Tempfile.new("THEIR-#{File.basename(f)}").path
475-
arr_opts = [":3:#{f}", ">#{their}"]
476-
command('show', arr_opts)
510+
command('show', ":3:#{f}", true, "> #{escape their}")
477511
yield(f, your, their)
478512
end
479513
end
@@ -507,12 +541,12 @@ def tag(tag)
507541

508542

509543
def fetch(remote)
510-
command('fetch', remote.to_s)
544+
command('fetch', remote)
511545
end
512546

513547
def push(remote, branch = 'master', tags = false)
514-
command('push', [remote.to_s, branch.to_s])
515-
command('push', ['--tags', remote.to_s]) if tags
548+
command('push', [remote, branch])
549+
command('push', ['--tags', remote]) if tags
516550
end
517551

518552
def tag_sha(tag_name)
@@ -534,7 +568,7 @@ def gc
534568
def read_tree(treeish, opts = {})
535569
arr_opts = []
536570
arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
537-
arr_opts << treeish.to_a.join(' ')
571+
arr_opts += treeish.to_a
538572
command('read-tree', arr_opts)
539573
end
540574

@@ -550,22 +584,29 @@ def commit_tree(tree, opts = {})
550584

551585
arr_opts = []
552586
arr_opts << tree
553-
arr_opts << "-p #{opts[:parent]}" if opts[:parent]
554-
arr_opts += opts[:parents].map { |p| "-p #{p.to_s}" } if opts[:parents]
555-
arr_opts << "< #{t.path}"
556-
command('commit-tree', arr_opts)
587+
if opts[:parent]
588+
arr_opts << '-p'
589+
arr_opts << opts[:parent]
590+
end
591+
arr_opts += opts[:parents].map { |p| ['-p', p] }.flatten if opts[:parents]
592+
command('commit-tree', arr_opts, true, "< #{escape t.path}")
557593
end
558594

559595
def update_ref(branch, commit)
560-
command('update-ref', [branch.to_s, commit.to_s])
596+
command('update-ref', [branch, commit])
561597
end
562598

563599
def checkout_index(opts = {})
564600
arr_opts = []
565601
arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
566602
arr_opts << "--force" if opts[:force]
567603
arr_opts << "--all" if opts[:all]
568-
arr_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
604+
605+
if opts[:path_limiter].is_a? String
606+
arr_opts << '--'
607+
arr_opts << opts[:path_limiter]
608+
end
609+
569610
command('checkout-index', arr_opts)
570611
end
571612

@@ -592,26 +633,24 @@ def archive(sha, file = nil, opts = {})
592633
arr_opts << "--remote=#{opts[:remote]}" if opts[:remote]
593634
arr_opts << sha
594635
arr_opts << opts[:path] if opts[:path]
595-
arr_opts << '| gzip' if opts[:add_gzip]
596-
arr_opts << "> #{file.to_s}"
597-
command('archive', arr_opts)
636+
command('archive', arr_opts, true, (opts[:add_gzip] ? '| gzip' : '') + " > #{escape file}")
598637
return file
599638
end
600639

601640
private
602641

603-
def command_lines(cmd, opts = [], chdir = true)
642+
def command_lines(cmd, opts = [], chdir = true, redirect = '')
604643
command(cmd, opts, chdir).split("\n")
605644
end
606645

607-
def command(cmd, opts = [], chdir = true, &block)
646+
def command(cmd, opts = [], chdir = true, redirect = '', &block)
608647
ENV['GIT_DIR'] = @git_dir
609648
ENV['GIT_INDEX_FILE'] = @git_index_file
610649
ENV['GIT_WORK_TREE'] = @git_work_dir
611650
path = @git_work_dir || @git_dir || @path
612651

613-
opts = opts.to_a.join(' ')
614-
git_cmd = "git #{cmd} #{opts} 2>&1"
652+
opts = opts.map {|s| escape(s) }.join(' ')
653+
git_cmd = "git #{cmd} #{opts} #{redirect} 2>&1"
615654

616655
out = nil
617656
if chdir && (Dir.getwd != path)
@@ -641,6 +680,10 @@ def run_command(git_cmd, &block)
641680
`#{git_cmd}`.chomp
642681
end
643682
end
644-
683+
684+
def escape(s)
685+
"'" + s.to_s.gsub('\'', '\'\\\'\'') + "'"
686+
end
687+
645688
end
646689
end

0 commit comments

Comments
 (0)