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