|
|
@@ -2,7 +2,7 @@ |
|
|
|
|
|
|
|
# == Synopsis |
|
|
|
# |
|
|
|
# reposman: manages your svn repositories with redMine |
|
|
|
# reposman: manages your svn repositories with Redmine |
|
|
|
# |
|
|
|
# == Usage |
|
|
|
# |
|
|
@@ -16,14 +16,28 @@ |
|
|
|
# use DIR as base directory for svn repositories |
|
|
|
# |
|
|
|
# -r, --redmine-host=HOST |
|
|
|
# assume redMine is hosted on HOST. |
|
|
|
# assume Redmine is hosted on HOST. |
|
|
|
# you can use : |
|
|
|
# * -r redmine.mydomain.foo (will add http://) |
|
|
|
# * -r http://redmine.mydomain.foo |
|
|
|
# * -r https://mydomain.foo/redmine |
|
|
|
# |
|
|
|
# == Options |
|
|
|
# |
|
|
|
# |
|
|
|
# -o, --owner=OWNER |
|
|
|
# owner of the repository. using the rails login allow user to browse |
|
|
|
# the repository in Redmine even for private project |
|
|
|
# |
|
|
|
# -u, --url=URL |
|
|
|
# the base url Redmine will use to access your repositories. This |
|
|
|
# will be used to register the repository in Redmine so that user |
|
|
|
# doesn't need to do anything. reposman will add the identifier to this url : |
|
|
|
# |
|
|
|
# -u https://my.svn.server/my/reposity/root # if the repository can be access by http |
|
|
|
# -u file:///var/svn/ # if the repository is local |
|
|
|
# if this option isn't set, reposman won't register the repository |
|
|
|
# |
|
|
|
# |
|
|
|
# -h, --help: |
|
|
|
# show help and exit |
|
|
|
# |
|
|
@@ -48,6 +62,8 @@ Version = "1.0" |
|
|
|
opts = GetoptLong.new( |
|
|
|
['--svn-dir', '-s', GetoptLong::REQUIRED_ARGUMENT], |
|
|
|
['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT], |
|
|
|
['--owner', '-o', GetoptLong::REQUIRED_ARGUMENT], |
|
|
|
['--url', '-u', GetoptLong::REQUIRED_ARGUMENT], |
|
|
|
['--verbose', '-v', GetoptLong::NO_ARGUMENT], |
|
|
|
['--version', '-V', GetoptLong::NO_ARGUMENT], |
|
|
|
['--help' , '-h', GetoptLong::NO_ARGUMENT], |
|
|
@@ -58,6 +74,8 @@ $verbose = 0 |
|
|
|
$quiet = false |
|
|
|
$redmine_host = '' |
|
|
|
$repos_base = '' |
|
|
|
$svn_owner = 'root' |
|
|
|
$svn_url = false |
|
|
|
|
|
|
|
def log(text,level=0, exit=false) |
|
|
|
return if $quiet or level > $verbose |
|
|
@@ -68,8 +86,10 @@ end |
|
|
|
begin |
|
|
|
opts.each do |opt, arg| |
|
|
|
case opt |
|
|
|
when '--svn-dir'; $repos_base = arg.dup |
|
|
|
when '--svn-dir'; $repos_base = arg.dup |
|
|
|
when '--redmine-host'; $redmine_host = arg.dup |
|
|
|
when '--owner'; $svn_owner = arg.dup |
|
|
|
when '--url'; $svn_url = arg.dup |
|
|
|
when '--verbose'; $verbose += 1 |
|
|
|
when '--version'; puts Version; exit |
|
|
|
when '--help'; RDoc::usage |
|
|
@@ -80,6 +100,8 @@ rescue |
|
|
|
exit 1 |
|
|
|
end |
|
|
|
|
|
|
|
$svn_url += "/" if $svn_url and not $svn_url.match(/\/$/) |
|
|
|
|
|
|
|
if ($redmine_host.empty? or $repos_base.empty?) |
|
|
|
RDoc::usage |
|
|
|
end |
|
|
@@ -88,7 +110,7 @@ unless File.directory?($repos_base) |
|
|
|
log("directory '#{$repos_base}' doesn't exists", 0, true) |
|
|
|
end |
|
|
|
|
|
|
|
log("querying redMine for projects...", 1); |
|
|
|
log("querying Redmine for projects...", 1); |
|
|
|
|
|
|
|
$redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://") |
|
|
|
$redmine_host.gsub!(/\/$/, '') |
|
|
@@ -109,28 +131,53 @@ end |
|
|
|
|
|
|
|
log("retrieved #{projects.size} projects", 1) |
|
|
|
|
|
|
|
projects.each do |p| |
|
|
|
log("treating project #{p.name}", 1) |
|
|
|
def set_owner_and_rights(project, repos_path, &block) |
|
|
|
if RUBY_PLATFORM =~ /mswin/ |
|
|
|
yield if block_given? |
|
|
|
else |
|
|
|
uid, gid = Etc.getpwnam($svn_owner).uid, Etc.getgrnam(project.identifier).gid |
|
|
|
right = project.is_public ? 0575 : 0570 |
|
|
|
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) |
|
|
|
RUBY_PLATFORM =~ /mswin/ ? |
|
|
|
$svn_owner : |
|
|
|
Etc.getpwuid( File.stat(file).uid ).name |
|
|
|
end |
|
|
|
|
|
|
|
if p.identifier.empty? |
|
|
|
log("\tno identifier for project #{p.name}") |
|
|
|
projects.each do |project| |
|
|
|
log("treating project #{project.name}", 1) |
|
|
|
|
|
|
|
if project.identifier.empty? |
|
|
|
log("\tno identifier for project #{project.name}") |
|
|
|
next |
|
|
|
elsif not p.identifier.match(/^[a-z0-9\-]+$/) |
|
|
|
log("\tinvalid identifier for project #{p.name} : #{p.identifier}"); |
|
|
|
elsif not project.identifier.match(/^[a-z0-9\-]+$/) |
|
|
|
log("\tinvalid identifier for project #{project.name} : #{project.identifier}"); |
|
|
|
next; |
|
|
|
end |
|
|
|
|
|
|
|
repos_path = $repos_base + "/" + p.identifier |
|
|
|
repos_path = $repos_base + "/" + project.identifier |
|
|
|
|
|
|
|
if File.directory?(repos_path) |
|
|
|
|
|
|
|
other_read = (File.stat(repos_path).mode & 0007).zero? ? false : true |
|
|
|
next if p.is_public == other_read |
|
|
|
|
|
|
|
right = p.is_public ? 0775 : 0770 |
|
|
|
# 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 |
|
|
|
|
|
|
|
begin |
|
|
|
Find.find(repos_path) { |f| File.chmod right, f } |
|
|
|
set_owner_and_rights(project, repos_path) |
|
|
|
rescue Errno::EPERM => e |
|
|
|
log("\tunable to change mode on #{repos_path} : #{e}\n") |
|
|
|
next |
|
|
@@ -139,17 +186,26 @@ projects.each do |p| |
|
|
|
log("\tmode change on #{repos_path}"); |
|
|
|
|
|
|
|
else |
|
|
|
p.is_public ? File.umask(0002) : File.umask(0007) |
|
|
|
project.is_public ? File.umask(0202) : File.umask(0207) |
|
|
|
|
|
|
|
begin |
|
|
|
uid, gid = Etc.getpwnam("root").uid, Etc.getgrnam(p.identifier).gid |
|
|
|
raise "svnadmin create #{repos_path} failed" unless system("svnadmin", "create", repos_path) |
|
|
|
Find.find(repos_path) { |f| File.chown uid, gid, f } |
|
|
|
set_owner_and_rights(project, repos_path) do |
|
|
|
raise "svnadmin create #{repos_path} failed" unless system("svnadmin", "create", repos_path) |
|
|
|
end |
|
|
|
rescue => e |
|
|
|
log("\tunable to create #{repos_path} : #{e}\n") |
|
|
|
next |
|
|
|
end |
|
|
|
|
|
|
|
if $svn_url |
|
|
|
ret = soap.RepositoryCreated project.identifier, "#{$svn_url}#{project.identifier}" |
|
|
|
if ret > 0 |
|
|
|
log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}"); |
|
|
|
else |
|
|
|
log("\trepository #{repos_path} not registered in Redmine. Look in your log to find why."); |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
log("\trepository #{repos_path} created"); |
|
|
|
end |
|
|
|
|