few hours work - diff is done
[rubygit.git] / lib / git / lib.rb
blob8bb518bf2e92d567d1fb7f8721c0ed856a624bd5
1 module Git
2   
3   class GitExecuteError < StandardError 
4   end
5   
6   class Lib
7       
8     @git_dir = nil
9     @git_index_file = nil
10     @git_work_dir = nil
11         
12     def initialize(base)
13       if base.is_a?(Git::Base)
14         @git_dir = base.repo.path
15         @git_index_file = base.index.path   
16         @git_work_dir = base.dir.path
17       elsif base.is_a?(Hash)
18         @git_dir = base[:repository]
19         @git_index_file = base[:index] 
20         @git_work_dir = base[:working_directory]
21       end
22     end
23     
24     def init
25       command('init')
26     end
27     
28     def log_commits(opts = {})
29       arr_opts = ['--pretty=oneline']
30       arr_opts << "-#{opts[:count]}" if opts[:count]
31       arr_opts << "--since=\"#{opts[:since]}\"" if opts[:since].is_a? String
32       arr_opts << "#{opts[:between][0]}..#{opts[:between][1].to_s}" if (opts[:between] && opts[:between].size == 2)
33       arr_opts << opts[:object] if opts[:object].is_a? String
34       arr_opts << '-- ' + opts[:path_limiter] if opts[:path_limiter].is_a? String
35       
36       command_lines('log', arr_opts).map { |l| l.split.first }
37     end
38     
39     def revparse(string)
40       command('rev-parse', string)
41     end
42     
43     def object_type(sha)
44       command('cat-file', ['-t', sha])
45     end
46     
47     def object_size(sha)
48       command('cat-file', ['-s', sha]).to_i
49     end
50     
51     def object_contents(sha)
52       command('cat-file', ['-p', sha])
53     end
55     def branches_all
56       arr = []
57       command_lines('branch', '-a').each do |b| 
58         current = false
59         current = true if b[0, 2] == '* '
60         arr << [b.gsub('* ', '').strip, current]
61       end
62       arr
63     end
65     def config_get(name)
66       command('config', ['--get', name])
67     end
68     
69     def config_list
70       hsh = {}
71       command_lines('config', ['--list']).each do |line|
72         (key, value) = line.split('=')
73         hsh[key] = value
74       end
75       hsh
76     end
77         
78     def config_remote(name)
79       hsh = {}
80       command_lines('config', ['--get-regexp', "remote.#{name}"]).each do |line|
81         (key, value) = line.split
82         hsh[key.gsub("remote.#{name}.", '')] = value
83       end
84       hsh
85     end
86     
87     # returns hash
88     # [tree-ish] = [[line_no, match], [line_no, match2]]
89     # [tree-ish] = [[line_no, match], [line_no, match2]]
90     def grep(string, opts = {})
91       opts[:object] = 'HEAD' if !opts[:object]
93       grep_opts = ['-n']
94       grep_opts << '-i' if opts[:ignore_case]
95       grep_opts << '-v' if opts[:invert_match]
96       grep_opts << "-e '#{string}'"
97       grep_opts << opts[:object] if opts[:object].is_a?(String)
98       grep_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
99       hsh = {}
100       command_lines('grep', grep_opts).each do |line|
101         if m = /(.*)\:(\d+)\:(.*)/.match(line)        
102           hsh[m[1]] ||= []
103           hsh[m[1]] << [m[2].to_i, m[3]] 
104         end
105       end
106       hsh
107     end
108     
109     def diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})
110       diff_opts = ['-p']
111       diff_opts << obj1
112       diff_opts << obj2 if obj2.is_a?(String)
113       diff_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
114       
115       command('diff', diff_opts)
116     end
117     
118     def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
119       diff_opts = ['--numstat']
120       diff_opts << obj1
121       diff_opts << obj2 if obj2.is_a?(String)
122       diff_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
123       
124       hsh = {:total => {:insertions => 0, :deletions => 0, :lines => 0, :files => 0}, :files => {}}
125       
126       command_lines('diff', diff_opts).each do |file|
127         (insertions, deletions, filename) = file.split("\t")
128         hsh[:total][:insertions] += insertions.to_i
129         hsh[:total][:deletions] += deletions.to_i
130         hsh[:total][:lines] = (hsh[:total][:deletions] + hsh[:total][:insertions])
131         hsh[:total][:files] += 1
132         hsh[:files][filename] = {:insertions => insertions.to_i, :deletions => deletions.to_i}
133       end
134             
135       hsh
136     end
137     
138     private
139     
140     def command_lines(cmd, opts)
141       command(cmd, opts).split("\n")
142     end
143     
144     def command(cmd, opts = {})
145       ENV['GIT_DIR'] = @git_dir
146       ENV['GIT_INDEX_FILE'] = @git_index_file if @git_index_file
147       ENV['GIT_WORK_DIR'] = @git_work_dir if @git_work_dir
148       Dir.chdir(@git_work_dir || @git_dir) do  
149         opts = opts.to_a.join(' ')
150         #puts "git #{cmd} #{opts}"
151         out = `git #{cmd} #{opts} 2>&1`.chomp
152         #puts out
153         if $?.exitstatus > 1
154           raise Git::GitExecuteError.new(out)
155         end
156         out
157       end
158     end
159     
160   end