##// END OF EJS Templates
Always log scm stderr and makes the log file path configurable....
Jean-Philippe Lang -
r10979:30801ca96805
parent child
Show More
@@ -1,200 +1,206
1 1 # = Redmine configuration file
2 2 #
3 3 # Each environment has it's own configuration options. If you are only
4 4 # running in production, only the production block needs to be configured.
5 5 # Environment specific configuration options override the default ones.
6 6 #
7 7 # Note that this file needs to be a valid YAML file.
8 8 # DO NOT USE TABS! Use 2 spaces instead of tabs for identation.
9 9 #
10 10 # == Outgoing email settings (email_delivery setting)
11 11 #
12 12 # === Common configurations
13 13 #
14 14 # ==== Sendmail command
15 15 #
16 16 # production:
17 17 # email_delivery:
18 18 # delivery_method: :sendmail
19 19 #
20 20 # ==== Simple SMTP server at localhost
21 21 #
22 22 # production:
23 23 # email_delivery:
24 24 # delivery_method: :smtp
25 25 # smtp_settings:
26 26 # address: "localhost"
27 27 # port: 25
28 28 #
29 29 # ==== SMTP server at example.com using LOGIN authentication and checking HELO for foo.com
30 30 #
31 31 # production:
32 32 # email_delivery:
33 33 # delivery_method: :smtp
34 34 # smtp_settings:
35 35 # address: "example.com"
36 36 # port: 25
37 37 # authentication: :login
38 38 # domain: 'foo.com'
39 39 # user_name: 'myaccount'
40 40 # password: 'password'
41 41 #
42 42 # ==== SMTP server at example.com using PLAIN authentication
43 43 #
44 44 # production:
45 45 # email_delivery:
46 46 # delivery_method: :smtp
47 47 # smtp_settings:
48 48 # address: "example.com"
49 49 # port: 25
50 50 # authentication: :plain
51 51 # domain: 'example.com'
52 52 # user_name: 'myaccount'
53 53 # password: 'password'
54 54 #
55 55 # ==== SMTP server at using TLS (GMail)
56 56 #
57 57 # This might require some additional configuration. See the guides at:
58 58 # http://www.redmine.org/projects/redmine/wiki/EmailConfiguration
59 59 #
60 60 # production:
61 61 # email_delivery:
62 62 # delivery_method: :smtp
63 63 # smtp_settings:
64 64 # enable_starttls_auto: true
65 65 # address: "smtp.gmail.com"
66 66 # port: 587
67 67 # domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps
68 68 # authentication: :plain
69 69 # user_name: "your_email@gmail.com"
70 70 # password: "your_password"
71 71 #
72 72 #
73 73 # === More configuration options
74 74 #
75 75 # See the "Configuration options" at the following website for a list of the
76 76 # full options allowed:
77 77 #
78 78 # http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer
79 79
80 80
81 81 # default configuration options for all environments
82 82 default:
83 83 # Outgoing emails configuration (see examples above)
84 84 email_delivery:
85 85 delivery_method: :smtp
86 86 smtp_settings:
87 87 address: smtp.example.net
88 88 port: 25
89 89 domain: example.net
90 90 authentication: :login
91 91 user_name: "redmine@example.net"
92 92 password: "redmine"
93 93
94 94 # Absolute path to the directory where attachments are stored.
95 95 # The default is the 'files' directory in your Redmine instance.
96 96 # Your Redmine instance needs to have write permission on this
97 97 # directory.
98 98 # Examples:
99 99 # attachments_storage_path: /var/redmine/files
100 100 # attachments_storage_path: D:/redmine/files
101 101 attachments_storage_path:
102 102
103 103 # Configuration of the autologin cookie.
104 104 # autologin_cookie_name: the name of the cookie (default: autologin)
105 105 # autologin_cookie_path: the cookie path (default: /)
106 106 # autologin_cookie_secure: true sets the cookie secure flag (default: false)
107 107 autologin_cookie_name:
108 108 autologin_cookie_path:
109 109 autologin_cookie_secure:
110 110
111 111 # Configuration of SCM executable command.
112 112 #
113 113 # Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe)
114 114 # On Windows + CRuby, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work.
115 115 #
116 116 # On Windows + JRuby 1.6.2, path which contains spaces does not work.
117 117 # For example, "C:\Program Files\TortoiseHg\hg.exe".
118 118 # If you want to this feature, you need to install to the path which does not contains spaces.
119 119 # For example, "C:\TortoiseHg\hg.exe".
120 120 #
121 121 # Examples:
122 122 # scm_subversion_command: svn # (default: svn)
123 123 # scm_mercurial_command: C:\Program Files\TortoiseHg\hg.exe # (default: hg)
124 124 # scm_git_command: /usr/local/bin/git # (default: git)
125 125 # scm_cvs_command: cvs # (default: cvs)
126 126 # scm_bazaar_command: bzr.exe # (default: bzr)
127 127 # scm_darcs_command: darcs-1.0.9-i386-linux # (default: darcs)
128 128 #
129 129 scm_subversion_command:
130 130 scm_mercurial_command:
131 131 scm_git_command:
132 132 scm_cvs_command:
133 133 scm_bazaar_command:
134 134 scm_darcs_command:
135 135
136 # Absolute path to the scm commands errors (stderr) log file.
137 # The default is to log in the 'log' directory of your Redmine instance.
138 # Example:
139 # scm_stderr_log_file: /var/log/redmine_scm_stderr.log
140 scm_stderr_log_file:
141
136 142 # Key used to encrypt sensitive data in the database (SCM and LDAP passwords).
137 143 # If you don't want to enable data encryption, just leave it blank.
138 144 # WARNING: losing/changing this key will make encrypted data unreadable.
139 145 #
140 146 # If you want to encrypt existing passwords in your database:
141 147 # * set the cipher key here in your configuration file
142 148 # * encrypt data using 'rake db:encrypt RAILS_ENV=production'
143 149 #
144 150 # If you have encrypted data and want to change this key, you have to:
145 151 # * decrypt data using 'rake db:decrypt RAILS_ENV=production' first
146 152 # * change the cipher key here in your configuration file
147 153 # * encrypt data using 'rake db:encrypt RAILS_ENV=production'
148 154 database_cipher_key:
149 155
150 156 # Set this to false to disable plugins' assets mirroring on startup.
151 157 # You can use `rake redmine:plugins:assets` to manually mirror assets
152 158 # to public/plugin_assets when you install/upgrade a Redmine plugin.
153 159 #
154 160 #mirror_plugins_assets_on_startup: false
155 161
156 162 # Your secret key for verifying cookie session data integrity. If you
157 163 # change this key, all old sessions will become invalid! Make sure the
158 164 # secret is at least 30 characters and all random, no regular words or
159 165 # you'll be exposed to dictionary attacks.
160 166 #
161 167 # If you have a load-balancing Redmine cluster, you have to use the
162 168 # same secret token on each machine.
163 169 #secret_token: 'change it to a long random string'
164 170
165 171 # Absolute path (e.g. /usr/bin/convert, c:/im/convert.exe) to
166 172 # the ImageMagick's `convert` binary. Used to generate attachment thumbnails.
167 173 #imagemagick_convert_command:
168 174
169 175 # Configuration of RMagcik font.
170 176 #
171 177 # Redmine uses RMagcik in order to export gantt png.
172 178 # You don't need this setting if you don't install RMagcik.
173 179 #
174 180 # In CJK (Chinese, Japanese and Korean),
175 181 # in order to show CJK characters correctly,
176 182 # you need to set this configuration.
177 183 #
178 184 # Because there is no standard font across platforms in CJK,
179 185 # you need to set a font installed in your server.
180 186 #
181 187 # This setting is not necessary in non CJK.
182 188 #
183 189 # Examples for Japanese:
184 190 # Windows:
185 191 # rmagick_font_path: C:\windows\fonts\msgothic.ttc
186 192 # Linux:
187 193 # rmagick_font_path: /usr/share/fonts/ipa-mincho/ipam.ttf
188 194 #
189 195 rmagick_font_path:
190 196
191 197 # Maximum number of simultaneous AJAX uploads
192 198 #max_concurrent_ajax_uploads: 2
193 199
194 200 # specific configuration options for production environment
195 201 # that overrides the default ones
196 202 production:
197 203
198 204 # specific configuration options for development environment
199 205 # that overrides the default ones
200 206 development:
@@ -1,424 +1,429
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'cgi'
19 19
20 20 if RUBY_VERSION < '1.9'
21 21 require 'iconv'
22 22 end
23 23
24 24 module Redmine
25 25 module Scm
26 26 module Adapters
27 27 class CommandFailed < StandardError #:nodoc:
28 28 end
29 29
30 30 class AbstractAdapter #:nodoc:
31 31
32 32 # raised if scm command exited with error, e.g. unknown revision.
33 33 class ScmCommandAborted < CommandFailed; end
34 34
35 35 class << self
36 36 def client_command
37 37 ""
38 38 end
39 39
40 40 def shell_quote_command
41 41 if Redmine::Platform.mswin? && RUBY_PLATFORM == 'java'
42 42 client_command
43 43 else
44 44 shell_quote(client_command)
45 45 end
46 46 end
47 47
48 48 # Returns the version of the scm client
49 49 # Eg: [1, 5, 0] or [] if unknown
50 50 def client_version
51 51 []
52 52 end
53 53
54 54 # Returns the version string of the scm client
55 55 # Eg: '1.5.0' or 'Unknown version' if unknown
56 56 def client_version_string
57 57 v = client_version || 'Unknown version'
58 58 v.is_a?(Array) ? v.join('.') : v.to_s
59 59 end
60 60
61 61 # Returns true if the current client version is above
62 62 # or equals the given one
63 63 # If option is :unknown is set to true, it will return
64 64 # true if the client version is unknown
65 65 def client_version_above?(v, options={})
66 66 ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown])
67 67 end
68 68
69 69 def client_available
70 70 true
71 71 end
72 72
73 73 def shell_quote(str)
74 74 if Redmine::Platform.mswin?
75 75 '"' + str.gsub(/"/, '\\"') + '"'
76 76 else
77 77 "'" + str.gsub(/'/, "'\"'\"'") + "'"
78 78 end
79 79 end
80 80 end
81 81
82 82 def initialize(url, root_url=nil, login=nil, password=nil,
83 83 path_encoding=nil)
84 84 @url = url
85 85 @login = login if login && !login.empty?
86 86 @password = (password || "") if @login
87 87 @root_url = root_url.blank? ? retrieve_root_url : root_url
88 88 end
89 89
90 90 def adapter_name
91 91 'Abstract'
92 92 end
93 93
94 94 def supports_cat?
95 95 true
96 96 end
97 97
98 98 def supports_annotate?
99 99 respond_to?('annotate')
100 100 end
101 101
102 102 def root_url
103 103 @root_url
104 104 end
105 105
106 106 def url
107 107 @url
108 108 end
109 109
110 110 def path_encoding
111 111 nil
112 112 end
113 113
114 114 # get info about the svn repository
115 115 def info
116 116 return nil
117 117 end
118 118
119 119 # Returns the entry identified by path and revision identifier
120 120 # or nil if entry doesn't exist in the repository
121 121 def entry(path=nil, identifier=nil)
122 122 parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?}
123 123 search_path = parts[0..-2].join('/')
124 124 search_name = parts[-1]
125 125 if search_path.blank? && search_name.blank?
126 126 # Root entry
127 127 Entry.new(:path => '', :kind => 'dir')
128 128 else
129 129 # Search for the entry in the parent directory
130 130 es = entries(search_path, identifier)
131 131 es ? es.detect {|e| e.name == search_name} : nil
132 132 end
133 133 end
134 134
135 135 # Returns an Entries collection
136 136 # or nil if the given path doesn't exist in the repository
137 137 def entries(path=nil, identifier=nil, options={})
138 138 return nil
139 139 end
140 140
141 141 def branches
142 142 return nil
143 143 end
144 144
145 145 def tags
146 146 return nil
147 147 end
148 148
149 149 def default_branch
150 150 return nil
151 151 end
152 152
153 153 def properties(path, identifier=nil)
154 154 return nil
155 155 end
156 156
157 157 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
158 158 return nil
159 159 end
160 160
161 161 def diff(path, identifier_from, identifier_to=nil)
162 162 return nil
163 163 end
164 164
165 165 def cat(path, identifier=nil)
166 166 return nil
167 167 end
168 168
169 169 def with_leading_slash(path)
170 170 path ||= ''
171 171 (path[0,1]!="/") ? "/#{path}" : path
172 172 end
173 173
174 174 def with_trailling_slash(path)
175 175 path ||= ''
176 176 (path[-1,1] == "/") ? path : "#{path}/"
177 177 end
178 178
179 179 def without_leading_slash(path)
180 180 path ||= ''
181 181 path.gsub(%r{^/+}, '')
182 182 end
183 183
184 184 def without_trailling_slash(path)
185 185 path ||= ''
186 186 (path[-1,1] == "/") ? path[0..-2] : path
187 187 end
188 188
189 189 def shell_quote(str)
190 190 self.class.shell_quote(str)
191 191 end
192 192
193 193 private
194 194 def retrieve_root_url
195 195 info = self.info
196 196 info ? info.root_url : nil
197 197 end
198 198
199 199 def target(path, sq=true)
200 200 path ||= ''
201 201 base = path.match(/^\//) ? root_url : url
202 202 str = "#{base}/#{path}".gsub(/[?<>\*]/, '')
203 203 if sq
204 204 str = shell_quote(str)
205 205 end
206 206 str
207 207 end
208 208
209 209 def logger
210 210 self.class.logger
211 211 end
212 212
213 213 def shellout(cmd, options = {}, &block)
214 214 self.class.shellout(cmd, options, &block)
215 215 end
216 216
217 217 def self.logger
218 218 Rails.logger
219 219 end
220 220
221 # Path to the file where scm stderr output is logged
222 def self.stderr_log_file
223 @stderr_log_path ||=
224 Redmine::Configuration['scm_stderr_log_file'].presence ||
225 Rails.root.join("log/#{Rails.env}.scm.stderr.log").to_s
226 end
227
221 228 def self.shellout(cmd, options = {}, &block)
222 229 if logger && logger.debug?
223 230 logger.debug "Shelling out: #{strip_credential(cmd)}"
224 231 end
225 if Rails.env == 'development'
226 # Capture stderr when running in dev environment
227 cmd = "#{cmd} 2>>#{shell_quote(Rails.root.join('log/scm.stderr.log').to_s)}"
228 end
232 # Capture stderr in a log file
233 cmd = "#{cmd} 2>>#{shell_quote(stderr_log_file)}"
229 234 begin
230 235 mode = "r+"
231 236 IO.popen(cmd, mode) do |io|
232 237 io.set_encoding("ASCII-8BIT") if io.respond_to?(:set_encoding)
233 238 io.close_write unless options[:write_stdin]
234 239 block.call(io) if block_given?
235 240 end
236 241 ## If scm command does not exist,
237 242 ## Linux JRuby 1.6.2 (ruby-1.8.7-p330) raises java.io.IOException
238 243 ## in production environment.
239 244 # rescue Errno::ENOENT => e
240 245 rescue Exception => e
241 246 msg = strip_credential(e.message)
242 247 # The command failed, log it and re-raise
243 248 logmsg = "SCM command failed, "
244 249 logmsg += "make sure that your SCM command (e.g. svn) is "
245 250 logmsg += "in PATH (#{ENV['PATH']})\n"
246 251 logmsg += "You can configure your scm commands in config/configuration.yml.\n"
247 252 logmsg += "#{strip_credential(cmd)}\n"
248 253 logmsg += "with: #{msg}"
249 254 logger.error(logmsg)
250 255 raise CommandFailed.new(msg)
251 256 end
252 257 end
253 258
254 259 # Hides username/password in a given command
255 260 def self.strip_credential(cmd)
256 261 q = (Redmine::Platform.mswin? ? '"' : "'")
257 262 cmd.to_s.gsub(/(\-\-(password|username))\s+(#{q}[^#{q}]+#{q}|[^#{q}]\S+)/, '\\1 xxxx')
258 263 end
259 264
260 265 def strip_credential(cmd)
261 266 self.class.strip_credential(cmd)
262 267 end
263 268
264 269 def scm_iconv(to, from, str)
265 270 return nil if str.nil?
266 271 return str if to == from
267 272 if str.respond_to?(:force_encoding)
268 273 str.force_encoding(from)
269 274 begin
270 275 str.encode(to)
271 276 rescue Exception => err
272 277 logger.error("failed to convert from #{from} to #{to}. #{err}")
273 278 nil
274 279 end
275 280 else
276 281 begin
277 282 Iconv.conv(to, from, str)
278 283 rescue Iconv::Failure => err
279 284 logger.error("failed to convert from #{from} to #{to}. #{err}")
280 285 nil
281 286 end
282 287 end
283 288 end
284 289
285 290 def parse_xml(xml)
286 291 if RUBY_PLATFORM == 'java'
287 292 xml = xml.sub(%r{<\?xml[^>]*\?>}, '')
288 293 end
289 294 ActiveSupport::XmlMini.parse(xml)
290 295 end
291 296 end
292 297
293 298 class Entries < Array
294 299 def sort_by_name
295 300 dup.sort! {|x,y|
296 301 if x.kind == y.kind
297 302 x.name.to_s <=> y.name.to_s
298 303 else
299 304 x.kind <=> y.kind
300 305 end
301 306 }
302 307 end
303 308
304 309 def revisions
305 310 revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact)
306 311 end
307 312 end
308 313
309 314 class Info
310 315 attr_accessor :root_url, :lastrev
311 316 def initialize(attributes={})
312 317 self.root_url = attributes[:root_url] if attributes[:root_url]
313 318 self.lastrev = attributes[:lastrev]
314 319 end
315 320 end
316 321
317 322 class Entry
318 323 attr_accessor :name, :path, :kind, :size, :lastrev, :changeset
319 324
320 325 def initialize(attributes={})
321 326 self.name = attributes[:name] if attributes[:name]
322 327 self.path = attributes[:path] if attributes[:path]
323 328 self.kind = attributes[:kind] if attributes[:kind]
324 329 self.size = attributes[:size].to_i if attributes[:size]
325 330 self.lastrev = attributes[:lastrev]
326 331 end
327 332
328 333 def is_file?
329 334 'file' == self.kind
330 335 end
331 336
332 337 def is_dir?
333 338 'dir' == self.kind
334 339 end
335 340
336 341 def is_text?
337 342 Redmine::MimeType.is_type?('text', name)
338 343 end
339 344
340 345 def author
341 346 if changeset
342 347 changeset.author.to_s
343 348 elsif lastrev
344 349 Redmine::CodesetUtil.replace_invalid_utf8(lastrev.author.to_s.split('<').first)
345 350 end
346 351 end
347 352 end
348 353
349 354 class Revisions < Array
350 355 def latest
351 356 sort {|x,y|
352 357 unless x.time.nil? or y.time.nil?
353 358 x.time <=> y.time
354 359 else
355 360 0
356 361 end
357 362 }.last
358 363 end
359 364 end
360 365
361 366 class Revision
362 367 attr_accessor :scmid, :name, :author, :time, :message,
363 368 :paths, :revision, :branch, :identifier,
364 369 :parents
365 370
366 371 def initialize(attributes={})
367 372 self.identifier = attributes[:identifier]
368 373 self.scmid = attributes[:scmid]
369 374 self.name = attributes[:name] || self.identifier
370 375 self.author = attributes[:author]
371 376 self.time = attributes[:time]
372 377 self.message = attributes[:message] || ""
373 378 self.paths = attributes[:paths]
374 379 self.revision = attributes[:revision]
375 380 self.branch = attributes[:branch]
376 381 self.parents = attributes[:parents]
377 382 end
378 383
379 384 # Returns the readable identifier.
380 385 def format_identifier
381 386 self.identifier.to_s
382 387 end
383 388
384 389 def ==(other)
385 390 if other.nil?
386 391 false
387 392 elsif scmid.present?
388 393 scmid == other.scmid
389 394 elsif identifier.present?
390 395 identifier == other.identifier
391 396 elsif revision.present?
392 397 revision == other.revision
393 398 end
394 399 end
395 400 end
396 401
397 402 class Annotate
398 403 attr_reader :lines, :revisions
399 404
400 405 def initialize
401 406 @lines = []
402 407 @revisions = []
403 408 end
404 409
405 410 def add_line(line, revision)
406 411 @lines << line
407 412 @revisions << revision
408 413 end
409 414
410 415 def content
411 416 content = lines.join("\n")
412 417 end
413 418
414 419 def empty?
415 420 lines.empty?
416 421 end
417 422 end
418 423
419 424 class Branch < String
420 425 attr_accessor :revision, :scmid
421 426 end
422 427 end
423 428 end
424 429 end
General Comments 0
You need to be logged in to leave comments. Login now