Project

General

Profile

RE: Git branch tracking » redmine_git_branches3.diff

GIt branch support "hack" that is does not require any core changes - Alban Browaeys, 2009-03-24 19:04

View differences:

redmine_argos_gitbranches/lib/redmine/scm/adapters/git_adapter.rb 2009-02-23 07:13:11.000000000 +0100
26 26
        GIT_BIN = "git"
27 27

  
28 28
        # Get the revision of a particuliar file
29
        def get_rev (rev,path)
30
        
31
          if rev != 'latest' && !rev.nil?
32
            cmd="#{GIT_BIN} --git-dir #{target('')} show --date=iso --pretty=fuller #{shell_quote rev} -- #{shell_quote path}" 
33
          else
34
            @branch ||= shellout("#{GIT_BIN} --git-dir #{target('')} branch") { |io| io.grep(/\*/)[0].strip.match(/\* (.*)/)[1] }
35
            cmd="#{GIT_BIN} --git-dir #{target('')} log --date=iso --pretty=fuller -1 #{@branch} -- #{shell_quote path}" 
36
          end
37
          rev=[]
38
          i=0
39
          shellout(cmd) do |io|
40
            files=[]
41
            changeset = {}
42
            parsing_descr = 0  #0: not parsing desc or files, 1: parsing desc, 2: parsing files
29
        def get_rev (rev,treepath)
30
	    if treepath =~ /^refs\/([^\/]+)\/([^\/]+)\/(.*)$/
31
	      type = $1
32
	      tree = $2
33
	      path = $3
34
	      type_tree = "#{type}/#{tree}"
35
	    else
36
	      path ||= ''
37
	      type_tree ||= '' 
38
	      #return nil
39
	    end
40
	    if rev != 'latest' && !rev.nil?
41
	      #cmd="#{GIT_BIN} --git-dir #{target('')} show --raw --date=iso --pretty=fuller  #{shell_quote rev} #{shell_quote type_tree} -- #{shell_quote path}" 
42
	      cmd="#{GIT_BIN} --git-dir #{target('')} show --raw --date=iso --pretty=fuller -1 #{shell_quote rev} -- #{shell_quote path}" 
43
	    else
44
	      #@branch ||= shellout("#{GIT_BIN} --git-dir #{target('')} branch") { |io| io.grep(/\*/)[0].strip.match(/\* (.*)/)[1] }
45
	      cmd="#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller -1 #{type_tree} -- #{shell_quote path}" 
46
	    end
47
	    rev=[]
48
	    i=0
49
	    shellout(cmd) do |io|
50
	      files=[]
51
	      changeset = {}
52
	      parsing_descr = 0  #0: not parsing desc or files, 1: parsing desc, 2: parsing files
53

  
54
	      io.each_line do |line|
55
		if line =~ /^commit ([0-9a-f]{40})$/
56
		  key = "commit"
57
		  value = $1
58
		  if (parsing_descr == 1 || parsing_descr == 2)
59
		    parsing_descr = 0
60
		    rev = Revision.new({:identifier => changeset[:commit],
61
					:scmid => changeset[:commit],
62
					:author => changeset[:author],
63
					:time => Time.parse(changeset[:date]),
64
					:message => changeset[:description],
65
					:paths => files
66
				       })
67
		    changeset = {}
68
		    files = []
69
		  end
70
		  changeset[:commit] = $1
71
		elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
72
		  key = $1
73
		  value = $2
74
		  if key == "Author"
75
		    changeset[:author] = value
76
		  elsif key == "CommitDate"
77
		    changeset[:date] = value
78
		  end
79
		elsif (parsing_descr == 0) && line.chomp.to_s == ""
80
		  parsing_descr = 1
81
		  changeset[:description] = ""
82
		elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/
83
		  parsing_descr = 2
84
		  fileaction = $1
85
		  filepath = $2
86
		  files << {:action => fileaction, :path => "refs/#{type_tree}/#{filepath}"}
87
		elsif (parsing_descr == 1) && line.chomp.to_s == ""
88
		  parsing_descr = 2
89
		elsif (parsing_descr == 1)
90
		  changeset[:description] << line
91
		end
92
	      end	
93
	      rev = Revision.new({:identifier => changeset[:commit],
94
				  :scmid => changeset[:commit],
95
				  :author => changeset[:author],
96
				  :time => (changeset[:date] ? Time.parse(changeset[:date]) : nil),
97
				  :message => changeset[:description],
98
				  :paths => files
99
				 })
43 100

  
44
            io.each_line do |line|
45
              if line =~ /^commit ([0-9a-f]{40})$/
46
                key = "commit"
47
                value = $1
48
                if (parsing_descr == 1 || parsing_descr == 2)
49
                  parsing_descr = 0
50
                  rev = Revision.new({:identifier => changeset[:commit],
51
                                      :scmid => changeset[:commit],
52
                                      :author => changeset[:author],
53
                                      :time => Time.parse(changeset[:date]),
54
                                      :message => changeset[:description],
55
                                      :paths => files
56
                                     })
57
                  changeset = {}
58
                  files = []
59
                end
60
                changeset[:commit] = $1
61
              elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
62
                key = $1
63
                value = $2
64
                if key == "Author"
65
                  changeset[:author] = value
66
                elsif key == "CommitDate"
67
                  changeset[:date] = value
68
                end
69
              elsif (parsing_descr == 0) && line.chomp.to_s == ""
70
                parsing_descr = 1
71
                changeset[:description] = ""
72
              elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/
73
                parsing_descr = 2
74
                fileaction = $1
75
                filepath = $2
76
                files << {:action => fileaction, :path => filepath}
77
              elsif (parsing_descr == 1) && line.chomp.to_s == ""
78
                parsing_descr = 2
79
              elsif (parsing_descr == 1)
80
                changeset[:description] << line
81
              end
82
            end	
83
            rev = Revision.new({:identifier => changeset[:commit],
84
                                :scmid => changeset[:commit],
85
                                :author => changeset[:author],
86
                                :time => (changeset[:date] ? Time.parse(changeset[:date]) : nil),
87
                                :message => changeset[:description],
88
                                :paths => files
89
                               })
101
	    end
90 102

  
91
          end
92

  
93
          get_rev('latest',path) if rev == []
103
	    get_rev('latest',treepath) if rev == []
94 104

  
95
          return nil if $? && $?.exitstatus != 0
96
          return rev
105
	    return nil if $? && $?.exitstatus != 0
106
	    return rev
97 107
        end
98 108

  
99 109
        def info
......
107 117
          return nil
108 118
        end
109 119
        
110
        def entries(path=nil, identifier=nil)
111
          path ||= ''
112
          entries = Entries.new
113
          cmd = "#{GIT_BIN} --git-dir #{target('')} ls-tree -l "
114
          cmd << shell_quote("HEAD:" + path) if identifier.nil?
115
          cmd << shell_quote(identifier + ":" + path) if identifier
116
          shellout(cmd)  do |io|
117
            io.each_line do |line|
118
              e = line.chomp.to_s
119
              if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\s+(.+)$/
120
                type = $1
121
                sha = $2
122
                size = $3
123
                name = $4
124
                entries << Entry.new({:name => name,
125
                                       :path => (path.empty? ? name : "#{path}/#{name}"),
126
                                       :kind => ((type == "tree") ? 'dir' : 'file'),
127
                                       :size => ((type == "tree") ? nil : size),
128
                                       :lastrev => get_rev(identifier,(path.empty? ? name : "#{path}/#{name}")) 
129
                                                                  
130
                                     }) unless entries.detect{|entry| entry.name == name}
131
              end
132
            end
133
          end
134
          return nil if $? && $?.exitstatus != 0
135
          entries.sort_by_name
120
        def entries(treepath=nil, identifier=nil)
121
	  treepath ||= ''
122
	    if treepath =~ /^refs\/([^\/]+)\/([^\/]+)\/(.*)$/
123
	      type = $1
124
	      tree = $2
125
	      path = $3
126
	    else
127
	      type = "heads"
128
	      tree = "master"
129
	      path = '' 
130
	    end
131
	    path ||= ''
132
	    entries = Entries.new
133
	    if !treepath.empty?
134
	      type_tree = "#{type}/#{tree}"
135
	      cmd = "#{GIT_BIN} --git-dir #{target('')} ls-tree -l "
136
	      cmd << shell_quote(type_tree + ":" + path + (path.empty? ? "" : "/")) if identifier.nil?
137
	      cmd << shell_quote(identifier + ":" + path + (path.empty? ? "" : "/")) if identifier
138
	      shellout(cmd)  do |io|
139
		io.each_line do |line|
140
		  e = line.chomp.to_s
141
		  if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\s+(.+)$/
142
		    type = $1
143
		    sha = $2
144
		    size = $3
145
		    name = $4
146
		    entries << Entry.new({:name => name,
147
					   :path => (treepath.empty? ? name : "#{treepath}/#{name}"),
148
					   :kind => ((type == "tree") ? 'dir' : 'file'),
149
					   :size => ((type == "tree") ? nil : size),
150
					   #:lastrev => get_rev(identifier,(path.empty? ? name : "#{path}/#{name}")) 
151
					   :lastrev => get_rev(identifier,(treepath.empty? ? name : "#{treepath}/#{name}")) 
152
								      
153
					 }) unless entries.detect{|entry| entry.name == name}
154
		  end
155
		end
156
	      end
157
	    else
158
	      cmd = "#{GIT_BIN} --git-dir #{target('')} for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs"
159
	      shellout(cmd)  do |io|
160
		io.each_line do |line|
161
		  e = line.chomp.to_s
162
		  if e =~ /^([0-9a-f]{40})\s+\w+\s+(.+)$/
163
		    sha = $1
164
		    refname = $2
165
		    entries << Entry.new({:name => refname,
166
					   :path => refname,
167
					   #:path => (path.empty? ? refname : "#{path}/#{refname}"),
168
					   :kind => 'dir',
169
					   :size => nil,
170
					   :lastrev => get_rev(sha,(path.empty? ? refname : "#{path}/#{refname}")) 
171
								      
172
					 }) unless entries.detect{|entry| entry.name == refname}
173
		  end
174
		end
175
	      end
176
	    end
177
	    return nil if $? && $?.exitstatus != 0
178
	    entries.sort_by_name
136 179
        end
137 180
        
138
        def revisions(path, identifier_from, identifier_to, options={})
181
        def revisions(treepath, identifier_from, identifier_to, options={})
139 182
          revisions = Revisions.new
140
          cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller"
141
          cmd << " --reverse" if options[:reverse]
142
          cmd << " -n #{options[:limit].to_i} " if (!options.nil?) && options[:limit]
143
          cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from
144
          cmd << " #{shell_quote identifier_to} " if identifier_to
145
          shellout(cmd) do |io|
146
            files=[]
147
            changeset = {}
148
            parsing_descr = 0  #0: not parsing desc or files, 1: parsing desc, 2: parsing files
149
            revno = 1
150

  
151
            io.each_line do |line|
152
              if line =~ /^commit ([0-9a-f]{40})$/
153
                key = "commit"
154
                value = $1
155
                if (parsing_descr == 1 || parsing_descr == 2)
156
                  parsing_descr = 0
157
                  revision = Revision.new({:identifier => changeset[:commit],
158
                                           :scmid => changeset[:commit],
159
                                           :author => changeset[:author],
160
                                           :time => Time.parse(changeset[:date]),
161
                                           :message => changeset[:description],
162
                                           :paths => files
163
                                          })
164
                  if block_given?
165
                    yield revision
166
                  else
167
                    revisions << revision
168
                  end
169
                  changeset = {}
170
                  files = []
171
                  revno = revno + 1
172
                end
173
                changeset[:commit] = $1
174
              elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
175
                key = $1
176
                value = $2
177
                if key == "Author"
178
                  changeset[:author] = value
179
                elsif key == "CommitDate"
180
                  changeset[:date] = value
181
                end
182
              elsif (parsing_descr == 0) && line.chomp.to_s == ""
183
                parsing_descr = 1
184
                changeset[:description] = ""
185
              elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/
186
                parsing_descr = 2
187
                fileaction = $1
188
                filepath = $2
189
                files << {:action => fileaction, :path => filepath}
190
              elsif (parsing_descr == 1) && line.chomp.to_s == ""
191
                parsing_descr = 2
192
              elsif (parsing_descr == 1)
193
                changeset[:description] << line[4..-1]
194
              end
195
            end	
196

  
197
            if changeset[:commit]
198
              revision = Revision.new({:identifier => changeset[:commit],
199
                                       :scmid => changeset[:commit],
200
                                       :author => changeset[:author],
201
                                       :time => Time.parse(changeset[:date]),
202
                                       :message => changeset[:description],
203
                                       :paths => files
204
                                      })
205
              if block_given?
206
                yield revision
207
              else
208
                revisions << revision
209
              end
210
            end
211
          end
183
	  treepath ||= ''
184
	    if treepath =~ /^refs\/([^\/]+)\/([^\/]+)\/(.*)$/
185
	      type = $1
186
	      tree = $2
187
	      path = $3
188
	      type_tree = "#{type}/#{tree}"
189
	    else
190
	      path ||= '' 
191
	      type_tree ||= ''
192
	    end
193
	      cmd = "#{GIT_BIN} --git-dir #{target('')} for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs"
194
	      shellout(cmd)  do |io|
195
		io.each_line do |line|
196
		  e = line.chomp.to_s
197
		  if e =~ /^([0-9a-f]{40})\s+\w+\s+(.+)$/
198
		    sha = $1
199
		    refname = $2
200

  
201
		    cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller"
202
		    cmd << " --reverse" if options[:reverse]
203
		    cmd << " -n #{options[:limit].to_i} " if (!options.nil?) && options[:limit]
204
		    cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from
205
		    cmd << " #{shell_quote identifier_to} " if identifier_to
206
		    cmd << " #{shell_quote refname} " if identifier_from.nil? && identifier_to.nil?
207
		    shellout(cmd) do |io|
208
		      files=[]
209
		      changeset = {}
210
		      parsing_descr = 0  #0: not parsing desc or files, 1: parsing desc, 2: parsing files
211
		      revno = 1
212

  
213
		      io.each_line do |line|
214
			if line =~ /^commit ([0-9a-f]{40})$/
215
			  key = "commit"
216
			  value = $1
217
			  if (parsing_descr == 1 || parsing_descr == 2)
218
			    parsing_descr = 0
219
			    revision = Revision.new({:identifier => changeset[:commit],
220
						     :scmid => changeset[:commit],
221
						     :author => changeset[:author],
222
						     :time => Time.parse(changeset[:date]),
223
						     :message => changeset[:description],
224
						     :paths => files
225
						    })
226
			    if block_given?
227
			      yield revision
228
			    else
229
			      revisions << revision
230
			    end
231
			    changeset = {}
232
			    files = []
233
			    revno = revno + 1
234
			  end
235
			  changeset[:commit] = $1
236
			elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
237
			  key = $1
238
			  value = $2
239
			  if key == "Author"
240
			    changeset[:author] = value
241
			  elsif key == "CommitDate"
242
			    changeset[:date] = value
243
			  end
244
			elsif (parsing_descr == 0) && line.chomp.to_s == ""
245
			  parsing_descr = 1
246
			  changeset[:description] = ""
247
			elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/
248
			  parsing_descr = 2
249
			  fileaction = $1
250
			  filepath = $2
251
			  files << {:action => fileaction, :path => "#{refname}/#{filepath}"}
252
			elsif (parsing_descr == 1) && line.chomp.to_s == ""
253
			  parsing_descr = 2
254
			elsif (parsing_descr == 1)
255
			  changeset[:description] << line[4..-1]
256
			end
257
		      end	
258

  
259
		      if changeset[:commit]
260
			revision = Revision.new({:identifier => changeset[:commit],
261
						 :scmid => changeset[:commit],
262
						 :author => changeset[:author],
263
						 :time => Time.parse(changeset[:date]),
264
						 :message => changeset[:description],
265
						 :paths => files
266
						})
267
			if block_given?
268
			  yield revision
269
			else
270
			  revisions << revision
271
			end
272
		      end
273
	            end
274
		  end
275
		end
276
	      end
212 277

  
213 278
          return nil if $? && $?.exitstatus != 0
214 279
          revisions
215 280
        end
216 281
        
217
        def diff(path, identifier_from, identifier_to=nil)
218
          path ||= ''
282
        def diff(treepath, identifier_from, identifier_to=nil)
283
	  treepath ||= ''
284
	  if treepath =~ /^refs\/([^\/]+)\/([^\/]+)\/(.*)$/
285
	    type = $1
286
	    tree = $2
287
	    path = $3
288
	    type_tree = "#{type}/#{tree}"
289
	  else
290
	    type = "heads"
291
	    tree = "master"
292
	    path ||= '' 
293
	    type_tree = 'heads/master'
294
	  end
219 295
          if !identifier_to
220 296
            identifier_to = nil
221 297
          end
......
233 309
          diff
234 310
        end
235 311
        
236
        def annotate(path, identifier=nil)
312
        def annotate(treepath, identifier=nil)
313
	  treepath ||= ''
314
	  if treepath =~ /^refs\/([^\/]+)\/([^\/]+)\/(.*)$/
315
	    type = $1
316
	    tree = $2
317
	    path = $3
318
	    type_tree = "#{type}/#{tree}"
319
	  else
320
	    type = "heads"
321
	    tree = "master"
322
	    path = '' 
323
	    type_tree = 'heads/master'
324
	  end
237 325
          identifier = 'HEAD' if identifier.blank?
238 326
          cmd = "#{GIT_BIN} --git-dir #{target('')} blame -l #{shell_quote identifier} -- #{shell_quote path}"
239 327
          blame = Annotate.new
......
249 337
          blame
250 338
        end
251 339
        
252
        def cat(path, identifier=nil)
340
        def cat(treepath, identifier=nil)
341
	  treepath ||= ''
342
	  if treepath =~ /^refs\/([^\/]+)\/([^\/]+)\/(.*)$/
343
	    type = $1
344
	    tree = $2
345
	    path = $3
346
	    type_tree = "#{type}/#{tree}"
347
	  else
348
	    type = "heads"
349
	    tree = "master"
350
	    path = '' 
351
	    type_tree = 'heads/master'
352
	  end
253 353
          if identifier.nil?
254 354
            identifier = 'HEAD'
255 355
          end
(1-1/2)