##// END OF EJS Templates
Slight change on git repository creation command....
Jean-Philippe Lang -
r1874:710ac5344d80
parent child
Show More
@@ -1,289 +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, options={})
93 def log(text, options={})
94 level = options[:level] || 0
94 level = options[:level] || 0
95 puts text unless $quiet or level > $verbose
95 puts text unless $quiet or level > $verbose
96 exit 1 if options[:exit]
96 exit 1 if options[:exit]
97 end
97 end
98
98
99 def system_or_raise(command)
99 def system_or_raise(command)
100 raise "\"#{command}\" failed" unless system command
100 raise "\"#{command}\" failed" unless system command
101 end
101 end
102
102
103 module SCM
103 module SCM
104
104
105 module Subversion
105 module Subversion
106 def self.create(path)
106 def self.create(path)
107 system_or_raise "svnadmin create #{path}"
107 system_or_raise "svnadmin create #{path}"
108 end
108 end
109 end
109 end
110
110
111 module Git
111 module Git
112 def self.create(path)
112 def self.create(path)
113 Dir.mkdir path
113 Dir.mkdir path
114 Dir.chdir(path) do
114 Dir.chdir(path) do
115 system_or_raise "git --bare init --shared"
115 system_or_raise "git --bare init --shared"
116 system_or_raise "git-update-server-info"
116 system_or_raise "git update-server-info"
117 end
117 end
118 end
118 end
119 end
119 end
120
120
121 end
121 end
122
122
123 begin
123 begin
124 opts.each do |opt, arg|
124 opts.each do |opt, arg|
125 case opt
125 case opt
126 when '--svn-dir'; $repos_base = arg.dup
126 when '--svn-dir'; $repos_base = arg.dup
127 when '--redmine-host'; $redmine_host = arg.dup
127 when '--redmine-host'; $redmine_host = arg.dup
128 when '--owner'; $svn_owner = arg.dup; $use_groupid = false;
128 when '--owner'; $svn_owner = arg.dup; $use_groupid = false;
129 when '--url'; $svn_url = arg.dup
129 when '--url'; $svn_url = arg.dup
130 when '--scm'; $scm = arg.dup.capitalize; log("Invalid SCM: #{$scm}", :exit => true) unless SUPPORTED_SCM.include?($scm)
130 when '--scm'; $scm = arg.dup.capitalize; log("Invalid SCM: #{$scm}", :exit => true) unless SUPPORTED_SCM.include?($scm)
131 when '--command'; $command = arg.dup
131 when '--command'; $command = arg.dup
132 when '--verbose'; $verbose += 1
132 when '--verbose'; $verbose += 1
133 when '--test'; $test = true
133 when '--test'; $test = true
134 when '--force'; $force = true
134 when '--force'; $force = true
135 when '--version'; puts Version; exit
135 when '--version'; puts Version; exit
136 when '--help'; RDoc::usage
136 when '--help'; RDoc::usage
137 when '--quiet'; $quiet = true
137 when '--quiet'; $quiet = true
138 end
138 end
139 end
139 end
140 rescue
140 rescue
141 exit 1
141 exit 1
142 end
142 end
143
143
144 if $test
144 if $test
145 log("running in test mode")
145 log("running in test mode")
146 end
146 end
147
147
148 # 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)
149 if $command.nil?
149 if $command.nil?
150 begin
150 begin
151 scm_module = SCM.const_get($scm)
151 scm_module = SCM.const_get($scm)
152 rescue
152 rescue
153 log("Please use --command option to specify how to create a #{$scm} repository.", :exit => true)
153 log("Please use --command option to specify how to create a #{$scm} repository.", :exit => true)
154 end
154 end
155 end
155 end
156
156
157 $svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
157 $svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
158
158
159 if ($redmine_host.empty? or $repos_base.empty?)
159 if ($redmine_host.empty? or $repos_base.empty?)
160 RDoc::usage
160 RDoc::usage
161 end
161 end
162
162
163 unless File.directory?($repos_base)
163 unless File.directory?($repos_base)
164 log("directory '#{$repos_base}' doesn't exists", :exit => true)
164 log("directory '#{$repos_base}' doesn't exists", :exit => true)
165 end
165 end
166
166
167 log("querying Redmine for projects...", :level => 1);
167 log("querying Redmine for projects...", :level => 1);
168
168
169 $redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
169 $redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://")
170 $redmine_host.gsub!(/\/$/, '')
170 $redmine_host.gsub!(/\/$/, '')
171
171
172 wsdl_url = "#{$redmine_host}/sys/service.wsdl";
172 wsdl_url = "#{$redmine_host}/sys/service.wsdl";
173
173
174 begin
174 begin
175 soap = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver
175 soap = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver
176 rescue => e
176 rescue => e
177 log("Unable to connect to #{wsdl_url} : #{e}", :exit => true)
177 log("Unable to connect to #{wsdl_url} : #{e}", :exit => true)
178 end
178 end
179
179
180 projects = soap.ProjectsWithRepositoryEnabled
180 projects = soap.ProjectsWithRepositoryEnabled
181
181
182 if projects.nil?
182 if projects.nil?
183 log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
183 log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
184 end
184 end
185
185
186 log("retrieved #{projects.size} projects", :level => 1)
186 log("retrieved #{projects.size} projects", :level => 1)
187
187
188 def set_owner_and_rights(project, repos_path, &block)
188 def set_owner_and_rights(project, repos_path, &block)
189 if RUBY_PLATFORM =~ /mswin/
189 if RUBY_PLATFORM =~ /mswin/
190 yield if block_given?
190 yield if block_given?
191 else
191 else
192 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)
193 right = project.is_public ? 0775 : 0770
193 right = project.is_public ? 0775 : 0770
194 yield if block_given?
194 yield if block_given?
195 Find.find(repos_path) do |f|
195 Find.find(repos_path) do |f|
196 File.chmod right, f
196 File.chmod right, f
197 File.chown uid, gid, f
197 File.chown uid, gid, f
198 end
198 end
199 end
199 end
200 end
200 end
201
201
202 def other_read_right?(file)
202 def other_read_right?(file)
203 (File.stat(file).mode & 0007).zero? ? false : true
203 (File.stat(file).mode & 0007).zero? ? false : true
204 end
204 end
205
205
206 def owner_name(file)
206 def owner_name(file)
207 RUBY_PLATFORM =~ /mswin/ ?
207 RUBY_PLATFORM =~ /mswin/ ?
208 $svn_owner :
208 $svn_owner :
209 Etc.getpwuid( File.stat(file).uid ).name
209 Etc.getpwuid( File.stat(file).uid ).name
210 end
210 end
211
211
212 projects.each do |project|
212 projects.each do |project|
213 log("treating project #{project.name}", :level => 1)
213 log("treating project #{project.name}", :level => 1)
214
214
215 if project.identifier.empty?
215 if project.identifier.empty?
216 log("\tno identifier for project #{project.name}")
216 log("\tno identifier for project #{project.name}")
217 next
217 next
218 elsif not project.identifier.match(/^[a-z0-9\-]+$/)
218 elsif not project.identifier.match(/^[a-z0-9\-]+$/)
219 log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
219 log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
220 next;
220 next;
221 end
221 end
222
222
223 repos_path = $repos_base + "/" + project.identifier
223 repos_path = $repos_base + "/" + project.identifier
224
224
225 if File.directory?(repos_path)
225 if File.directory?(repos_path)
226
226
227 # 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
228 # rights before leaving
228 # rights before leaving
229 other_read = other_read_right?(repos_path)
229 other_read = other_read_right?(repos_path)
230 owner = owner_name(repos_path)
230 owner = owner_name(repos_path)
231 next if project.is_public == other_read and owner == $svn_owner
231 next if project.is_public == other_read and owner == $svn_owner
232
232
233 if $test
233 if $test
234 log("\tchange mode on #{repos_path}")
234 log("\tchange mode on #{repos_path}")
235 next
235 next
236 end
236 end
237
237
238 begin
238 begin
239 set_owner_and_rights(project, repos_path)
239 set_owner_and_rights(project, repos_path)
240 rescue Errno::EPERM => e
240 rescue Errno::EPERM => e
241 log("\tunable to change mode on #{repos_path} : #{e}\n")
241 log("\tunable to change mode on #{repos_path} : #{e}\n")
242 next
242 next
243 end
243 end
244
244
245 log("\tmode change on #{repos_path}");
245 log("\tmode change on #{repos_path}");
246
246
247 else
247 else
248 # if repository is already declared in redmine, we don't create
248 # if repository is already declared in redmine, we don't create
249 # unless user use -f with reposman
249 # unless user use -f with reposman
250 if $force == false and not project.repository.nil?
250 if $force == false and not project.repository.nil?
251 log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1)
251 log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1)
252 next
252 next
253 end
253 end
254
254
255 project.is_public ? File.umask(0002) : File.umask(0007)
255 project.is_public ? File.umask(0002) : File.umask(0007)
256
256
257 if $test
257 if $test
258 log("\tcreate repository #{repos_path}")
258 log("\tcreate repository #{repos_path}")
259 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;
260 next
260 next
261 end
261 end
262
262
263 begin
263 begin
264 set_owner_and_rights(project, repos_path) do
264 set_owner_and_rights(project, repos_path) do
265 if scm_module.nil?
265 if scm_module.nil?
266 system_or_raise "#{$command} #{repos_path}"
266 system_or_raise "#{$command} #{repos_path}"
267 else
267 else
268 scm_module.create(repos_path)
268 scm_module.create(repos_path)
269 end
269 end
270 end
270 end
271 rescue => e
271 rescue => e
272 log("\tunable to create #{repos_path} : #{e}\n")
272 log("\tunable to create #{repos_path} : #{e}\n")
273 next
273 next
274 end
274 end
275
275
276 if $svn_url
276 if $svn_url
277 ret = soap.RepositoryCreated project.identifier, $scm, "#{$svn_url}#{project.identifier}"
277 ret = soap.RepositoryCreated project.identifier, $scm, "#{$svn_url}#{project.identifier}"
278 if ret > 0
278 if ret > 0
279 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}");
280 else
280 else
281 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.");
282 end
282 end
283 end
283 end
284
284
285 log("\trepository #{repos_path} created");
285 log("\trepository #{repos_path} created");
286 end
286 end
287
287
288 end
288 end
289
289
General Comments 0
You need to be logged in to leave comments. Login now