# Redmine - project management software
-# Copyright (C) 2006-2008 Jean-Philippe Lang
+# Copyright (C) 2006-2010 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
super
end
+ def committer=(arg)
+ write_attribute(:committer, self.class.to_utf8(arg.to_s))
+ end
+
def project
repository.project
end
encoding = Setting.commit_logs_encoding.to_s.strip
unless encoding.blank? || encoding == 'UTF-8'
begin
- return Iconv.conv('UTF-8', encoding, str)
+ str = Iconv.conv('UTF-8', encoding, str)
rescue Iconv::Failure
# do nothing here
end
end
- str
+ # removes invalid UTF8 sequences
+ Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3]
end
end
# With SCM's that have a sequential commit numbering, redmine is able to be
# clever and only fetch changesets going forward from the most recent one
# it knows about. However, with git, you never know if people have merged
- # commits into the middle of the repository history, so we always have to
- # parse the entire log.
+ # commits into the middle of the repository history, so we should parse
+ # the entire log. Since it's way too slow for large repositories, we only
+ # parse 1 week before the last known commit.
+ # The repository can still be fully reloaded by calling #clear_changesets
+ # before fetching changesets (eg. for offline resync)
def fetch_changesets
- # Save ourselves an expensive operation if we're already up to date
- return if scm.num_revisions == changesets.count
+ c = changesets.find(:first, :order => 'committed_on DESC')
+ since = (c ? c.committed_on - 7.days : nil)
- revisions = scm.revisions('', nil, nil, :all => true)
+ revisions = scm.revisions('', nil, nil, :all => true, :since => since)
return if revisions.nil? || revisions.empty?
- # Find revisions that redmine knows about already
- existing_revisions = changesets.find(:all).map!{|c| c.scmid}
+ recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
# Clean out revisions that are no longer in git
- Changeset.delete_all(["scmid NOT IN (?) AND repository_id = (?)", revisions.map{|r| r.scmid}, self.id])
+ recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
# Subtract revisions that redmine already knows about
- revisions.reject!{|r| existing_revisions.include?(r.scmid)}
+ recent_revisions = recent_changesets.map{|c| c.scmid}
+ revisions.reject!{|r| recent_revisions.include?(r.scmid)}
# Save the remaining ones to the database
revisions.each{|r| r.save(self)} unless revisions.nil?
--- /dev/null
+class AddIndexOnChangesetsScmid < ActiveRecord::Migration
+ def self.up
+ add_index :changesets, [:repository_id, :scmid], :name => :changesets_repos_scmid
+ end
+
+ def self.down
+ remove_index :changesets, :name => :changesets_repos_scmid
+ end
+end
end
def branches
- branches = []
+ return @branches if @branches
+ @branches = []
cmd = "#{GIT_BIN} --git-dir #{target('')} branch"
shellout(cmd) do |io|
io.each_line do |line|
- branches << line.match('\s*\*?\s*(.*)$')[1]
+ @branches << line.match('\s*\*?\s*(.*)$')[1]
end
end
- branches.sort!
+ @branches.sort!
end
def tags
- tags = []
+ return @tags if @tags
cmd = "#{GIT_BIN} --git-dir #{target('')} tag"
shellout(cmd) do |io|
- io.readlines.sort!.map{|t| t.strip}
+ @tags = io.readlines.sort!.map{|t| t.strip}
end
end
end
end
- def num_revisions
- cmd = "#{GIT_BIN} --git-dir #{target('')} log --all --pretty=format:'' | wc -l"
- shellout(cmd) {|io| io.gets.chomp.to_i + 1}
- end
-
def revisions(path, identifier_from, identifier_to, options={})
revisions = Revisions.new
- cmd = "#{GIT_BIN} --git-dir #{target('')} log --find-copies-harder --raw --date=iso --pretty=fuller"
+ cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller"
cmd << " --reverse" if options[:reverse]
cmd << " --all" if options[:all]
cmd << " -n #{options[:limit]} " if options[:limit]
cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from
cmd << " #{shell_quote identifier_to} " if identifier_to
+ cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since]
cmd << " -- #{path}" if path && !path.empty?
shellout(cmd) do |io|
--- /dev/null
+Texte encodé en ISO-8859-1.
\ No newline at end of file
-# redMine - project management software
-# Copyright (C) 2006-2007 Jean-Philippe Lang
+# encoding: utf-8
+#
+# Redmine - project management software
+# Copyright (C) 2006-2010 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
changeset = Changeset.find_by_revision('10')
assert_nil changeset.next
end
+
+ def test_comments_should_be_converted_to_utf8
+ with_settings :commit_logs_encoding => 'ISO-8859-1' do
+ c = Changeset.new
+ c.comments = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
+ assert_equal "Texte encodé en ISO-8859-1.", c.comments
+ end
+ end
+
+ def test_invalid_utf8_sequences_in_comments_should_be_stripped
+ c = Changeset.new
+ c.comments = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
+ assert_equal "Texte encod en ISO-8859-1.", c.comments
+ end
end
@repository.reload
assert_equal 12, @repository.changesets.count
- assert_equal 20, @repository.changes.count
+ assert_equal 21, @repository.changes.count
commit = @repository.changesets.find(:first, :order => 'committed_on ASC')
assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments