# HG changeset patch
# Parent 9607de6099a5f4e6a7d01d504e35e259daae8b7d
# User Toshi MARUYAMA
imported patch 2664-repo-fs-encoding/20110205-impl.diff

diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb
--- a/app/helpers/repositories_helper.rb
+++ b/app/helpers/repositories_helper.rb
@@ -176,7 +176,9 @@ module RepositoriesHelper
   end
   
   def mercurial_field_tags(form, repository)
-      content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
+    content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) +
+    content_tag('p', form.select(:path_encoding, [nil] + Setting::ENCODINGS,
+                                 :label => 'Path encoding'))
   end
 
   def git_field_tags(form, repository)
diff --git a/app/models/repository.rb b/app/models/repository.rb
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -15,6 +15,8 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
+require 'redmine/scm/adapters/path_encodable_wrapper'
+
 class Repository < ActiveRecord::Base
   belongs_to :project
   has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
@@ -38,7 +40,7 @@ class Repository < ActiveRecord::Base
   end
 
   def scm
-    @scm ||= self.scm_adapter.new url, root_url, login, password
+    @scm ||= new_scm
     update_attribute(:root_url, @scm.root_url) if root_url.blank?
     @scm
   end
@@ -206,6 +208,12 @@ class Repository < ActiveRecord::Base
   end
   
   private
+
+  def new_scm
+    scm = self.scm_adapter.new url, root_url, login, password
+    scm = Redmine::Scm::Adapters::PathEncodableWrapper.new(scm, path_encoding) unless path_encoding.blank?
+    scm
+  end
   
   def before_save
     # Strips url and root_url
diff --git a/lib/redmine/scm/adapters/path_encodable_wrapper.rb b/lib/redmine/scm/adapters/path_encodable_wrapper.rb
new file mode 100644
--- /dev/null
+++ b/lib/redmine/scm/adapters/path_encodable_wrapper.rb
@@ -0,0 +1,109 @@
+# redMine - project management software
+# Copyright (C) 2006-2010  Jean-Philippe Lang
+# Copyright (C) 2010 Yuya Nishihara <yuya@tcha.org>
+#
+# 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.
+
+require 'delegate'
+require 'iconv'
+
+module Redmine
+  module Scm
+    module Adapters
+      # wraps scm adapter to convert path encodings
+      class PathEncodableWrapper < SimpleDelegator  # :nodoc:
+        def initialize(scm, path_encoding)
+          super(scm)
+          @path_encoding = path_encoding
+        end
+
+        def entry(path=nil, identifier=nil)
+          convert_entry!(super(to_scm_path(path), identifier))
+        end
+
+        def entries(path=nil, identifier=nil)
+          convert_entries!(super(to_scm_path(path), identifier))
+        end
+
+        def properties(path, identifier=nil)
+          super(to_scm_path(path), identifier)
+        end
+
+        def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
+          convert_revisions!(super(to_scm_path(path), identifier_from, identifier_to, options))
+        end
+
+        def diff(path, identifier_from, identifier_to=nil)
+          super(to_scm_path(path), identifier_from, identifier_to)
+        end
+
+        def cat(path, identifier=nil)
+          super(to_scm_path(path), identifier)
+        end
+
+        def annotate(path, identifier=nil)
+          super(to_scm_path(path), identifier)
+        end
+
+        private
+
+        def convert_entry!(entry)
+          return unless entry
+          entry.name = from_scm_path(entry.name)
+          entry.path = from_scm_path(entry.path)
+          entry
+        end
+
+        def convert_entries!(entries)
+          return unless entries
+          entries.each { |e| convert_entry!(e) }
+          entries
+        end
+
+        def convert_revisions!(revisions)
+          return unless revisions
+          revisions.each do |rev|
+            next unless rev.paths
+            rev.paths.each do |e|
+              e[:path] = from_scm_path(e[:path])
+              e[:from_path] = from_scm_path(e[:from_path])
+            end
+          end
+          revisions
+        end
+
+        # convert repository path string to utf-8
+        def from_scm_path(s)
+          return unless s
+          begin
+            Iconv.conv('UTF-8', @path_encoding, s)
+          rescue Iconv::Failure => err
+            raise CommandFailed, "failed to convert path from #{@path_encoding} to UTF-8. #{err}"
+          end
+        end
+
+        # convert utf-8 path string to repository encoding
+        def to_scm_path(s)
+          return unless s
+          begin
+            Iconv.conv(@path_encoding, 'UTF-8', s)
+          rescue Iconv::Failure => err
+            raise CommandFailed, "failed to convert path from UTF-8 to #{@path_encoding}. #{err}"
+          end
+        end
+      end
+    end
+  end
+end
