##// END OF EJS Templates
Merged r9742 from trunk....
Jean-Philippe Lang -
r9568:93d8f998842f
parent child
Show More
@@ -1,288 +1,289
1 1 #!/usr/bin/env ruby
2 2
3 3 require 'optparse'
4 4 require 'find'
5 5 require 'etc'
6 require 'rubygems'
6 7
7 8 Version = "1.4"
8 9 SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem )
9 10
10 11 $verbose = 0
11 12 $quiet = false
12 13 $redmine_host = ''
13 14 $repos_base = ''
14 15 $svn_owner = 'root'
15 16 $svn_group = 'root'
16 17 $use_groupid = true
17 18 $svn_url = false
18 19 $test = false
19 20 $force = false
20 21 $scm = 'Subversion'
21 22
22 23 def log(text, options={})
23 24 level = options[:level] || 0
24 25 puts text unless $quiet or level > $verbose
25 26 exit 1 if options[:exit]
26 27 end
27 28
28 29 def system_or_raise(command)
29 30 raise "\"#{command}\" failed" unless system command
30 31 end
31 32
32 33 module SCM
33 34
34 35 module Subversion
35 36 def self.create(path)
36 37 system_or_raise "svnadmin create #{path}"
37 38 end
38 39 end
39 40
40 41 module Git
41 42 def self.create(path)
42 43 Dir.mkdir path
43 44 Dir.chdir(path) do
44 45 system_or_raise "git --bare init --shared"
45 46 system_or_raise "git update-server-info"
46 47 end
47 48 end
48 49 end
49 50
50 51 end
51 52
52 53 def read_key_from_file(filename)
53 54 begin
54 55 $api_key = File.read(filename).strip
55 56 rescue Exception => e
56 57 $stderr.puts "Unable to read the key from #{filename}: #{e.message}"
57 58 exit 1
58 59 end
59 60 end
60 61
61 62 def set_scm(scm)
62 63 $scm = scm.capitalize
63 64 unless SUPPORTED_SCM.include?($scm)
64 65 log("Invalid SCM: #{$scm}\nValid SCM are: #{SUPPORTED_SCM.join(', ')}", :exit => true)
65 66 end
66 67 end
67 68
68 69 optparse = OptionParser.new do |opts|
69 70 opts.banner = "Usage: reposman.rb [OPTIONS...] -s [DIR] -r [HOST] -k [KEY]"
70 71 opts.separator("")
71 72 opts.separator("Manages your repositories with Redmine.")
72 73 opts.separator("")
73 74 opts.separator("Required arguments:")
74 75 opts.on("-s", "--svn-dir DIR", "use DIR as base directory for svn repositories") {|v| $repos_base = v}
75 76 opts.on("-r", "--redmine-host HOST","assume Redmine is hosted on HOST. Examples:",
76 77 " -r redmine.example.net",
77 78 " -r http://redmine.example.net",
78 79 " -r https://redmine.example.net") {|v| $redmine_host = v}
79 80 opts.on("-k", "--key KEY", "use KEY as the Redmine API key",
80 81 "(you can use --key-file option as an alternative)") {|v| $api_key = v}
81 82 opts.separator("")
82 83 opts.separator("Options:")
83 84 opts.on("-o", "--owner OWNER", "owner of the repository. using the rails login",
84 85 "allows users to browse the repository within",
85 86 "Redmine even for private projects. If you want to",
86 87 "share repositories through Redmine.pm, you need",
87 88 "to use the apache owner.") {|v| $svn_owner = v; $use_groupid = false}
88 89 opts.on("-g", "--group GROUP", "group of the repository (default: root)") {|v| $svn_group = v; $use_groupid = false}
89 90 opts.on("-u", "--url URL", "the base url Redmine will use to access your",
90 91 "repositories. This option is used to register",
91 92 "the repositories in Redmine automatically. The",
92 93 "project identifier will be appended to this url.",
93 94 "Examples:",
94 95 " -u https://example.net/svn",
95 96 " -u file:///var/svn/",
96 97 "if this option isn't set, reposman won't register",
97 98 "the repositories in Redmine") {|v| $svn_url = v}
98 99 opts.on( "--scm SCM", "the kind of SCM repository you want to create",
99 100 "(and register) in Redmine (default: Subversion).",
100 101 "reposman is able to create Git and Subversion",
101 102 "repositories.",
102 103 "For all other kind, you must specify a --command",
103 104 "option") {|v| set_scm(v)}
104 105 opts.on("-c", "--command COMMAND", "use this command instead of `svnadmin create` to",
105 106 "create a repository. This option can be used to",
106 107 "create repositories other than subversion and git",
107 108 "kind.",
108 109 "This command override the default creation for",
109 110 "git and subversion.") {|v| $command = v}
110 111 opts.on( "--key-file FILE", "path to a file that contains the Redmine API key",
111 112 "(use this option instead of --key if you don't",
112 113 "want the key to appear in the command line)") {|v| read_key_from_file(v)}
113 114 opts.on("-t", "--test", "only show what should be done") {$test = true}
114 115 opts.on("-f", "--force", "force repository creation even if the project", "repository is already declared in Redmine") {$force = true}
115 116 opts.on("-v", "--verbose", "verbose") {$verbose += 1}
116 117 opts.on("-V", "--version", "show version and exit") {puts Version; exit}
117 118 opts.on("-h", "--help", "show help and exit") {puts opts; exit 1}
118 119 opts.on("-q", "--quiet", "no log") {$quiet = true}
119 120 opts.separator("")
120 121 opts.separator("Examples:")
121 122 opts.separator(" reposman.rb --svn-dir=/var/svn --redmine-host=redmine.host")
122 123 opts.separator(" reposman.rb -s /var/git -r redmine.host -u http://git.host --scm git")
123 124 opts.separator("")
124 125 opts.separator("You can find more information on the redmine's wiki:\nhttp://www.redmine.org/projects/redmine/wiki/HowTos")
125 126
126 127 opts.summary_width = 25
127 128 end
128 129 optparse.parse!
129 130
130 131 if $test
131 132 log("running in test mode")
132 133 end
133 134
134 135 # Make sure command is overridden if SCM vendor is not handled internally (for the moment Subversion and Git)
135 136 if $command.nil?
136 137 begin
137 138 scm_module = SCM.const_get($scm)
138 139 rescue
139 140 log("Please use --command option to specify how to create a #{$scm} repository.", :exit => true)
140 141 end
141 142 end
142 143
143 144 $svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
144 145
145 146 if ($redmine_host.empty? or $repos_base.empty?)
146 147 puts "Some arguments are missing. Use reposman.rb --help for getting help."
147 148 exit 1
148 149 end
149 150
150 151 unless File.directory?($repos_base)
151 152 log("directory '#{$repos_base}' doesn't exists", :exit => true)
152 153 end
153 154
154 155 begin
155 156 require 'active_resource'
156 157 rescue LoadError
157 158 log("This script requires activeresource.\nRun 'gem install activeresource' to install it.", :exit => true)
158 159 end
159 160
160 161 class Project < ActiveResource::Base
161 162 self.headers["User-agent"] = "Redmine repository manager/#{Version}"
162 163 self.format = :xml
163 164 end
164 165
165 166 log("querying Redmine for projects...", :level => 1);
166 167
167 168 $redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
168 169 $redmine_host.gsub!(/\/$/, '')
169 170
170 171 Project.site = "#{$redmine_host}/sys";
171 172
172 173 begin
173 174 # Get all active projects that have the Repository module enabled
174 175 projects = Project.find(:all, :params => {:key => $api_key})
175 176 rescue ActiveResource::ForbiddenAccess
176 177 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.")
177 178 rescue => e
178 179 log("Unable to connect to #{Project.site}: #{e}", :exit => true)
179 180 end
180 181
181 182 if projects.nil?
182 183 log('No project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
183 184 end
184 185
185 186 log("retrieved #{projects.size} projects", :level => 1)
186 187
187 188 def set_owner_and_rights(project, repos_path, &block)
188 189 if mswin?
189 190 yield if block_given?
190 191 else
191 192 uid, gid = Etc.getpwnam($svn_owner).uid, ($use_groupid ? Etc.getgrnam(project.identifier).gid : Etc.getgrnam($svn_group).gid)
192 193 right = project.is_public ? 0775 : 0770
193 194 yield if block_given?
194 195 Find.find(repos_path) do |f|
195 196 File.chmod right, f
196 197 File.chown uid, gid, f
197 198 end
198 199 end
199 200 end
200 201
201 202 def other_read_right?(file)
202 203 (File.stat(file).mode & 0007).zero? ? false : true
203 204 end
204 205
205 206 def owner_name(file)
206 207 mswin? ?
207 208 $svn_owner :
208 209 Etc.getpwuid( File.stat(file).uid ).name
209 210 end
210 211
211 212 def mswin?
212 213 (RUBY_PLATFORM =~ /(:?mswin|mingw)/) || (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i)
213 214 end
214 215
215 216 projects.each do |project|
216 217 log("treating project #{project.name}", :level => 1)
217 218
218 219 if project.identifier.empty?
219 220 log("\tno identifier for project #{project.name}")
220 221 next
221 222 elsif not project.identifier.match(/^[a-z0-9\-_]+$/)
222 223 log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
223 224 next;
224 225 end
225 226
226 227 repos_path = File.join($repos_base, project.identifier).gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR)
227 228
228 229 if File.directory?(repos_path)
229 230 # we must verify that repository has the good owner and the good
230 231 # rights before leaving
231 232 other_read = other_read_right?(repos_path)
232 233 owner = owner_name(repos_path)
233 234 next if project.is_public == other_read and owner == $svn_owner
234 235
235 236 if $test
236 237 log("\tchange mode on #{repos_path}")
237 238 next
238 239 end
239 240
240 241 begin
241 242 set_owner_and_rights(project, repos_path)
242 243 rescue Errno::EPERM => e
243 244 log("\tunable to change mode on #{repos_path} : #{e}\n")
244 245 next
245 246 end
246 247
247 248 log("\tmode change on #{repos_path}");
248 249
249 250 else
250 251 # if repository is already declared in redmine, we don't create
251 252 # unless user use -f with reposman
252 253 if $force == false and project.respond_to?(:repository)
253 254 log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1)
254 255 next
255 256 end
256 257
257 258 project.is_public ? File.umask(0002) : File.umask(0007)
258 259
259 260 if $test
260 261 log("\tcreate repository #{repos_path}")
261 262 log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}") if $svn_url;
262 263 next
263 264 end
264 265
265 266 begin
266 267 set_owner_and_rights(project, repos_path) do
267 268 if scm_module.nil?
268 269 system_or_raise "#{$command} #{repos_path}"
269 270 else
270 271 scm_module.create(repos_path)
271 272 end
272 273 end
273 274 rescue => e
274 275 log("\tunable to create #{repos_path} : #{e}\n")
275 276 next
276 277 end
277 278
278 279 if $svn_url
279 280 begin
280 281 project.post(:repository, :vendor => $scm, :repository => {:url => "#{$svn_url}#{project.identifier}"}, :key => $api_key)
281 282 log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}");
282 283 rescue => e
283 284 log("\trepository #{repos_path} not registered in Redmine: #{e.message}");
284 285 end
285 286 end
286 287 log("\trepository #{repos_path} created");
287 288 end
288 289 end
General Comments 0
You need to be logged in to leave comments. Login now