To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / .svn / pristine / 8e / 8ea72f11aca3633b56300020cda571d3f13b20ac.svn-base @ 1297:0a574315af3e

History | View | Annotate | Download (11.1 KB)

1
#!/usr/bin/env ruby
2

    
3
# == Synopsis
4
#
5
# reposman: manages your repositories with Redmine
6
#
7
# == Usage
8
#
9
#    reposman [OPTIONS...] -s [DIR] -r [HOST]
10
#
11
#  Examples:
12
#    reposman --svn-dir=/var/svn --redmine-host=redmine.example.net --scm subversion
13
#    reposman -s /var/git -r redmine.example.net -u http://svn.example.net --scm git
14
#
15
# == Arguments (mandatory)
16
#
17
#   -s, --svn-dir=DIR         use DIR as base directory for svn repositories
18
#   -r, --redmine-host=HOST   assume Redmine is hosted on HOST. Examples:
19
#                             -r redmine.example.net
20
#                             -r http://redmine.example.net
21
#                             -r https://example.net/redmine
22
#   -k, --key=KEY             use KEY as the Redmine API key (you can use the
23
#                             --key-file option as an alternative)
24
#
25
# == Options
26
#
27
#   -o, --owner=OWNER         owner of the repository. using the rails login
28
#                             allow user to browse the repository within
29
#                             Redmine even for private project. If you want to
30
#                             share repositories through Redmine.pm, you need
31
#                             to use the apache owner.
32
#   -g, --group=GROUP         group of the repository. (default: root)
33
#   --scm=SCM                 the kind of SCM repository you want to create (and
34
#                             register) in Redmine (default: Subversion).
35
#                             reposman is able to create Git and Subversion
36
#                             repositories. For all other kind, you must specify
37
#                             a --command option
38
#   -u, --url=URL             the base url Redmine will use to access your
39
#                             repositories. This option is used to automatically
40
#                             register the repositories in Redmine. The project
41
#                             identifier will be appended to this url. Examples:
42
#                             -u https://example.net/svn
43
#                             -u file:///var/svn/
44
#                             if this option isn't set, reposman won't register
45
#                             the repositories in Redmine
46
#   -c, --command=COMMAND     use this command instead of "svnadmin create" to
47
#                             create a repository. This option can be used to
48
#                             create repositories other than subversion and git
49
#                             kind.
50
#                             This command override the default creation for git
51
#                             and subversion.
52
#   -f, --force               force repository creation even if the project
53
#                             repository is already declared in Redmine
54
#       --key-file=PATH       path to a file that contains the Redmine API key
55
#                             (use this option instead of --key if you don't 
56
#                             the key to appear in the command line)
57
#   -t, --test                only show what should be done
58
#   -h, --help                show help and exit
59
#   -v, --verbose             verbose
60
#   -V, --version             print version and exit
61
#   -q, --quiet               no log
62
#
63
# == References
64
#
65
# You can find more information on the redmine's wiki : http://www.redmine.org/wiki/redmine/HowTos
66

    
67

    
68
require 'getoptlong'
69
require 'rdoc/usage'
70
require 'find'
71
require 'etc'
72

    
73
Version = "1.3"
74
SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem )
75

    
76
opts = GetoptLong.new(
77
                      ['--svn-dir',      '-s', GetoptLong::REQUIRED_ARGUMENT],
78
                      ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
79
                      ['--key',          '-k', GetoptLong::REQUIRED_ARGUMENT],
80
                      ['--key-file',           GetoptLong::REQUIRED_ARGUMENT],
81
                      ['--owner',        '-o', GetoptLong::REQUIRED_ARGUMENT],
82
                      ['--group',        '-g', GetoptLong::REQUIRED_ARGUMENT],
83
                      ['--url',          '-u', GetoptLong::REQUIRED_ARGUMENT],
84
                      ['--command' ,     '-c', GetoptLong::REQUIRED_ARGUMENT],
85
                      ['--scm',                GetoptLong::REQUIRED_ARGUMENT],
86
                      ['--test',         '-t', GetoptLong::NO_ARGUMENT],
87
                      ['--force',        '-f', GetoptLong::NO_ARGUMENT],
88
                      ['--verbose',      '-v', GetoptLong::NO_ARGUMENT],
89
                      ['--version',      '-V', GetoptLong::NO_ARGUMENT],
90
                      ['--help'   ,      '-h', GetoptLong::NO_ARGUMENT],
91
                      ['--quiet'  ,      '-q', GetoptLong::NO_ARGUMENT]
92
                      )
93

    
94
$verbose      = 0
95
$quiet        = false
96
$redmine_host = ''
97
$repos_base   = ''
98
$svn_owner    = 'root'
99
$svn_group    = 'root'
100
$use_groupid  = true
101
$svn_url      = false
102
$test         = false
103
$force        = false
104
$scm          = 'Subversion'
105

    
106
def log(text, options={})
107
  level = options[:level] || 0
108
  puts text unless $quiet or level > $verbose
109
  exit 1 if options[:exit]
110
end
111

    
112
def system_or_raise(command)
113
  raise "\"#{command}\" failed" unless system command
114
end
115

    
116
module SCM
117

    
118
  module Subversion
119
    def self.create(path)
120
      system_or_raise "svnadmin create #{path}"
121
    end
122
  end
123

    
124
  module Git
125
    def self.create(path)
126
      Dir.mkdir path
127
      Dir.chdir(path) do
128
        system_or_raise "git --bare init --shared"
129
        system_or_raise "git update-server-info"
130
      end
131
    end
132
  end
133

    
134
end
135

    
136
begin
137
  opts.each do |opt, arg|
138
    case opt
139
    when '--svn-dir';        $repos_base   = arg.dup
140
    when '--redmine-host';   $redmine_host = arg.dup
141
    when '--key';            $api_key      = arg.dup
142
    when '--key-file'
143
      begin
144
        $api_key = File.read(arg).strip
145
      rescue Exception => e
146
        $stderr.puts "Unable to read the key from #{arg}: #{e.message}"
147
        exit 1
148
      end
149
    when '--owner';          $svn_owner    = arg.dup; $use_groupid = false;
150
    when '--group';          $svn_group    = arg.dup; $use_groupid = false;
151
    when '--url';            $svn_url      = arg.dup
152
    when '--scm';            $scm          = arg.dup.capitalize; log("Invalid SCM: #{$scm}", :exit => true) unless SUPPORTED_SCM.include?($scm)
153
    when '--command';        $command =      arg.dup
154
    when '--verbose';        $verbose += 1
155
    when '--test';           $test = true
156
    when '--force';          $force = true
157
    when '--version';        puts Version; exit
158
    when '--help';           RDoc::usage
159
    when '--quiet';          $quiet = true
160
    end
161
  end
162
rescue
163
  exit 1
164
end
165

    
166
if $test
167
  log("running in test mode")
168
end
169

    
170
# Make sure command is overridden if SCM vendor is not handled internally (for the moment Subversion and Git)
171
if $command.nil?
172
  begin
173
    scm_module = SCM.const_get($scm)
174
  rescue
175
    log("Please use --command option to specify how to create a #{$scm} repository.", :exit => true)
176
  end
177
end
178

    
179
$svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
180

    
181
if ($redmine_host.empty? or $repos_base.empty?)
182
  RDoc::usage
183
end
184

    
185
unless File.directory?($repos_base)
186
  log("directory '#{$repos_base}' doesn't exists", :exit => true)
187
end
188

    
189
begin
190
  require 'active_resource'
191
rescue LoadError
192
  log("This script requires activeresource.\nRun 'gem install activeresource' to install it.", :exit => true)
193
end
194

    
195
class Project < ActiveResource::Base
196
  self.headers["User-agent"] = "Redmine repository manager/#{Version}"
197
  self.format = :xml
198
end
199

    
200
log("querying Redmine for projects...", :level => 1);
201

    
202
$redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
203
$redmine_host.gsub!(/\/$/, '')
204

    
205
Project.site = "#{$redmine_host}/sys";
206

    
207
begin
208
  # Get all active projects that have the Repository module enabled
209
  projects = Project.find(:all, :params => {:key => $api_key})
210
rescue ActiveResource::ForbiddenAccess
211
  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.")
212
rescue => e
213
  log("Unable to connect to #{Project.site}: #{e}", :exit => true)
214
end
215

    
216
if projects.nil?
217
  log('No project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
218
end
219

    
220
log("retrieved #{projects.size} projects", :level => 1)
221

    
222
def set_owner_and_rights(project, repos_path, &block)
223
  if mswin?
224
    yield if block_given?
225
  else
226
    uid, gid = Etc.getpwnam($svn_owner).uid, ($use_groupid ? Etc.getgrnam(project.identifier).gid : Etc.getgrnam($svn_group).gid)
227
    right = project.is_public ? 0775 : 0770
228
    yield if block_given?
229
    Find.find(repos_path) do |f|
230
      File.chmod right, f
231
      File.chown uid, gid, f
232
    end
233
  end
234
end
235

    
236
def other_read_right?(file)
237
  (File.stat(file).mode & 0007).zero? ? false : true
238
end
239

    
240
def owner_name(file)
241
  mswin? ?
242
    $svn_owner :
243
    Etc.getpwuid( File.stat(file).uid ).name
244
end
245

    
246
def mswin?
247
  (RUBY_PLATFORM =~ /(:?mswin|mingw)/) || (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i)
248
end
249

    
250
projects.each do |project|
251
  log("treating project #{project.name}", :level => 1)
252

    
253
  if project.identifier.empty?
254
    log("\tno identifier for project #{project.name}")
255
    next
256
  elsif not project.identifier.match(/^[a-z0-9\-]+$/)
257
    log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
258
    next;
259
  end
260

    
261
  repos_path = File.join($repos_base, project.identifier).gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR)
262

    
263
  if File.directory?(repos_path)
264
    # we must verify that repository has the good owner and the good
265
    # rights before leaving
266
    other_read = other_read_right?(repos_path)
267
    owner      = owner_name(repos_path)
268
    next if project.is_public == other_read and owner == $svn_owner
269

    
270
    if $test
271
      log("\tchange mode on #{repos_path}")
272
      next
273
    end
274

    
275
    begin
276
      set_owner_and_rights(project, repos_path)
277
    rescue Errno::EPERM => e
278
      log("\tunable to change mode on #{repos_path} : #{e}\n")
279
      next
280
    end
281

    
282
    log("\tmode change on #{repos_path}");
283

    
284
  else
285
    # if repository is already declared in redmine, we don't create
286
    # unless user use -f with reposman
287
    if $force == false and project.respond_to?(:repository)
288
      log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1)
289
      next
290
    end
291

    
292
    project.is_public ? File.umask(0002) : File.umask(0007)
293

    
294
    if $test
295
      log("\tcreate repository #{repos_path}")
296
      log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}") if $svn_url;
297
      next
298
    end
299

    
300
    begin
301
      set_owner_and_rights(project, repos_path) do
302
        if scm_module.nil?
303
          system_or_raise "#{$command} #{repos_path}"
304
        else
305
          scm_module.create(repos_path)
306
        end
307
      end
308
    rescue => e
309
      log("\tunable to create #{repos_path} : #{e}\n")
310
      next
311
    end
312

    
313
    if $svn_url
314
      begin
315
        project.post(:repository, :vendor => $scm, :repository => {:url => "#{$svn_url}#{project.identifier}"}, :key => $api_key)
316
        log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}");
317
      rescue => e
318
        log("\trepository #{repos_path} not registered in Redmine: #{e.message}");
319
      end
320
    end
321
    log("\trepository #{repos_path} created");
322
  end
323
end