@@ -0,0 +1,9 | |||||
|
1 | class AddIndexOnChangesetsScmid < ActiveRecord::Migration | |||
|
2 | def self.up | |||
|
3 | add_index :changesets, [:repository_id, :scmid], :name => :changesets_repos_scmid | |||
|
4 | end | |||
|
5 | ||||
|
6 | def self.down | |||
|
7 | remove_index :changesets, :name => :changesets_repos_scmid | |||
|
8 | end | |||
|
9 | end |
@@ -0,0 +1,1 | |||||
|
1 | Texte encod� en ISO-8859-1. No newline at end of file |
@@ -1,5 +1,5 | |||||
1 | # Redmine - project management software |
|
1 | # Redmine - project management software | |
2 |
# Copyright (C) 2006-200 |
|
2 | # Copyright (C) 2006-2010 Jean-Philippe Lang | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
4 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
5 | # modify it under the terms of the GNU General Public License | |
@@ -57,6 +57,10 class Changeset < ActiveRecord::Base | |||||
57 | super |
|
57 | super | |
58 | end |
|
58 | end | |
59 |
|
59 | |||
|
60 | def committer=(arg) | |||
|
61 | write_attribute(:committer, self.class.to_utf8(arg.to_s)) | |||
|
62 | end | |||
|
63 | ||||
60 | def project |
|
64 | def project | |
61 | repository.project |
|
65 | repository.project | |
62 | end |
|
66 | end | |
@@ -171,11 +175,12 class Changeset < ActiveRecord::Base | |||||
171 | encoding = Setting.commit_logs_encoding.to_s.strip |
|
175 | encoding = Setting.commit_logs_encoding.to_s.strip | |
172 | unless encoding.blank? || encoding == 'UTF-8' |
|
176 | unless encoding.blank? || encoding == 'UTF-8' | |
173 | begin |
|
177 | begin | |
174 |
|
|
178 | str = Iconv.conv('UTF-8', encoding, str) | |
175 | rescue Iconv::Failure |
|
179 | rescue Iconv::Failure | |
176 | # do nothing here |
|
180 | # do nothing here | |
177 | end |
|
181 | end | |
178 | end |
|
182 | end | |
179 | str |
|
183 | # removes invalid UTF8 sequences | |
|
184 | Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3] | |||
180 | end |
|
185 | end | |
181 | end |
|
186 | end |
@@ -40,23 +40,26 class Repository::Git < Repository | |||||
40 | # With SCM's that have a sequential commit numbering, redmine is able to be |
|
40 | # With SCM's that have a sequential commit numbering, redmine is able to be | |
41 | # clever and only fetch changesets going forward from the most recent one |
|
41 | # clever and only fetch changesets going forward from the most recent one | |
42 | # it knows about. However, with git, you never know if people have merged |
|
42 | # it knows about. However, with git, you never know if people have merged | |
43 |
# commits into the middle of the repository history, so we |
|
43 | # commits into the middle of the repository history, so we should parse | |
44 | # parse the entire log. |
|
44 | # the entire log. Since it's way too slow for large repositories, we only | |
|
45 | # parse 1 week before the last known commit. | |||
|
46 | # The repository can still be fully reloaded by calling #clear_changesets | |||
|
47 | # before fetching changesets (eg. for offline resync) | |||
45 | def fetch_changesets |
|
48 | def fetch_changesets | |
46 | # Save ourselves an expensive operation if we're already up to date |
|
49 | c = changesets.find(:first, :order => 'committed_on DESC') | |
47 | return if scm.num_revisions == changesets.count |
|
50 | since = (c ? c.committed_on - 7.days : nil) | |
48 |
|
51 | |||
49 | revisions = scm.revisions('', nil, nil, :all => true) |
|
52 | revisions = scm.revisions('', nil, nil, :all => true, :since => since) | |
50 | return if revisions.nil? || revisions.empty? |
|
53 | return if revisions.nil? || revisions.empty? | |
51 |
|
54 | |||
52 | # Find revisions that redmine knows about already |
|
55 | recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since]) | |
53 | existing_revisions = changesets.find(:all).map!{|c| c.scmid} |
|
|||
54 |
|
56 | |||
55 | # Clean out revisions that are no longer in git |
|
57 | # Clean out revisions that are no longer in git | |
56 | Changeset.delete_all(["scmid NOT IN (?) AND repository_id = (?)", revisions.map{|r| r.scmid}, self.id]) |
|
58 | recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }} | |
57 |
|
59 | |||
58 | # Subtract revisions that redmine already knows about |
|
60 | # Subtract revisions that redmine already knows about | |
59 | revisions.reject!{|r| existing_revisions.include?(r.scmid)} |
|
61 | recent_revisions = recent_changesets.map{|c| c.scmid} | |
|
62 | revisions.reject!{|r| recent_revisions.include?(r.scmid)} | |||
60 |
|
63 | |||
61 | # Save the remaining ones to the database |
|
64 | # Save the remaining ones to the database | |
62 | revisions.each{|r| r.save(self)} unless revisions.nil? |
|
65 | revisions.each{|r| r.save(self)} unless revisions.nil? |
@@ -33,21 +33,22 module Redmine | |||||
33 | end |
|
33 | end | |
34 |
|
34 | |||
35 | def branches |
|
35 | def branches | |
36 |
|
|
36 | return @branches if @branches | |
|
37 | @branches = [] | |||
37 | cmd = "#{GIT_BIN} --git-dir #{target('')} branch" |
|
38 | cmd = "#{GIT_BIN} --git-dir #{target('')} branch" | |
38 | shellout(cmd) do |io| |
|
39 | shellout(cmd) do |io| | |
39 | io.each_line do |line| |
|
40 | io.each_line do |line| | |
40 | branches << line.match('\s*\*?\s*(.*)$')[1] |
|
41 | @branches << line.match('\s*\*?\s*(.*)$')[1] | |
41 | end |
|
42 | end | |
42 | end |
|
43 | end | |
43 | branches.sort! |
|
44 | @branches.sort! | |
44 | end |
|
45 | end | |
45 |
|
46 | |||
46 | def tags |
|
47 | def tags | |
47 |
|
|
48 | return @tags if @tags | |
48 | cmd = "#{GIT_BIN} --git-dir #{target('')} tag" |
|
49 | cmd = "#{GIT_BIN} --git-dir #{target('')} tag" | |
49 | shellout(cmd) do |io| |
|
50 | shellout(cmd) do |io| | |
50 | io.readlines.sort!.map{|t| t.strip} |
|
51 | @tags = io.readlines.sort!.map{|t| t.strip} | |
51 | end |
|
52 | end | |
52 | end |
|
53 | end | |
53 |
|
54 | |||
@@ -110,20 +111,16 module Redmine | |||||
110 | end |
|
111 | end | |
111 | end |
|
112 | end | |
112 |
|
113 | |||
113 | def num_revisions |
|
|||
114 | cmd = "#{GIT_BIN} --git-dir #{target('')} log --all --pretty=format:'' | wc -l" |
|
|||
115 | shellout(cmd) {|io| io.gets.chomp.to_i + 1} |
|
|||
116 | end |
|
|||
117 |
|
||||
118 | def revisions(path, identifier_from, identifier_to, options={}) |
|
114 | def revisions(path, identifier_from, identifier_to, options={}) | |
119 | revisions = Revisions.new |
|
115 | revisions = Revisions.new | |
120 |
|
116 | |||
121 |
cmd = "#{GIT_BIN} --git-dir #{target('')} log -- |
|
117 | cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller" | |
122 | cmd << " --reverse" if options[:reverse] |
|
118 | cmd << " --reverse" if options[:reverse] | |
123 | cmd << " --all" if options[:all] |
|
119 | cmd << " --all" if options[:all] | |
124 | cmd << " -n #{options[:limit]} " if options[:limit] |
|
120 | cmd << " -n #{options[:limit]} " if options[:limit] | |
125 | cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from |
|
121 | cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from | |
126 | cmd << " #{shell_quote identifier_to} " if identifier_to |
|
122 | cmd << " #{shell_quote identifier_to} " if identifier_to | |
|
123 | cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since] | |||
127 | cmd << " -- #{path}" if path && !path.empty? |
|
124 | cmd << " -- #{path}" if path && !path.empty? | |
128 |
|
125 | |||
129 | shellout(cmd) do |io| |
|
126 | shellout(cmd) do |io| |
@@ -1,5 +1,7 | |||||
1 | # redMine - project management software |
|
1 | # encoding: utf-8 | |
2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
2 | # | |
|
3 | # Redmine - project management software | |||
|
4 | # Copyright (C) 2006-2010 Jean-Philippe Lang | |||
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
@@ -117,4 +119,18 class ChangesetTest < ActiveSupport::TestCase | |||||
117 | changeset = Changeset.find_by_revision('10') |
|
119 | changeset = Changeset.find_by_revision('10') | |
118 | assert_nil changeset.next |
|
120 | assert_nil changeset.next | |
119 | end |
|
121 | end | |
|
122 | ||||
|
123 | def test_comments_should_be_converted_to_utf8 | |||
|
124 | with_settings :commit_logs_encoding => 'ISO-8859-1' do | |||
|
125 | c = Changeset.new | |||
|
126 | c.comments = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") | |||
|
127 | assert_equal "Texte encodé en ISO-8859-1.", c.comments | |||
|
128 | end | |||
|
129 | end | |||
|
130 | ||||
|
131 | def test_invalid_utf8_sequences_in_comments_should_be_stripped | |||
|
132 | c = Changeset.new | |||
|
133 | c.comments = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") | |||
|
134 | assert_equal "Texte encod en ISO-8859-1.", c.comments | |||
|
135 | end | |||
120 | end |
|
136 | end |
@@ -35,7 +35,7 class RepositoryGitTest < ActiveSupport::TestCase | |||||
35 | @repository.reload |
|
35 | @repository.reload | |
36 |
|
36 | |||
37 | assert_equal 12, @repository.changesets.count |
|
37 | assert_equal 12, @repository.changesets.count | |
38 |
assert_equal 2 |
|
38 | assert_equal 21, @repository.changes.count | |
39 |
|
39 | |||
40 | commit = @repository.changesets.find(:first, :order => 'committed_on ASC') |
|
40 | commit = @repository.changesets.find(:first, :order => 'committed_on ASC') | |
41 | assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments |
|
41 | assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments |
General Comments 0
You need to be logged in to leave comments.
Login now