Revision 912:5e80956cc792 lib/redmine/scm

View differences:

lib/redmine/scm/adapters/abstract_adapter.rb
24 24
      end
25 25

  
26 26
      class AbstractAdapter #:nodoc:
27

  
28
        # raised if scm command exited with error, e.g. unknown revision.
29
        class ScmCommandAborted < CommandFailed; end
30

  
27 31
        class << self
28 32
          def client_command
29 33
            ""
30 34
          end
31 35

  
36
          def shell_quote_command
37
            if Redmine::Platform.mswin? && RUBY_PLATFORM == 'java'
38
              client_command
39
            else
40
              shell_quote(client_command)
41
            end
42
          end
43

  
32 44
          # Returns the version of the scm client
33 45
          # Eg: [1, 5, 0] or [] if unknown
34 46
          def client_version
......
180 192
          info ? info.root_url : nil
181 193
        end
182 194

  
183
        def target(path)
195
        def target(path, sq=true)
184 196
          path ||= ''
185 197
          base = path.match(/^\//) ? root_url : url
186
          shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, ''))
198
          str = "#{base}/#{path}".gsub(/[?<>\*]/, '')
199
          if sq
200
            str = shell_quote(str)
201
          end
202
          str
187 203
        end
188 204

  
189 205
        def logger
......
195 211
        end
196 212

  
197 213
        def self.logger
198
          RAILS_DEFAULT_LOGGER
214
          Rails.logger
199 215
        end
200 216

  
201 217
        def self.shellout(cmd, &block)
......
204 220
          end
205 221
          if Rails.env == 'development'
206 222
            # Capture stderr when running in dev environment
207
            cmd = "#{cmd} 2>>#{RAILS_ROOT}/log/scm.stderr.log"
223
            cmd = "#{cmd} 2>>#{Rails.root}/log/scm.stderr.log"
208 224
          end
209 225
          begin
210 226
            if RUBY_VERSION < '1.9'
......
216 232
              io.close_write
217 233
              block.call(io) if block_given?
218 234
            end
219
          rescue Errno::ENOENT => e
235
          ## If scm command does not exist,
236
          ## Linux JRuby 1.6.2 (ruby-1.8.7-p330) raises java.io.IOException
237
          ## in production environment.
238
          # rescue Errno::ENOENT => e
239
          rescue Exception => e
220 240
            msg = strip_credential(e.message)
221 241
            # The command failed, log it and re-raise
222 242
            logmsg = "SCM command failed, "
......
313 333

  
314 334
      class Revision
315 335
        attr_accessor :scmid, :name, :author, :time, :message,
316
                      :paths, :revision, :branch, :identifier
336
                      :paths, :revision, :branch, :identifier,
337
                      :parents
317 338

  
318 339
        def initialize(attributes={})
319 340
          self.identifier = attributes[:identifier]
......
325 346
          self.paths      = attributes[:paths]
326 347
          self.revision   = attributes[:revision]
327 348
          self.branch     = attributes[:branch]
349
          self.parents    = attributes[:parents]
328 350
        end
329 351

  
330 352
        # Returns the readable identifier.
......
354 376
          lines.empty?
355 377
        end
356 378
      end
379

  
380
      class Branch < String
381
        attr_accessor :revision, :scmid
382
      end
357 383
    end
358 384
  end
359 385
end
lib/redmine/scm/adapters/bazaar_adapter.rb
31 31
          end
32 32

  
33 33
          def sq_bin
34
            @@sq_bin ||= shell_quote(BZR_BIN)
34
            @@sq_bin ||= shell_quote_command
35 35
          end
36 36

  
37 37
          def client_version
......
59 59

  
60 60
        # Get info about the repository
61 61
        def info
62
          cmd = "#{self.class.sq_bin} revno #{target('')}"
62
          cmd_args = %w|revno|
63
          cmd_args << bzr_target('')
63 64
          info = nil
64
          shellout(cmd) do |io|
65
          scm_cmd(*cmd_args) do |io|
65 66
            if io.read =~ %r{^(\d+)\r?$}
66 67
              info = Info.new({:root_url => url,
67 68
                               :lastrev => Revision.new({
......
70 71
                             })
71 72
            end
72 73
          end
73
          return nil if $? && $?.exitstatus != 0
74 74
          info
75
        rescue CommandFailed
75
        rescue ScmCommandAborted
76 76
          return nil
77 77
        end
78 78

  
......
81 81
        def entries(path=nil, identifier=nil, options={})
82 82
          path ||= ''
83 83
          entries = Entries.new
84
          cmd = "#{self.class.sq_bin} ls -v --show-ids"
85 84
          identifier = -1 unless identifier && identifier.to_i > 0
86
          cmd << " -r#{identifier.to_i}"
87
          cmd << " #{target(path)}"
88
          shellout(cmd) do |io|
85
          cmd_args = %w|ls -v --show-ids|
86
          cmd_args << "-r#{identifier.to_i}"
87
          cmd_args << bzr_target(path)
88
          scm_cmd(*cmd_args) do |io|
89 89
            prefix = "#{url}/#{path}".gsub('\\', '/')
90 90
            logger.debug "PREFIX: #{prefix}"
91 91
            re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)\r?$}
......
99 99
                                  })
100 100
            end
101 101
          end
102
          return nil if $? && $?.exitstatus != 0
103
          logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
102
          if logger && logger.debug?
103
            logger.debug("Found #{entries.size} entries in the repository for #{target(path)}")
104
          end
104 105
          entries.sort_by_name
106
        rescue ScmCommandAborted
107
          return nil
105 108
        end
106 109

  
107 110
        def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
......
109 112
          identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1'
110 113
          identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
111 114
          revisions = Revisions.new
112
          cmd = "#{self.class.sq_bin} log -v --show-ids -r#{identifier_to}..#{identifier_from} #{target(path)}"
113
          shellout(cmd) do |io|
115
          cmd_args = %w|log -v --show-ids|
116
          cmd_args << "-r#{identifier_to}..#{identifier_from}"
117
          cmd_args << bzr_target(path)
118
          scm_cmd(*cmd_args) do |io|
114 119
            revision = nil
115
            parsing = nil
120
            parsing  = nil
116 121
            io.each_line do |line|
117 122
              if line =~ /^----/
118 123
                revisions << revision if revision
......
160 165
            end
161 166
            revisions << revision if revision
162 167
          end
163
          return nil if $? && $?.exitstatus != 0
164 168
          revisions
169
        rescue ScmCommandAborted
170
          return nil
165 171
        end
166 172

  
167 173
        def diff(path, identifier_from, identifier_to=nil)
......
174 180
          if identifier_from
175 181
            identifier_from = identifier_from.to_i
176 182
          end
177
          cmd = "#{self.class.sq_bin} diff -r#{identifier_to}..#{identifier_from} #{target(path)}"
178 183
          diff = []
179
          shellout(cmd) do |io|
184
          cmd_args = %w|diff|
185
          cmd_args << "-r#{identifier_to}..#{identifier_from}"
186
          cmd_args << bzr_target(path)
187
          scm_cmd_no_raise(*cmd_args) do |io|
180 188
            io.each_line do |line|
181 189
              diff << line
182 190
            end
183 191
          end
184
          #return nil if $? && $?.exitstatus != 0
185 192
          diff
186 193
        end
187 194

  
188 195
        def cat(path, identifier=nil)
189
          cmd = "#{self.class.sq_bin} cat"
190
          cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
191
          cmd << " #{target(path)}"
192 196
          cat = nil
193
          shellout(cmd) do |io|
197
          cmd_args = %w|cat|
198
          cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0
199
          cmd_args << bzr_target(path)
200
          scm_cmd(*cmd_args) do |io|
194 201
            io.binmode
195 202
            cat = io.read
196 203
          end
197
          return nil if $? && $?.exitstatus != 0
198 204
          cat
205
        rescue ScmCommandAborted
206
          return nil
199 207
        end
200 208

  
201 209
        def annotate(path, identifier=nil)
202
          cmd = "#{self.class.sq_bin} annotate --all"
203
          cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
204
          cmd << " #{target(path)}"
205 210
          blame = Annotate.new
206
          shellout(cmd) do |io|
207
            author = nil
211
          cmd_args = %w|annotate -q --all|
212
          cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0
213
          cmd_args << bzr_target(path)
214
          scm_cmd(*cmd_args) do |io|
215
            author     = nil
208 216
            identifier = nil
209 217
            io.each_line do |line|
210 218
              next unless line =~ %r{^(\d+) ([^|]+)\| (.*)$}
......
217 225
                  ))
218 226
            end
219 227
          end
220
          return nil if $? && $?.exitstatus != 0
221 228
          blame
229
        rescue ScmCommandAborted
230
          return nil
222 231
        end
232

  
233
        def self.branch_conf_path(path)
234
          bcp = nil
235
          m = path.match(%r{^(.*[/\\])\.bzr.*$})
236
          if m
237
            bcp = m[1]
238
          else
239
            bcp = path
240
          end
241
          bcp.gsub!(%r{[\/\\]$}, "")
242
          if bcp
243
            bcp = File.join(bcp, ".bzr", "branch", "branch.conf")
244
          end
245
          bcp
246
        end
247

  
248
        def append_revisions_only
249
          return @aro if ! @aro.nil?
250
          @aro = false
251
          bcp = self.class.branch_conf_path(url)
252
          if bcp && File.exist?(bcp)
253
            begin
254
              f = File::open(bcp, "r")
255
              cnt = 0
256
              f.each_line do |line|
257
                l = line.chomp.to_s
258
                if l =~ /^\s*append_revisions_only\s*=\s*(\w+)\s*$/
259
                  str_aro = $1
260
                  if str_aro.upcase == "TRUE"
261
                    @aro = true
262
                    cnt += 1
263
                  elsif str_aro.upcase == "FALSE"
264
                    @aro = false
265
                    cnt += 1
266
                  end
267
                  if cnt > 1
268
                    @aro = false
269
                    break
270
                  end
271
                end
272
              end
273
            ensure
274
              f.close
275
            end
276
          end
277
          @aro
278
        end
279

  
280
        def scm_cmd(*args, &block)
281
          full_args = []
282
          full_args += args
283
          ret = shellout(
284
                   self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
285
                   &block
286
                   )
287
          if $? && $?.exitstatus != 0
288
            raise ScmCommandAborted, "bzr exited with non-zero status: #{$?.exitstatus}"
289
          end
290
          ret
291
        end
292
        private :scm_cmd
293

  
294
        def scm_cmd_no_raise(*args, &block)
295
          full_args = []
296
          full_args += args
297
          ret = shellout(
298
                   self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
299
                   &block
300
                   )
301
          ret
302
        end
303
        private :scm_cmd_no_raise
304

  
305
        def bzr_target(path)
306
          target(path, false)
307
        end
308
        private :bzr_target
223 309
      end
224 310
    end
225 311
  end
lib/redmine/scm/adapters/cvs_adapter.rb
25 25
        # CVS executable name
26 26
        CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs"
27 27

  
28
        # raised if scm command exited with error, e.g. unknown revision.
29
        class ScmCommandAborted < CommandFailed; end
30

  
31 28
        class << self
32 29
          def client_command
33 30
            @@bin    ||= CVS_BIN
34 31
          end
35 32

  
36 33
          def sq_bin
37
            @@sq_bin ||= shell_quote(CVS_BIN)
34
            @@sq_bin ||= shell_quote_command
38 35
          end
39 36

  
40 37
          def client_version
......
379 376
        end
380 377

  
381 378
        def scm_cmd(*args, &block)
382
          full_args = [CVS_BIN, '-d', root_url]
379
          full_args = ['-d', root_url]
383 380
          full_args += args
384 381
          full_args_locale = []
385 382
          full_args.map do |e|
386 383
            full_args_locale << scm_iconv(@path_encoding, 'UTF-8', e)
387 384
          end
388
          ret = shellout(full_args_locale.map { |e| shell_quote e.to_s }.join(' '), &block)
385
          ret = shellout(
386
                   self.class.sq_bin + ' ' + full_args_locale.map { |e| shell_quote e.to_s }.join(' '),
387
                   &block
388
                   )
389 389
          if $? && $?.exitstatus != 0
390 390
            raise ScmCommandAborted, "cvs exited with non-zero status: #{$?.exitstatus}"
391 391
          end
lib/redmine/scm/adapters/darcs_adapter.rb
31 31
          end
32 32

  
33 33
          def sq_bin
34
            @@sq_bin ||= shell_quote(DARCS_BIN)
34
            @@sq_bin ||= shell_quote_command
35 35
          end
36 36

  
37 37
          def client_version
lib/redmine/scm/adapters/git_adapter.rb
25 25
        # Git executable name
26 26
        GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
27 27

  
28
        # raised if scm command exited with error, e.g. unknown revision.
29
        class ScmCommandAborted < CommandFailed; end
30

  
31 28
        class << self
32 29
          def client_command
33 30
            @@bin    ||= GIT_BIN
34 31
          end
35 32

  
36 33
          def sq_bin
37
            @@sq_bin ||= shell_quote(GIT_BIN)
34
            @@sq_bin ||= shell_quote_command
38 35
          end
39 36

  
40 37
          def client_version
......
80 77
        def branches
81 78
          return @branches if @branches
82 79
          @branches = []
83
          cmd_args = %w|branch --no-color|
80
          cmd_args = %w|branch --no-color --verbose --no-abbrev|
84 81
          scm_cmd(*cmd_args) do |io|
85 82
            io.each_line do |line|
86
              @branches << line.match('\s*\*?\s*(.*)$')[1]
83
              branch_rev = line.match('\s*\*?\s*(.*?)\s*([0-9a-f]{40}).*$')
84
              bran = Branch.new(branch_rev[1])
85
              bran.revision =  branch_rev[2]
86
              bran.scmid    =  branch_rev[2]
87
              @branches << bran
87 88
            end
88 89
          end
89 90
          @branches.sort!
......
188 189

  
189 190
        def revisions(path, identifier_from, identifier_to, options={})
190 191
          revs = Revisions.new
191
          cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller|
192
          cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents|
192 193
          cmd_args << "--reverse" if options[:reverse]
193 194
          cmd_args << "--all" if options[:all]
194 195
          cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit]
......
205 206
            parsing_descr = 0  #0: not parsing desc or files, 1: parsing desc, 2: parsing files
206 207

  
207 208
            io.each_line do |line|
208
              if line =~ /^commit ([0-9a-f]{40})$/
209
              if line =~ /^commit ([0-9a-f]{40})(( [0-9a-f]{40})*)$/
209 210
                key = "commit"
210 211
                value = $1
212
                parents_str = $2
211 213
                if (parsing_descr == 1 || parsing_descr == 2)
212 214
                  parsing_descr = 0
213 215
                  revision = Revision.new({
......
216 218
                    :author     => changeset[:author],
217 219
                    :time       => Time.parse(changeset[:date]),
218 220
                    :message    => changeset[:description],
219
                    :paths      => files
221
                    :paths      => files,
222
                    :parents    => changeset[:parents]
220 223
                  })
221 224
                  if block_given?
222 225
                    yield revision
......
227 230
                  files = []
228 231
                end
229 232
                changeset[:commit] = $1
233
                unless parents_str.nil? or parents_str == ""
234
                  changeset[:parents] = parents_str.strip.split(' ')
235
                end
230 236
              elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
231 237
                key = $1
232 238
                value = $2
......
266 272
                :author     => changeset[:author],
267 273
                :time       => Time.parse(changeset[:date]),
268 274
                :message    => changeset[:description],
269
                :paths      => files
275
                :paths      => files,
276
                :parents    => changeset[:parents]
270 277
                 })
271 278
              if block_given?
272 279
                yield revision
......
359 366

  
360 367
        def scm_cmd(*args, &block)
361 368
          repo_path = root_url || url
362
          full_args = [GIT_BIN, '--git-dir', repo_path]
369
          full_args = ['--git-dir', repo_path]
363 370
          if self.class.client_version_above?([1, 7, 2])
364 371
            full_args << '-c' << 'core.quotepath=false'
365 372
            full_args << '-c' << 'log.decorate=no'
366 373
          end
367 374
          full_args += args
368
          ret = shellout(full_args.map { |e| shell_quote e.to_s }.join(' '), &block)
375
          ret = shellout(
376
                   self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
377
                   &block
378
                   )
369 379
          if $? && $?.exitstatus != 0
370 380
            raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}"
371 381
          end
lib/redmine/scm/adapters/mercurial/hg-template-1.0.tmpl
1 1
changeset = 'This template must be used with --debug option\n'
2 2
changeset_quiet =  'This template must be used with --debug option\n'
3 3
changeset_verbose = 'This template must be used with --debug option\n'
4
changeset_debug = '<logentry revision="{rev}" node="{node|short}">\n<author>{author|escape}</author>\n<date>{date|isodatesec}</date>\n<paths>\n{file_mods}{file_adds}{file_dels}{file_copies}</paths>\n<msg>{desc|escape}</msg>\n{tags}</logentry>\n\n'
4
changeset_debug = '<logentry revision="{rev}" node="{node|short}">\n<author>{author|escape}</author>\n<date>{date|isodatesec}</date>\n<paths>\n{file_mods}{file_adds}{file_dels}{file_copies}</paths>\n<msg>{desc|escape}</msg>\n<parents>\n{parents}</parents>\n</logentry>\n\n'
5 5

  
6 6
file_mod = '<path action="M">{file_mod|urlescape}</path>\n'
7 7
file_add = '<path action="A">{file_add|urlescape}</path>\n'
8 8
file_del = '<path action="D">{file_del|urlescape}</path>\n'
9 9
file_copy = '<path-copied copyfrom-path="{source|urlescape}">{name|urlescape}</path-copied>\n'
10
tag = '<tag>{tag|escape}</tag>\n'
10
parent = '<parent>{node|short}</parent>\n'
11 11
header='<?xml version="1.0" encoding="UTF-8" ?>\n<log>\n\n'
12 12
footer='</log>'
lib/redmine/scm/adapters/mercurial/redminehelper.py
46 46
    </rhmanifest>
47 47
"""
48 48
import re, time, cgi, urllib
49
from mercurial import cmdutil, commands, node, error
49
from mercurial import cmdutil, commands, node, error, hg
50 50

  
51 51
_x = cgi.escape
52 52
_u = lambda s: cgi.escape(urllib.quote(s))
......
146 146
    bra      = urllib.unquote_plus(opts.pop('rhbranch', None))
147 147
    from_rev = from_rev.replace('"', '\\"')
148 148
    to_rev   = to_rev.replace('"', '\\"')
149
    opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
149
    if hg.util.version() >= '1.6':
150
      opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
151
    else:
152
      opts['rev'] = ['%s:%s' % (from_rev, to_rev)]
150 153
    opts['branch'] = [bra]
151 154
    return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts)
152 155

  
......
196 199
                   [
197 200
                    ('r', 'rev', [], 'show the specified revision'),
198 201
                    ('b', 'branch', [],
199
                       'show changesets within the given named branch', 'BRANCH'),
202
                       'show changesets within the given named branch'),
200 203
                    ('l', 'limit', '',
201
                         'limit number of changes displayed', 'NUM'),
204
                         'limit number of changes displayed'),
202 205
                    ('d', 'date', '',
203
                         'show revisions matching date spec', 'DATE'),
206
                         'show revisions matching date spec'),
204 207
                    ('u', 'user', [],
205
                      'revisions committed by user', 'USER'),
208
                      'revisions committed by user'),
206 209
                    ('', 'from', '',
207
                      '', ''),
210
                      ''),
208 211
                    ('', 'to', '',
209
                      '', ''),
212
                      ''),
210 213
                    ('', 'rhbranch', '',
211
                      '', ''),
214
                      ''),
212 215
                    ('', 'template', '',
213
                       'display with template', 'TEMPLATE')],
216
                       'display with template')],
214 217
                   'hg rhlog [OPTION]... [FILE]'),
215 218
    'rhmanifest': (rhmanifest,
216 219
                   [('r', 'rev', '', 'show the specified revision')],
lib/redmine/scm/adapters/mercurial_adapter.rb
39 39
          end
40 40

  
41 41
          def sq_bin
42
            @@sq_bin ||= shell_quote(HG_BIN)
42
            @@sq_bin ||= shell_quote_command
43 43
          end
44 44

  
45 45
          def client_version
......
47 47
          end
48 48

  
49 49
          def client_available
50
            client_version_above?([0, 9, 5])
50
            client_version_above?([1, 2])
51 51
          end
52 52

  
53 53
          def hgversion
......
72 72
          end
73 73

  
74 74
          def template_path_for(version)
75
            if ((version <=> [0,9,5]) > 0) || version.empty?
76
              ver = "1.0"
77
            else
78
              ver = "0.9.5"
79
            end
80
            "#{HELPERS_DIR}/#{TEMPLATE_NAME}-#{ver}.#{TEMPLATE_EXTENSION}"
75
            "#{HELPERS_DIR}/#{TEMPLATE_NAME}-1.0.#{TEMPLATE_EXTENSION}"
81 76
          end
82 77
        end
83 78

  
......
114 109
        end
115 110

  
116 111
        def branches
117
          as_ary(summary['repository']['branch']).map { |e| e['name'] }
112
          brs = []
113
          as_ary(summary['repository']['branch']).each do |e|
114
            br = Branch.new(e['name'])
115
            br.revision =  e['revision']
116
            br.scmid    =  e['node']
117
            brs << br
118
          end
119
          brs
118 120
        end
119 121

  
120 122
        # Returns map of {'branch' => 'nodeid', ...}
......
214 216
               :from_path     => (cpmap.member?(p) ? with_leading_slash(cpmap[p]) : nil),
215 217
               :from_revision => (cpmap.member?(p) ? le['node'] : nil)}
216 218
            end.sort { |a, b| a[:path] <=> b[:path] }
219
            parents_ary = []
220
            as_ary(le['parents']['parent']).map do |par|
221
              parents_ary << par['__content__'] if par['__content__'] != "000000000000"
222
            end
217 223
            yield Revision.new(:revision => le['revision'],
218 224
                               :scmid    => le['node'],
219 225
                               :author   => (le['author']['__content__'] rescue ''),
220 226
                               :time     => Time.parse(le['date']['__content__']),
221 227
                               :message  => le['msg']['__content__'],
222
                               :paths    => paths)
228
                               :paths    => paths,
229
                               :parents  => parents_ary)
223 230
          end
224 231
          self
225 232
        end
......
293 300
        # Runs 'hg' command with the given args
294 301
        def hg(*args, &block)
295 302
          repo_path = root_url || url
296
          full_args = [HG_BIN, '-R', repo_path, '--encoding', 'utf-8']
303
          full_args = ['-R', repo_path, '--encoding', 'utf-8']
297 304
          full_args << '--config' << "extensions.redminehelper=#{HG_HELPER_EXT}"
298 305
          full_args << '--config' << 'diff.git=false'
299 306
          full_args += args
300
          ret = shellout(full_args.map { |e| shell_quote e.to_s }.join(' '), &block)
307
          ret = shellout(
308
                   self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
309
                   &block
310
                   )
301 311
          if $? && $?.exitstatus != 0
302 312
            raise HgCommandAborted, "hg exited with non-zero status: #{$?.exitstatus}"
303 313
          end
lib/redmine/scm/adapters/mercurial_adapter.rb.rej
1
--- lib/redmine/scm/adapters/mercurial_adapter.rb
2
+++ lib/redmine/scm/adapters/mercurial_adapter.rb
3
@@ -67,19 +67,17 @@
4
         end
5
         
6
         def info
7
-          cmd = "#{HG_BIN} -R #{target('')} root"
8
-          root_url = nil
9
-          shellout(cmd) do |io|
10
-            root_url = io.gets
11
-          end
12
-          return nil if $? && $?.exitstatus != 0
13
-          info = Info.new({:root_url => root_url.chomp,
14
-                            :lastrev => revisions(nil,nil,nil,{:limit => 1}).last
15
-                          })
16
-          info
17
-        rescue CommandFailed
18
-          return nil
19
+          tip = summary['tip'].first
20
+          Info.new(:root_url => summary['root'].first['path'],
21
+                   :lastrev => Revision.new(:identifier => tip['rev'].to_i,
22
+                                            :revision => tip['rev'],
23
+                                            :scmid => tip['node']))
24
         end
25
+
26
+        def summary
27
+          @summary ||= fetchg 'rhsummary'
28
+        end
29
+        private :summary
30
         
31
         def entries(path=nil, identifier=nil)
32
           path ||= ''
33
--- lib/redmine/scm/adapters/mercurial_adapter.rb
34
+++ lib/redmine/scm/adapters/mercurial_adapter.rb
35
@@ -74,6 +74,16 @@
36
                                             :scmid => tip['node']))
37
         end
38
 
39
+        def tags
40
+          summary['tags'].map { |e| e['name'] }
41
+        end
42
+
43
+        # Returns map of {'tag' => 'nodeid', ...}
44
+        def tagmap
45
+          alist = summary['tags'].map { |e| e.values_at('name', 'node') }
46
+          Hash[*alist.flatten]
47
+        end
48
+
49
         def summary
50
           @summary ||= fetchg 'rhsummary'
51
         end
52
--- lib/redmine/scm/adapters/mercurial_adapter.rb
53
+++ lib/redmine/scm/adapters/mercurial_adapter.rb
54
@@ -84,6 +84,19 @@
55
           Hash[*alist.flatten]
56
         end
57
 
58
+        def branches
59
+          summary['branches'].map { |e| e['name'] }
60
+        end
61
+
62
+        # Returns map of {'branch' => 'nodeid', ...}
63
+        def branchmap
64
+          alist = summary['branches'].map { |e| e.values_at('name', 'node') }
65
+          Hash[*alist.flatten]
66
+        end
67
+
68
+        # NOTE: DO NOT IMPLEMENT default_branch !!
69
+        # It's used as the default revision by RepositoriesController.
70
+
71
         def summary
72
           @summary ||= fetchg 'rhsummary'
73
         end
lib/redmine/scm/adapters/subversion_adapter.rb
32 32
          end
33 33

  
34 34
          def sq_bin
35
            @@sq_bin ||= shell_quote(SVN_BIN)
35
            @@sq_bin ||= shell_quote_command
36 36
          end
37 37

  
38 38
          def client_version

Also available in: Unified diff