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