Redmine 3.4.4

This commit is contained in:
Manuel Cillero 2018-02-02 22:19:29 +01:00
commit 64924a6376
2112 changed files with 259028 additions and 0 deletions

560
extra/svn/Redmine.pm Normal file
View file

@ -0,0 +1,560 @@
package Apache::Authn::Redmine;
=head1 Apache::Authn::Redmine
Redmine - a mod_perl module to authenticate webdav subversion users
against redmine database
=head1 SYNOPSIS
This module allow anonymous users to browse public project and
registred users to browse and commit their project. Authentication is
done against the redmine database or the LDAP configured in redmine.
This method is far simpler than the one with pam_* and works with all
database without an hassle but you need to have apache/mod_perl on the
svn server.
=head1 INSTALLATION
For this to automagically work, you need to have a recent reposman.rb
(after r860) and if you already use reposman, read the last section to
migrate.
Sorry ruby users but you need some perl modules, at least mod_perl2,
DBI and DBD::mysql (or the DBD driver for you database as it should
work on allmost all databases).
On debian/ubuntu you must do :
aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
If your Redmine users use LDAP authentication, you will also need
Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl
=head1 CONFIGURATION
## This module has to be in your perl path
## eg: /usr/lib/perl5/Apache/Authn/Redmine.pm
PerlLoadModule Apache::Authn::Redmine
<Location /svn>
DAV svn
SVNParentPath "/var/svn"
AuthType Basic
AuthName redmine
Require valid-user
PerlAccessHandler Apache::Authn::Redmine::access_handler
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
## for mysql
RedmineDSN "DBI:mysql:database=databasename;host=my.db.server"
## for postgres
# RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server"
RedmineDbUser "redmine"
RedmineDbPass "password"
## Optional where clause (fulltext search would be slow and
## database dependent).
# RedmineDbWhereClause "and members.role_id IN (1,2)"
## Optional credentials cache size
# RedmineCacheCredsMax 50
</Location>
To be able to browse repository inside redmine, you must add something
like that :
<Location /svn-private>
DAV svn
SVNParentPath "/var/svn"
Order deny,allow
Deny from all
# only allow reading orders
<Limit GET PROPFIND OPTIONS REPORT>
Allow from redmine.server.ip
</Limit>
</Location>
and you will have to use this reposman.rb command line to create repository :
reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
=head1 REPOSITORIES NAMING
A project repository must be named with the project identifier. In case
of multiple repositories for the same project, use the project identifier
and the repository identifier separated with a dot:
/var/svn/foo
/var/svn/foo.otherrepo
=head1 MIGRATION FROM OLDER RELEASES
If you use an older reposman.rb (r860 or before), you need to change
rights on repositories to allow the apache user to read and write
S<them :>
sudo chown -R www-data /var/svn/*
sudo chmod -R u+w /var/svn/*
And you need to upgrade at least reposman.rb (after r860).
=head1 GIT SMART HTTP SUPPORT
Git's smart HTTP protocol (available since Git 1.7.0) will not work with the
above settings. Redmine.pm normally does access control depending on the HTTP
method used: read-only methods are OK for everyone in public projects and
members with read rights in private projects. The rest require membership with
commit rights in the project.
However, this scheme doesn't work for Git's smart HTTP protocol, as it will use
POST even for a simple clone. Instead, read-only requests must be detected using
the full URL (including the query string): anything that doesn't belong to the
git-receive-pack service is read-only.
To activate this mode of operation, add this line inside your <Location /git>
block:
RedmineGitSmartHttp yes
Here's a sample Apache configuration which integrates git-http-backend with
a MySQL database and this new option:
SetEnv GIT_PROJECT_ROOT /var/www/git/
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
<Location /git>
Order allow,deny
Allow from all
AuthType Basic
AuthName Git
Require valid-user
PerlAccessHandler Apache::Authn::Redmine::access_handler
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
# for mysql
RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
RedmineDbUser "redmine"
RedmineDbPass "xxx"
RedmineGitSmartHttp yes
</Location>
Make sure that all the names of the repositories under /var/www/git/ have a
matching identifier for some project: /var/www/git/myproject and
/var/www/git/myproject.git will work. You can put both bare and non-bare
repositories in /var/www/git, though bare repositories are strongly
recommended. You should create them with the rights of the user running Redmine,
like this:
cd /var/www/git
sudo -u user-running-redmine mkdir myproject
cd myproject
sudo -u user-running-redmine git init --bare
Once you have activated this option, you have three options when cloning a
repository:
- Cloning using "http://user@host/git/repo(.git)" works, but will ask for the password
all the time.
- Cloning with "http://user:pass@host/git/repo(.git)" does not have this problem, but
this could reveal accidentally your password to the console in some versions
of Git, and you would have to ensure that .git/config is not readable except
by the owner for each of your projects.
- Use "http://host/git/repo(.git)", and store your credentials in the ~/.netrc
file. This is the recommended solution, as you only have one file to protect
and passwords will not be leaked accidentally to the console.
IMPORTANT NOTE: It is *very important* that the file cannot be read by other
users, as it will contain your password in cleartext. To create the file, you
can use the following commands, replacing yourhost, youruser and yourpassword
with the right values:
touch ~/.netrc
chmod 600 ~/.netrc
echo -e "machine yourhost\nlogin youruser\npassword yourpassword" > ~/.netrc
=cut
use strict;
use warnings FATAL => 'all', NONFATAL => 'redefine';
use DBI;
use Digest::SHA;
# optional module for LDAP authentication
my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
use Apache2::Module;
use Apache2::Access;
use Apache2::ServerRec qw();
use Apache2::RequestRec qw();
use Apache2::RequestUtil qw();
use Apache2::Const qw(:common :override :cmd_how);
use APR::Pool ();
use APR::Table ();
# use Apache2::Directive qw();
my @directives = (
{
name => 'RedmineDSN',
req_override => OR_AUTHCFG,
args_how => TAKE1,
errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
},
{
name => 'RedmineDbUser',
req_override => OR_AUTHCFG,
args_how => TAKE1,
},
{
name => 'RedmineDbPass',
req_override => OR_AUTHCFG,
args_how => TAKE1,
},
{
name => 'RedmineDbWhereClause',
req_override => OR_AUTHCFG,
args_how => TAKE1,
},
{
name => 'RedmineCacheCredsMax',
req_override => OR_AUTHCFG,
args_how => TAKE1,
errmsg => 'RedmineCacheCredsMax must be decimal number',
},
{
name => 'RedmineGitSmartHttp',
req_override => OR_AUTHCFG,
args_how => TAKE1,
},
);
sub RedmineDSN {
my ($self, $parms, $arg) = @_;
$self->{RedmineDSN} = $arg;
my $query = "SELECT
users.hashed_password, users.salt, users.auth_source_id, roles.permissions, projects.status
FROM projects, users, roles
WHERE
users.login=?
AND projects.identifier=?
AND EXISTS (SELECT 1 FROM enabled_modules em WHERE em.project_id = projects.id AND em.name = 'repository')
AND users.type='User'
AND users.status=1
AND (
roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id)
OR
(cast(projects.is_public as CHAR) IN ('t', '1')
AND (roles.builtin=1
OR roles.id IN (SELECT member_roles.role_id FROM members, member_roles, users g
WHERE members.user_id = g.id AND members.project_id = projects.id AND members.id = member_roles.member_id
AND g.type = 'GroupNonMember'))
)
)
AND roles.permissions IS NOT NULL";
$self->{RedmineQuery} = trim($query);
}
sub RedmineDbUser { set_val('RedmineDbUser', @_); }
sub RedmineDbPass { set_val('RedmineDbPass', @_); }
sub RedmineDbWhereClause {
my ($self, $parms, $arg) = @_;
$self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
}
sub RedmineCacheCredsMax {
my ($self, $parms, $arg) = @_;
if ($arg) {
$self->{RedmineCachePool} = APR::Pool->new;
$self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg);
$self->{RedmineCacheCredsCount} = 0;
$self->{RedmineCacheCredsMax} = $arg;
}
}
sub RedmineGitSmartHttp {
my ($self, $parms, $arg) = @_;
$arg = lc $arg;
if ($arg eq "yes" || $arg eq "true") {
$self->{RedmineGitSmartHttp} = 1;
} else {
$self->{RedmineGitSmartHttp} = 0;
}
}
sub trim {
my $string = shift;
$string =~ s/\s{2,}/ /g;
return $string;
}
sub set_val {
my ($key, $self, $parms, $arg) = @_;
$self->{$key} = $arg;
}
Apache2::Module::add(__PACKAGE__, \@directives);
my %read_only_methods = map { $_ => 1 } qw/GET HEAD PROPFIND REPORT OPTIONS/;
sub request_is_read_only {
my ($r) = @_;
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
# Do we use Git's smart HTTP protocol, or not?
if (defined $cfg->{RedmineGitSmartHttp} and $cfg->{RedmineGitSmartHttp}) {
my $uri = $r->unparsed_uri;
my $location = $r->location;
my $is_read_only = $uri !~ m{^$location/*[^/]+/+(info/refs\?service=)?git\-receive\-pack$}o;
return $is_read_only;
} else {
# Standard behaviour: check the HTTP method
my $method = $r->method;
return defined $read_only_methods{$method};
}
}
sub access_handler {
my $r = shift;
unless ($r->some_auth_required) {
$r->log_reason("No authentication has been configured");
return FORBIDDEN;
}
return OK unless request_is_read_only($r);
my $project_id = get_project_identifier($r);
if (is_public_project($project_id, $r) && anonymous_allowed_to_browse_repository($project_id, $r)) {
$r->user("");
$r->set_handlers(PerlAuthenHandler => [\&OK]);
}
return OK
}
sub authen_handler {
my $r = shift;
my ($res, $redmine_pass) = $r->get_basic_auth_pw();
return $res unless $res == OK;
if (is_member($r->user, $redmine_pass, $r)) {
return OK;
} else {
$r->note_auth_failure();
return DECLINED;
}
}
# check if authentication is forced
sub is_authentication_forced {
my $r = shift;
my $dbh = connect_database($r);
my $sth = $dbh->prepare(
"SELECT value FROM settings where settings.name = 'login_required';"
);
$sth->execute();
my $ret = 0;
if (my @row = $sth->fetchrow_array) {
if ($row[0] eq "1" || $row[0] eq "t") {
$ret = 1;
}
}
$sth->finish();
undef $sth;
$dbh->disconnect();
undef $dbh;
$ret;
}
sub is_public_project {
my $project_id = shift;
my $r = shift;
if (is_authentication_forced($r)) {
return 0;
}
my $dbh = connect_database($r);
my $sth = $dbh->prepare(
"SELECT is_public FROM projects
WHERE projects.identifier = ? AND projects.status <> 9
AND EXISTS (SELECT 1 FROM enabled_modules em WHERE em.project_id = projects.id AND em.name = 'repository');"
);
$sth->execute($project_id);
my $ret = 0;
if (my @row = $sth->fetchrow_array) {
if ($row[0] eq "1" || $row[0] eq "t") {
$ret = 1;
}
}
$sth->finish();
undef $sth;
$dbh->disconnect();
undef $dbh;
$ret;
}
sub anonymous_allowed_to_browse_repository {
my $project_id = shift;
my $r = shift;
my $dbh = connect_database($r);
my $sth = $dbh->prepare(
"SELECT permissions FROM roles WHERE permissions like '%browse_repository%'
AND (roles.builtin = 2
OR roles.id IN (SELECT member_roles.role_id FROM projects, members, member_roles, users
WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id
AND projects.identifier = ? AND users.type = 'GroupAnonymous'));"
);
$sth->execute($project_id);
my $ret = 0;
if (my @row = $sth->fetchrow_array) {
if ($row[0] =~ /:browse_repository/) {
$ret = 1;
}
}
$sth->finish();
undef $sth;
$dbh->disconnect();
undef $dbh;
$ret;
}
# perhaps we should use repository right (other read right) to check public access.
# it could be faster BUT it doesn't work for the moment.
# sub is_public_project_by_file {
# my $project_id = shift;
# my $r = shift;
# my $tree = Apache2::Directive::conftree();
# my $node = $tree->lookup('Location', $r->location);
# my $hash = $node->as_hash;
# my $svnparentpath = $hash->{SVNParentPath};
# my $repos_path = $svnparentpath . "/" . $project_id;
# return 1 if (stat($repos_path))[2] & 00007;
# }
sub is_member {
my $redmine_user = shift;
my $redmine_pass = shift;
my $r = shift;
my $project_id = get_project_identifier($r);
my $pass_digest = Digest::SHA::sha1_hex($redmine_pass);
my $access_mode = request_is_read_only($r) ? "R" : "W";
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
my $usrprojpass;
if ($cfg->{RedmineCacheCredsMax}) {
$usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
}
my $dbh = connect_database($r);
my $query = $cfg->{RedmineQuery};
my $sth = $dbh->prepare($query);
$sth->execute($redmine_user, $project_id);
my $ret;
while (my ($hashed_password, $salt, $auth_source_id, $permissions, $project_status) = $sth->fetchrow_array) {
if ($project_status eq "9" || ($project_status ne "1" && $access_mode eq "W")) {
last;
}
unless ($auth_source_id) {
my $method = $r->method;
my $salted_password = Digest::SHA::sha1_hex($salt.$pass_digest);
if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
$ret = 1;
last;
}
} elsif ($CanUseLDAPAuth) {
my $sthldap = $dbh->prepare(
"SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
);
$sthldap->execute($auth_source_id);
while (my @rowldap = $sthldap->fetchrow_array) {
my $bind_as = $rowldap[3] ? $rowldap[3] : "";
my $bind_pw = $rowldap[4] ? $rowldap[4] : "";
if ($bind_as =~ m/\$login/) {
# replace $login with $redmine_user and use $redmine_pass
$bind_as =~ s/\$login/$redmine_user/g;
$bind_pw = $redmine_pass
}
my $ldap = Authen::Simple::LDAP->new(
host => ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0],
port => $rowldap[1],
basedn => $rowldap[5],
binddn => $bind_as,
bindpw => $bind_pw,
filter => "(".$rowldap[6]."=%s)"
);
my $method = $r->method;
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
}
$sthldap->finish();
undef $sthldap;
}
}
$sth->finish();
undef $sth;
$dbh->disconnect();
undef $dbh;
if ($cfg->{RedmineCacheCredsMax} and $ret) {
if (defined $usrprojpass) {
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
} else {
if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
$cfg->{RedmineCacheCredsCount}++;
} else {
$cfg->{RedmineCacheCreds}->clear();
$cfg->{RedmineCacheCredsCount} = 0;
}
}
}
$ret;
}
sub get_project_identifier {
my $r = shift;
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
my $location = $r->location;
$location =~ s/\.git$// if (defined $cfg->{RedmineGitSmartHttp} and $cfg->{RedmineGitSmartHttp});
my ($identifier) = $r->uri =~ m{$location/*([^/.]+)};
$identifier;
}
sub connect_database {
my $r = shift;
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
}
1;

288
extra/svn/reposman.rb Executable file
View file

@ -0,0 +1,288 @@
#!/usr/bin/env ruby
require 'optparse'
require 'find'
require 'etc'
require 'rubygems'
Version = "1.5"
SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem )
$verbose = 0
$quiet = false
$redmine_host = ''
$repos_base = ''
$svn_owner = 'root'
$svn_group = 'root'
$use_groupid = true
$svn_url = false
$test = false
$force = false
$scm = 'Subversion'
def log(text, options={})
level = options[:level] || 0
puts text unless $quiet or level > $verbose
exit 1 if options[:exit]
end
def system_or_raise(command)
raise "\"#{command}\" failed" unless system command
end
module SCM
module Subversion
def self.create(path)
system_or_raise "svnadmin create #{path}"
end
end
module Git
def self.create(path)
Dir.mkdir path
Dir.chdir(path) do
system_or_raise "git --bare init --shared"
system_or_raise "git update-server-info"
end
end
end
end
def read_key_from_file(filename)
begin
$api_key = File.read(filename).strip
rescue Exception => e
$stderr.puts "Unable to read the key from #{filename}: #{e.message}"
exit 1
end
end
def set_scm(scm)
$scm = scm.capitalize
unless SUPPORTED_SCM.include?($scm)
log("Invalid SCM: #{$scm}\nValid SCM are: #{SUPPORTED_SCM.join(', ')}", :exit => true)
end
end
optparse = OptionParser.new do |opts|
opts.banner = "Usage: reposman.rb [OPTIONS...] -s [DIR] -r [HOST] -k [KEY]"
opts.separator("")
opts.separator("Manages your repositories with Redmine.")
opts.separator("")
opts.separator("Required arguments:")
opts.on("-s", "--svn-dir DIR", "use DIR as base directory for svn repositories") {|v| $repos_base = v}
opts.on("-r", "--redmine-host HOST","assume Redmine is hosted on HOST. Examples:",
" -r redmine.example.net",
" -r http://redmine.example.net",
" -r https://redmine.example.net") {|v| $redmine_host = v}
opts.on("-k", "--key KEY", "use KEY as the Redmine API key",
"(you can use --key-file option as an alternative)") {|v| $api_key = v}
opts.separator("")
opts.separator("Options:")
opts.on("-o", "--owner OWNER", "owner of the repository. using the rails login",
"allows users to browse the repository within",
"Redmine even for private projects. If you want to",
"share repositories through Redmine.pm, you need",
"to use the apache owner.") {|v| $svn_owner = v; $use_groupid = false}
opts.on("-g", "--group GROUP", "group of the repository (default: root)") {|v| $svn_group = v; $use_groupid = false}
opts.on("-u", "--url URL", "the base url Redmine will use to access your",
"repositories. This option is used to register",
"the repositories in Redmine automatically. The",
"project identifier will be appended to this url.",
"Examples:",
" -u https://example.net/svn",
" -u file:///var/svn/",
"if this option isn't set, reposman won't register",
"the repositories in Redmine") {|v| $svn_url = v}
opts.on( "--scm SCM", "the kind of SCM repository you want to create",
"(and register) in Redmine (default: Subversion).",
"reposman is able to create Git and Subversion",
"repositories.",
"For all other kind, you must specify a --command",
"option") {|v| set_scm(v)}
opts.on("-c", "--command COMMAND", "use this command instead of `svnadmin create` to",
"create a repository. This option can be used to",
"create repositories other than subversion and git",
"kind.",
"This command override the default creation for",
"git and subversion.") {|v| $command = v}
opts.on( "--key-file FILE", "path to a file that contains the Redmine API key",
"(use this option instead of --key if you don't",
"want the key to appear in the command line)") {|v| read_key_from_file(v)}
opts.on("-t", "--test", "only show what should be done") {$test = true}
opts.on("-f", "--force", "force repository creation even if the project", "repository is already declared in Redmine") {$force = true}
opts.on("-v", "--verbose", "verbose") {$verbose += 1}
opts.on("-V", "--version", "show version and exit") {puts Version; exit}
opts.on("-h", "--help", "show help and exit") {puts opts; exit 1}
opts.on("-q", "--quiet", "no log") {$quiet = true}
opts.separator("")
opts.separator("Examples:")
opts.separator(" reposman.rb --svn-dir=/var/svn --redmine-host=redmine.host")
opts.separator(" reposman.rb -s /var/git -r redmine.host -u http://git.host --scm git")
opts.separator("")
opts.separator("You can find more information on the redmine's wiki:\nhttp://www.redmine.org/projects/redmine/wiki/HowTos")
opts.summary_width = 25
end
optparse.parse!
if $test
log("running in test mode")
end
# Make sure command is overridden if SCM vendor is not handled internally (for the moment Subversion and Git)
if $command.nil?
begin
scm_module = SCM.const_get($scm)
rescue
log("Please use --command option to specify how to create a #{$scm} repository.", :exit => true)
end
end
$svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
if ($redmine_host.empty? or $repos_base.empty?)
puts "Some arguments are missing. Use reposman.rb --help for getting help."
exit 1
end
unless File.directory?($repos_base)
log("directory '#{$repos_base}' doesn't exists", :exit => true)
end
begin
require 'active_resource'
rescue LoadError
log("This script requires activeresource.\nRun 'gem install activeresource' to install it.", :exit => true)
end
class Project < ActiveResource::Base
self.headers["User-agent"] = "Redmine repository manager/#{Version}"
self.format = :json
end
log("querying Redmine for active projects with repository module enabled...", :level => 1);
$redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
$redmine_host.gsub!(/\/$/, '')
Project.site = "#{$redmine_host}/sys";
begin
# Get all active projects that have the Repository module enabled
projects = Project.find(:all, :params => {:key => $api_key})
rescue ActiveResource::ForbiddenAccess
log("Request was denied by your Redmine server. Make sure that 'WS for repository management' is enabled in application settings and that you provided the correct API key.")
rescue => e
log("Unable to connect to #{Project.site}: #{e}", :exit => true)
end
if projects.nil?
log('No project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
end
log("retrieved #{projects.size} projects", :level => 1)
def set_owner_and_rights(project, repos_path, &block)
if mswin?
yield if block_given?
else
uid, gid = Etc.getpwnam($svn_owner).uid, ($use_groupid ? Etc.getgrnam(project.identifier).gid : Etc.getgrnam($svn_group).gid)
right = project.is_public ? 0775 : 0770
yield if block_given?
Find.find(repos_path) do |f|
File.chmod right, f
File.chown uid, gid, f
end
end
end
def other_read_right?(file)
(File.stat(file).mode & 0007).zero? ? false : true
end
def owner_name(file)
mswin? ?
$svn_owner :
Etc.getpwuid( File.stat(file).uid ).name
end
def mswin?
(RUBY_PLATFORM =~ /(:?mswin|mingw)/) || (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i)
end
projects.each do |project|
if project.identifier.empty?
log("\tno identifier for project #{project.name}")
next
elsif not project.identifier.match(/^[a-z0-9\-_]+$/)
log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
next;
end
log("processing project #{project.identifier} (#{project.name})", :level => 1)
repos_path = File.join($repos_base, project.identifier).gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR)
if File.directory?(repos_path)
# we must verify that repository has the good owner and the good
# rights before leaving
other_read = other_read_right?(repos_path)
owner = owner_name(repos_path)
next if project.is_public == other_read and owner == $svn_owner
if $test
log("\tchange mode on #{repos_path}")
next
end
begin
set_owner_and_rights(project, repos_path)
rescue Errno::EPERM => e
log("\tunable to change mode on #{repos_path} : #{e}\n")
next
end
log("\tmode change on #{repos_path}");
else
# if repository is already declared in redmine, we don't create
# unless user use -f with reposman
if $force == false and project.respond_to?(:repository)
log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1)
next
end
project.is_public ? File.umask(0002) : File.umask(0007)
if $test
log("\trepository #{repos_path} created")
log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}") if $svn_url;
next
end
begin
set_owner_and_rights(project, repos_path) do
if scm_module.nil?
system_or_raise "#{$command} #{repos_path}"
else
scm_module.create(repos_path)
end
end
rescue => e
log("\tunable to create #{repos_path} : #{e}\n")
next
end
log("\trepository #{repos_path} created");
if $svn_url
begin
project.post(:repository, :vendor => $scm, :repository => {:url => "#{$svn_url}#{project.identifier}"}, :key => $api_key)
log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}");
rescue => e
log("\trepository #{repos_path} not registered in Redmine: #{e.message}");
end
end
end
end