Adds Filesystem adapter (patch #1393 by Paul R).

git-svn-id: http://redmine.rubyforge.org/svn/trunk@1508 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang 2008-06-08 15:40:24 +00:00
parent dfe62d7f51
commit e69b4647f2
10 changed files with 254 additions and 1 deletions

View File

@ -98,4 +98,8 @@ module RepositoriesHelper
def bazaar_field_tags(form, repository) def bazaar_field_tags(form, repository)
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.new_record?))) content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.new_record?)))
end end
def filesystem_field_tags(form, repository)
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
end
end end

View File

@ -0,0 +1,43 @@
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# FileSystem adapter
# File written by Paul Rivier, at Demotera.
#
# 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 'redmine/scm/adapters/filesystem_adapter'
class Repository::Filesystem < Repository
attr_protected :root_url
validates_presence_of :url
def scm_adapter
Redmine::Scm::Adapters::FilesystemAdapter
end
def self.scm_name
'Filesystem'
end
def entries(path=nil, identifier=nil)
scm.entries(path, identifier)
end
def fetch_changesets
nil
end
end

View File

@ -24,6 +24,10 @@ Git
--- ---
gunzip < test/fixtures/repositories/git_repository.tar.gz | tar -xv -C tmp/test gunzip < test/fixtures/repositories/git_repository.tar.gz | tar -xv -C tmp/test
FileSystem
----------
gunzip < test/fixtures/repositories/filesystem_repository.tar.gz | tar -xv -C tmp/test
Running Tests Running Tests
============= =============

View File

@ -11,7 +11,7 @@ rescue LoadError
# RMagick is not available # RMagick is not available
end end
REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git ) REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git Filesystem )
# Permissions # Permissions
Redmine::AccessControl.map do |map| Redmine::AccessControl.map do |map|

View File

@ -100,6 +100,16 @@ module Redmine
(path[-1,1] == "/") ? path : "#{path}/" (path[-1,1] == "/") ? path : "#{path}/"
end end
def without_leading_slash(path)
path ||= ''
path.gsub(%r{^/+}, '')
end
def without_trailling_slash(path)
path ||= ''
(path[-1,1] == "/") ? path[0..-2] : path
end
def shell_quote(str) def shell_quote(str)
if RUBY_PLATFORM =~ /mswin/ if RUBY_PLATFORM =~ /mswin/
'"' + str.gsub(/"/, '\\"') + '"' '"' + str.gsub(/"/, '\\"') + '"'

View File

@ -0,0 +1,94 @@
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# FileSystem adapter
# File written by Paul Rivier, at Demotera.
#
# 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 'redmine/scm/adapters/abstract_adapter'
require 'find'
module Redmine
module Scm
module Adapters
class FilesystemAdapter < AbstractAdapter
def initialize(url, root_url=nil, login=nil, password=nil)
@url = with_trailling_slash(url)
end
def format_path_ends(path, leading=true, trailling=true)
path = leading ? with_leading_slash(path) :
without_leading_slash(path)
trailling ? with_trailling_slash(path) :
without_trailling_slash(path)
end
def info
info = Info.new({:root_url => target(),
:lastrev => nil
})
info
rescue CommandFailed
return nil
end
def entries(path="", identifier=nil)
entries = Entries.new
Dir.new(target(path)).each do |e|
relative_path = format_path_ends((format_path_ends(path,
false,
true) + e),
false,false)
target = target(relative_path)
entries <<
Entry.new({ :name => File.basename(e),
# below : list unreadable files, but dont link them.
:path => File.readable?(target) ? relative_path : "",
:kind => (File.directory?(target) ? 'dir' : 'file'),
:size => if (File.directory?(target))
nil else File.size(target) end,
:lastrev =>
Revision.new({:time => (File.mtime(target)).localtime,
})
}) if File.exist?(target) and # paranoid test
%w{file directory}.include?(File.ftype(target)) and # avoid special types
not File.basename(e).match(/^\.+$/) # avoid . and ..
end
entries.sort_by_name
end
def cat(path, identifier=nil)
File.new(target(path)).read
end
private
# AbstractAdapter::target is implicitly made to quote paths.
# Here we do not shell-out, so we do not want quotes.
def target(path=nil)
#Prevent the use of ..
if path and !path.match(/(^|\/)\.\.(\/|$)/)
return "#{self.url}#{without_leading_slash(path)}"
end
return self.url
end
end
end
end
end

Binary file not shown.

View File

@ -0,0 +1,42 @@
require File.dirname(__FILE__) + '/../test_helper'
class FilesystemAdapterTest < Test::Unit::TestCase
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/filesystem_repository'
if File.directory?(REPOSITORY_PATH)
def setup
@adapter = Redmine::Scm::Adapters::FilesystemAdapter.new(REPOSITORY_PATH)
end
def test_entries
assert_equal 2, @adapter.entries.size
assert_equal ["dir", "test"], @adapter.entries.collect(&:name)
assert_equal ["dir", "test"], @adapter.entries(nil).collect(&:name)
assert_equal ["dir", "test"], @adapter.entries("/").collect(&:name)
["dir", "/dir", "/dir/", "dir/"].each do |path|
assert_equal ["subdir", "dirfile"], @adapter.entries(path).collect(&:name)
end
# If y try to use "..", the path is ignored
["/../","dir/../", "..", "../", "/..", "dir/.."].each do |path|
assert_equal ["dir", "test"], @adapter.entries(path).collect(&:name), ".. must be ignored in path argument"
end
end
def test_cat
assert_equal "TEST CAT\n", @adapter.cat("test")
assert_equal "TEST CAT\n", @adapter.cat("/test")
# Revision number is ignored
assert_equal "TEST CAT\n", @adapter.cat("/test", 1)
end
else
puts "Filesystem test repository NOT FOUND. Skipping unit tests !!! See doc/RUNNING_TESTS."
def test_fake; assert true end
end
end

View File

@ -0,0 +1,54 @@
# redMine - project management software
# Copyright (C) 2006-2007 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.
require File.dirname(__FILE__) + '/../test_helper'
class RepositoryFilesystemTest < Test::Unit::TestCase
fixtures :projects
# No '..' in the repository path
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/filesystem_repository'
def setup
@project = Project.find(1)
Setting.enabled_scm << 'Filesystem' unless Setting.enabled_scm.include?('Filesystem')
assert @repository = Repository::Filesystem.create(:project => @project, :url => REPOSITORY_PATH)
end
if File.directory?(REPOSITORY_PATH)
def test_fetch_changesets
@repository.fetch_changesets
@repository.reload
assert_equal 0, @repository.changesets.count
assert_equal 0, @repository.changes.count
end
def test_entries
assert_equal 2, @repository.entries("", 2).size
assert_equal 2, @repository.entries("dir", 3).size
end
def test_cat
assert_equal "TEST CAT\n", @repository.scm.cat("test")
end
else
puts "Filesystem test repository NOT FOUND. Skipping unit tests !!! See doc/RUNNING_TESTS."
def test_fake; assert true end
end
end

View File

@ -51,6 +51,8 @@ class RepositoryTest < Test::Unit::TestCase
repository = Repository::Subversion.new(:project => Project.find(3), :url => "svn://localhost") repository = Repository::Subversion.new(:project => Project.find(3), :url => "svn://localhost")
assert !repository.save assert !repository.save
assert_equal :activerecord_error_invalid, repository.errors.on(:type) assert_equal :activerecord_error_invalid, repository.errors.on(:type)
# re-enable Subversion for following tests
Setting.delete_all
end end
def test_scan_changesets_for_issue_ids def test_scan_changesets_for_issue_ids