diff app/models/.svn/text-base/changeset.rb.svn-base @ 441:cbce1fd3b1b7 redmine-1.2

Update to Redmine 1.2-stable branch (Redmine SVN rev 6000)
author Chris Cannam
date Mon, 06 Jun 2011 14:24:13 +0100
parents 051f544170fe
children 753f1380d6bc
line wrap: on
line diff
--- a/app/models/.svn/text-base/changeset.rb.svn-base	Thu Mar 03 11:42:28 2011 +0000
+++ b/app/models/.svn/text-base/changeset.rb.svn-base	Mon Jun 06 14:24:13 2011 +0100
@@ -1,16 +1,16 @@
 # Redmine - project management software
-# Copyright (C) 2006-2010  Jean-Philippe Lang
+# Copyright (C) 2006-2011  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
 # as published by the Free Software Foundation; either version 2
 # of the License, or (at your option) any later version.
-# 
+#
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
-# 
+#
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
@@ -27,23 +27,23 @@
                 :description => :long_comments,
                 :datetime => :committed_on,
                 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :rev => o.identifier}}
-                
+
   acts_as_searchable :columns => 'comments',
                      :include => {:repository => :project},
                      :project_key => "#{Repository.table_name}.project_id",
                      :date_column => 'committed_on'
-                     
+
   acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
                             :author_key => :user_id,
                             :find_options => {:include => [:user, {:repository => :project}]}
-  
+
   validates_presence_of :repository_id, :revision, :committed_on, :commit_date
   validates_uniqueness_of :revision, :scope => :repository_id
   validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
-  
+
   named_scope :visible, lambda {|*args| { :include => {:repository => :project},
-                                          :conditions => Project.allowed_to_condition(args.first || User.current, :view_changesets) } }
-                                          
+                                          :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
+
   def revision=(r)
     write_attribute :revision, (r.nil? ? nil : r.to_s)
   end
@@ -70,25 +70,26 @@
       identifier
     end
   end
-  
+
   def project
     repository.project
   end
-  
+
   def author
     user || committer.to_s.split('<').first
   end
-  
+
   def before_create
     self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
-    self.comments  = self.class.normalize_comments(self.comments, repository.repo_log_encoding)
+    self.comments  = self.class.normalize_comments(
+                       self.comments, repository.repo_log_encoding)
     self.user = repository.find_committer_user(self.committer)
   end
 
   def after_create
     scan_comment_for_issue_ids
   end
-  
+
   TIMELOG_RE = /
     (
     ((\d+)(h|hours?))((\d+)(m|min)?)?
@@ -100,7 +101,7 @@
     (\d+([\.,]\d+)?)h?
     )
     /x
-  
+
   def scan_comment_for_issue_ids
     return if comments.blank?
     # keywords used to reference issues
@@ -108,15 +109,15 @@
     ref_keywords_any = ref_keywords.delete('*')
     # keywords used to fix issues
     fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
-    
+
     kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
-    
+
     referenced_issues = []
-    
+
     comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
       action, refs = match[2], match[3]
       next unless action.present? || ref_keywords_any
-      
+
       refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
         issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
         if issue
@@ -126,15 +127,15 @@
         end
       end
     end
-    
+
     referenced_issues.uniq!
     self.issues = referenced_issues unless referenced_issues.empty?
   end
-  
+
   def short_comments
     @short_comments || split_comments.first
   end
-  
+
   def long_comments
     @long_comments || split_comments.last
   end
@@ -146,23 +147,29 @@
       "r#{revision}"
     end
   end
-  
+
   # Returns the previous changeset
   def previous
-    @previous ||= Changeset.find(:first, :conditions => ['id < ? AND repository_id = ?', self.id, self.repository_id], :order => 'id DESC')
+    @previous ||= Changeset.find(:first,
+                    :conditions => ['id < ? AND repository_id = ?',
+                                    self.id, self.repository_id],
+                    :order => 'id DESC')
   end
 
   # Returns the next changeset
   def next
-    @next ||= Changeset.find(:first, :conditions => ['id > ? AND repository_id = ?', self.id, self.repository_id], :order => 'id ASC')
+    @next ||= Changeset.find(:first,
+                    :conditions => ['id > ? AND repository_id = ?',
+                                    self.id, self.repository_id],
+                    :order => 'id ASC')
   end
-  
+
   # Creates a new Change from it's common parameters
   def create_change(change)
-    Change.create(:changeset => self,
-                  :action => change[:action],
-                  :path => change[:path],
-                  :from_path => change[:from_path],
+    Change.create(:changeset     => self,
+                  :action        => change[:action],
+                  :path          => change[:path],
+                  :from_path     => change[:from_path],
                   :from_revision => change[:from_revision])
   end
 
@@ -174,25 +181,27 @@
     return nil if id.blank?
     issue = Issue.find_by_id(id.to_i, :include => :project)
     if issue
-      unless project == issue.project || project.is_ancestor_of?(issue.project) || project.is_descendant_of?(issue.project)
+      unless issue.project &&
+                (project == issue.project || project.is_ancestor_of?(issue.project) ||
+                 project.is_descendant_of?(issue.project))
         issue = nil
       end
     end
     issue
   end
-  
+
   def fix_issue(issue)
     status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
     if status.nil?
       logger.warn("No status macthes commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
       return issue
     end
-    
+
     # the issue may have been updated by the closure of another one (eg. duplicate)
     issue.reload
     # don't change the status is the issue is closed
     return if issue.status && issue.status.is_closed?
-    
+
     journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag))
     issue.status = status
     unless Setting.commit_fix_done_ratio.blank?
@@ -205,29 +214,30 @@
     end
     issue
   end
-  
+
   def log_time(issue, hours)
     time_entry = TimeEntry.new(
       :user => user,
       :hours => hours,
       :issue => issue,
       :spent_on => commit_date,
-      :comments => l(:text_time_logged_by_changeset, :value => text_tag, :locale => Setting.default_language)
+      :comments => l(:text_time_logged_by_changeset, :value => text_tag,
+                     :locale => Setting.default_language)
       )
     time_entry.activity = log_time_activity unless log_time_activity.nil?
-    
+
     unless time_entry.save
       logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger
     end
     time_entry
   end
-  
+
   def log_time_activity
     if Setting.commit_logtime_activity_id.to_i > 0
       TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i)
     end
   end
-  
+
   def split_comments
     comments =~ /\A(.+?)\r?\n(.*)$/m
     @short_comments = $1 || comments
@@ -242,30 +252,39 @@
     Changeset.to_utf8(str.to_s.strip, encoding)
   end
 
-  private
-
   def self.to_utf8(str, encoding)
-    return str if str.blank?
-    unless encoding.blank? || encoding == 'UTF-8'
-      begin
-        str = Iconv.conv('UTF-8', encoding, str)
-      rescue Iconv::Failure
-        # do nothing here
-      end
+    return str if str.nil?
+    str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
+    if str.empty?
+      str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
+      return str
     end
+    enc = encoding.blank? ? "UTF-8" : encoding
     if str.respond_to?(:force_encoding)
-      str.force_encoding('UTF-8')
-      if ! str.valid_encoding?
-        str = str.encode("US-ASCII", :invalid => :replace,
-              :undef => :replace, :replace => '?').encode("UTF-8")
+      if enc.upcase != "UTF-8"
+        str.force_encoding(enc)
+        str = str.encode("UTF-8", :invalid => :replace,
+              :undef => :replace, :replace => '?')
+      else
+        str.force_encoding("UTF-8")
+        if ! str.valid_encoding?
+          str = str.encode("US-ASCII", :invalid => :replace,
+                :undef => :replace, :replace => '?').encode("UTF-8")
+        end
       end
     else
-      # removes invalid UTF8 sequences
+      ic = Iconv.new('UTF-8', enc)
+      txtar = ""
       begin
-        str = Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + '  ')[0..-3]
-      rescue Iconv::InvalidEncoding
-        # "UTF-8//IGNORE" is not supported on some OS
+        txtar += ic.iconv(str)
+      rescue Iconv::IllegalSequence
+        txtar += $!.success
+        str = '?' + $!.failed[1,$!.failed.length]
+        retry
+      rescue
+        txtar += $!.success
       end
+      str = txtar
     end
     str
   end