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