got clone and init to work - my first writing functions
[rubygit.git] / lib / git / lib.rb
blob9fa3986f03b04b8a0025718b991eb5d64a65eb2e
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     @path = nil
12         
13     def initialize(base = nil)
14       if base.is_a?(Git::Base)
15         @git_dir = base.repo.path
16         @git_index_file = base.index.path   
17         @git_work_dir = base.dir.path
18       elsif base.is_a?(Hash)
19         @git_dir = base[:repository]
20         @git_index_file = base[:index] 
21         @git_work_dir = base[:working_directory]
22       end
23     end
24     
25     def init
26       command('init')
27     end
28     
29     # tries to clone the given repo
30     #
31     # returns {:repository} (if bare)
32     #         {:working_directory} otherwise
33     #
34     # accepts options:
35     #  :remote - name of remote (rather than 'origin')
36     #  :bare   - no working directory
37     # 
38     # TODO - make this work with SSH password or auth_key
39     #
40     def clone(repository, name, opts = {})
41       @path = opts[:path] || '.'
42       clone_dir = File.join(@path, name)
43       
44       arr_opts = []
45       arr_opts << "--bare" if opts[:bare]
46       arr_opts << "-o #{opts[:remote]}" if opts[:remote]
47       arr_opts << repository
48       arr_opts << clone_dir
49       
50       command('clone', arr_opts)
51       
52       opts[:bare] ? {:repository => clone_dir} : {:working_directory => clone_dir}
53     end
54     
55     def log_commits(opts = {})
56       arr_opts = ['--pretty=oneline']
57       arr_opts << "-#{opts[:count]}" if opts[:count]
58       arr_opts << "--since=\"#{opts[:since]}\"" if opts[:since].is_a? String
59       arr_opts << "#{opts[:between][0]}..#{opts[:between][1].to_s}" if (opts[:between] && opts[:between].size == 2)
60       arr_opts << opts[:object] if opts[:object].is_a? String
61       arr_opts << '-- ' + opts[:path_limiter] if opts[:path_limiter].is_a? String
62       
63       command_lines('log', arr_opts).map { |l| l.split.first }
64     end
65     
66     def revparse(string)
67       command('rev-parse', string)
68     end
69     
70     def object_type(sha)
71       command('cat-file', ['-t', sha])
72     end
73     
74     def object_size(sha)
75       command('cat-file', ['-s', sha]).to_i
76     end
77     
78     def object_contents(sha)
79       command('cat-file', ['-p', sha])
80     end
82     def branches_all
83       arr = []
84       command_lines('branch', '-a').each do |b| 
85         current = false
86         current = true if b[0, 2] == '* '
87         arr << [b.gsub('* ', '').strip, current]
88       end
89       arr
90     end
92     def config_get(name)
93       command('config', ['--get', name])
94     end
95     
96     def config_list
97       hsh = {}
98       command_lines('config', ['--list']).each do |line|
99         (key, value) = line.split('=')
100         hsh[key] = value
101       end
102       hsh
103     end
104         
105     def config_remote(name)
106       hsh = {}
107       command_lines('config', ['--get-regexp', "remote.#{name}"]).each do |line|
108         (key, value) = line.split
109         hsh[key.gsub("remote.#{name}.", '')] = value
110       end
111       hsh
112     end
113     
114     # returns hash
115     # [tree-ish] = [[line_no, match], [line_no, match2]]
116     # [tree-ish] = [[line_no, match], [line_no, match2]]
117     def grep(string, opts = {})
118       opts[:object] = 'HEAD' if !opts[:object]
120       grep_opts = ['-n']
121       grep_opts << '-i' if opts[:ignore_case]
122       grep_opts << '-v' if opts[:invert_match]
123       grep_opts << "-e '#{string}'"
124       grep_opts << opts[:object] if opts[:object].is_a?(String)
125       grep_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
126       hsh = {}
127       command_lines('grep', grep_opts).each do |line|
128         if m = /(.*)\:(\d+)\:(.*)/.match(line)        
129           hsh[m[1]] ||= []
130           hsh[m[1]] << [m[2].to_i, m[3]] 
131         end
132       end
133       hsh
134     end
135     
136     def diff_full(obj1 = 'HEAD', obj2 = nil, opts = {})
137       diff_opts = ['-p']
138       diff_opts << obj1
139       diff_opts << obj2 if obj2.is_a?(String)
140       diff_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
141       
142       command('diff', diff_opts)
143     end
144     
145     def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
146       diff_opts = ['--numstat']
147       diff_opts << obj1
148       diff_opts << obj2 if obj2.is_a?(String)
149       diff_opts << ('-- ' + opts[:path_limiter]) if opts[:path_limiter].is_a? String
150       
151       hsh = {:total => {:insertions => 0, :deletions => 0, :lines => 0, :files => 0}, :files => {}}
152       
153       command_lines('diff', diff_opts).each do |file|
154         (insertions, deletions, filename) = file.split("\t")
155         hsh[:total][:insertions] += insertions.to_i
156         hsh[:total][:deletions] += deletions.to_i
157         hsh[:total][:lines] = (hsh[:total][:deletions] + hsh[:total][:insertions])
158         hsh[:total][:files] += 1
159         hsh[:files][filename] = {:insertions => insertions.to_i, :deletions => deletions.to_i}
160       end
161             
162       hsh
163     end
164     
165     private
166     
167     def command_lines(cmd, opts)
168       command(cmd, opts).split("\n")
169     end
170     
171     def command(cmd, opts = {})
172       ENV['GIT_DIR'] = @git_dir if @git_dir
173       ENV['GIT_INDEX_FILE'] = @git_index_file if @git_index_file
174       ENV['GIT_WORK_DIR'] = @git_work_dir if @git_work_dir
175       Dir.chdir(@git_work_dir || @git_dir || @path) do  
176         opts = opts.to_a.join(' ')
177         #puts "git #{cmd} #{opts}"
178         out = `git #{cmd} #{opts} 2>&1`.chomp
179         #puts out
180         if $?.exitstatus > 1
181           raise Git::GitExecuteError.new(out)
182         end
183         out
184       end
185     end
186     
187   end