comparison lib/redmine/scm/adapters/.svn/text-base/filesystem_adapter.rb.svn-base @ 511:107d36338b70 live

Merge from branch "cannam"
author Chris Cannam
date Thu, 14 Jul 2011 10:43:07 +0100
parents cbce1fd3b1b7
children
comparison
equal deleted inserted replaced
451:a9f6345cb43d 511:107d36338b70
1 # redMine - project management software 1 # RedMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 # 3 #
4 # FileSystem adapter 4 # FileSystem adapter
5 # File written by Paul Rivier, at Demotera. 5 # File written by Paul Rivier, at Demotera.
6 # 6 #
7 # This program is free software; you can redistribute it and/or 7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License 8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2 9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version. 10 # of the License, or (at your option) any later version.
11 # 11 #
12 # This program is distributed in the hope that it will be useful, 12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details. 15 # GNU General Public License for more details.
16 # 16 #
17 # You should have received a copy of the GNU General Public License 17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software 18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 20
21 require 'redmine/scm/adapters/abstract_adapter' 21 require 'redmine/scm/adapters/abstract_adapter'
22 require 'find' 22 require 'find'
23 23
24 module Redmine 24 module Redmine
25 module Scm 25 module Scm
26 module Adapters 26 module Adapters
27 class FilesystemAdapter < AbstractAdapter 27 class FilesystemAdapter < AbstractAdapter
28
29 28
30 def initialize(url, root_url=nil, login=nil, password=nil) 29 class << self
30 def client_available
31 true
32 end
33 end
34
35 def initialize(url, root_url=nil, login=nil, password=nil,
36 path_encoding=nil)
31 @url = with_trailling_slash(url) 37 @url = with_trailling_slash(url)
38 @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding
39 end
40
41 def path_encoding
42 @path_encoding
32 end 43 end
33 44
34 def format_path_ends(path, leading=true, trailling=true) 45 def format_path_ends(path, leading=true, trailling=true)
35 path = leading ? with_leading_slash(path) : 46 path = leading ? with_leading_slash(path) :
36 without_leading_slash(path) 47 without_leading_slash(path)
37 trailling ? with_trailling_slash(path) : 48 trailling ? with_trailling_slash(path) :
38 without_trailling_slash(path) 49 without_trailling_slash(path)
39 end 50 end
40 51
41 def info 52 def info
42 info = Info.new({:root_url => target(), 53 info = Info.new({:root_url => target(),
43 :lastrev => nil 54 :lastrev => nil
44 }) 55 })
45 info 56 info
46 rescue CommandFailed 57 rescue CommandFailed
47 return nil 58 return nil
48 end 59 end
49 60
50 def entries(path="", identifier=nil) 61 def entries(path="", identifier=nil, options={})
51 entries = Entries.new 62 entries = Entries.new
52 Dir.new(target(path)).each do |e| 63 trgt_utf8 = target(path)
53 relative_path = format_path_ends((format_path_ends(path, 64 trgt = scm_iconv(@path_encoding, 'UTF-8', trgt_utf8)
54 false, 65 Dir.new(trgt).each do |e1|
55 true) + e), 66 e_utf8 = scm_iconv('UTF-8', @path_encoding, e1)
56 false,false) 67 next if e_utf8.blank?
57 target = target(relative_path) 68 relative_path_utf8 = format_path_ends(
58 entries << 69 (format_path_ends(path,false,true) + e_utf8),false,false)
59 Entry.new({ :name => File.basename(e), 70 t1_utf8 = target(relative_path_utf8)
71 t1 = scm_iconv(@path_encoding, 'UTF-8', t1_utf8)
72 relative_path = scm_iconv(@path_encoding, 'UTF-8', relative_path_utf8)
73 e1 = scm_iconv(@path_encoding, 'UTF-8', e_utf8)
74 if File.exist?(t1) and # paranoid test
75 %w{file directory}.include?(File.ftype(t1)) and # avoid special types
76 not File.basename(e1).match(/^\.+$/) # avoid . and ..
77 p1 = File.readable?(t1) ? relative_path : ""
78 utf_8_path = scm_iconv('UTF-8', @path_encoding, p1)
79 entries <<
80 Entry.new({ :name => scm_iconv('UTF-8', @path_encoding, File.basename(e1)),
60 # below : list unreadable files, but dont link them. 81 # below : list unreadable files, but dont link them.
61 :path => File.readable?(target) ? relative_path : "", 82 :path => utf_8_path,
62 :kind => (File.directory?(target) ? 'dir' : 'file'), 83 :kind => (File.directory?(t1) ? 'dir' : 'file'),
63 :size => (File.directory?(target) ? nil : [File.size(target)].pack('l').unpack('L').first), 84 :size => (File.directory?(t1) ? nil : [File.size(t1)].pack('l').unpack('L').first),
64 :lastrev => 85 :lastrev =>
65 Revision.new({:time => (File.mtime(target)).localtime, 86 Revision.new({:time => (File.mtime(t1)) })
66 }) 87 })
67 }) if File.exist?(target) and # paranoid test 88 end
68 %w{file directory}.include?(File.ftype(target)) and # avoid special types
69 not File.basename(e).match(/^\.+$/) # avoid . and ..
70 end 89 end
71 entries.sort_by_name 90 entries.sort_by_name
91 rescue => err
92 logger.error "scm: filesystem: error: #{err.message}"
93 raise CommandFailed.new(err.message)
72 end 94 end
73 95
74 def cat(path, identifier=nil) 96 def cat(path, identifier=nil)
75 File.new(target(path), "rb").read 97 p = scm_iconv(@path_encoding, 'UTF-8', target(path))
98 File.new(p, "rb").read
99 rescue => err
100 logger.error "scm: filesystem: error: #{err.message}"
101 raise CommandFailed.new(err.message)
76 end 102 end
77 103
78 private 104 private
79 105
80 # AbstractAdapter::target is implicitly made to quote paths. 106 # AbstractAdapter::target is implicitly made to quote paths.
81 # Here we do not shell-out, so we do not want quotes. 107 # Here we do not shell-out, so we do not want quotes.
82 def target(path=nil) 108 def target(path=nil)
83 #Prevent the use of .. 109 # Prevent the use of ..
84 if path and !path.match(/(^|\/)\.\.(\/|$)/) 110 if path and !path.match(/(^|\/)\.\.(\/|$)/)
85 return "#{self.url}#{without_leading_slash(path)}" 111 return "#{self.url}#{without_leading_slash(path)}"
86 end 112 end
87 return self.url 113 return self.url
88 end 114 end
89
90 end 115 end
91 end 116 end
92 end 117 end
93 end 118 end