Project

General

Profile

Patch #10470 » 0001-Pass-revisions-to-git-log-via-stdin.patch

Minimal changes to pass all revisions to git-log via stdin - Jeremy Bopp, 2012-03-16 21:16

View differences:

lib/redmine/scm/adapters/abstract_adapter.rb
206 206
          self.class.logger
207 207
        end
208 208

  
209
        def shellout(cmd, &block)
210
          self.class.shellout(cmd, &block)
209
        def shellout(cmd, options = {}, &block)
210
          self.class.shellout(cmd, options, &block)
211 211
        end
212 212

  
213 213
        def self.logger
214 214
          Rails.logger
215 215
        end
216 216

  
217
        def self.shellout(cmd, &block)
217
        def self.shellout(cmd, options = {}, &block)
218 218
          if logger && logger.debug?
219 219
            logger.debug "Shelling out: #{strip_credential(cmd)}"
220 220
          end
......
223 223
            cmd = "#{cmd} 2>>#{shell_quote(Rails.root.join('log/scm.stderr.log').to_s)}"
224 224
          end
225 225
          begin
226
            if RUBY_VERSION < '1.9'
227
              mode = "r+"
228
            else
229
              mode = "r+:ASCII-8BIT"
230
            end
226
            mode = (options[:mode] || 'r').to_s
231 227
            IO.popen(cmd, mode) do |io|
232
              io.close_write
228
              io.set_encoding("ASCII-8BIT") if io.respond_to?(:set_encoding)
233 229
              block.call(io) if block_given?
234 230
            end
235 231
          ## If scm command does not exist,
lib/redmine/scm/adapters/git_adapter.rb
82 82
          return @branches if @branches
83 83
          @branches = []
84 84
          cmd_args = %w|branch --no-color --verbose --no-abbrev|
85
          scm_cmd(*cmd_args) do |io|
85
          scm_cmd(cmd_args) do |io|
86 86
            io.each_line do |line|
87 87
              branch_rev = line.match('\s*(\*?)\s*(.*?)\s*([0-9a-f]{40}).*$')
88 88
              bran = GitBranch.new(branch_rev[2])
......
100 100
        def tags
101 101
          return @tags if @tags
102 102
          cmd_args = %w|tag|
103
          scm_cmd(*cmd_args) do |io|
103
          scm_cmd(cmd_args) do |io|
104 104
            @tags = io.readlines.sort!.map{|t| t.strip}
105 105
          end
106 106
        rescue ScmCommandAborted
......
138 138
          cmd_args = %w|ls-tree -l|
139 139
          cmd_args << "HEAD:#{p}"          if identifier.nil?
140 140
          cmd_args << "#{identifier}:#{p}" if identifier
141
          scm_cmd(*cmd_args) do |io|
141
          scm_cmd(cmd_args) do |io|
142 142
            io.each_line do |line|
143 143
              e = line.chomp.to_s
144 144
              if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/
......
173 173
          cmd_args << rev if rev
174 174
          cmd_args << "--" << path unless path.empty?
175 175
          lines = []
176
          scm_cmd(*cmd_args) { |io| lines = io.readlines }
176
          scm_cmd(cmd_args) { |io| lines = io.readlines }
177 177
          begin
178 178
              id = lines[0].split[1]
179 179
              author = lines[1].match('Author:\s+(.*)$')[1]
......
197 197

  
198 198
        def revisions(path, identifier_from, identifier_to, options={})
199 199
          revs = Revisions.new
200
          cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents|
200
          cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents --stdin|
201 201
          cmd_args << "--reverse" if options[:reverse]
202 202
          cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit]
203
          from_to = ""
203
          cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty?
204
          revisions = []
204 205
          if identifier_from || identifier_to
205
            from_to << "#{identifier_from}.." if identifier_from
206
            from_to << "#{identifier_to}" if identifier_to
207
            cmd_args << from_to if !from_to.empty?
206
            revisions << ""
207
            revisions[0] << "#{identifier_from}.." if identifier_from
208
            revisions[0] << "#{identifier_to}" if identifier_to
208 209
          else
209
            cmd_args += options[:includes] unless options[:includes].blank?
210
            unless options[:includes].blank?
211
              revisions += ignore_missing_revisions(options[:includes])
212
            end
210 213
            unless options[:excludes].blank?
211
              cmd_args << "--not"
212
              cmd_args += options[:excludes]
214
              revisions +=
215
                ignore_missing_revisions(options[:excludes]).map{|r| "^#{r}"}
213 216
            end
214 217
          end
215
          cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty?
216 218

  
217
          scm_cmd *cmd_args do |io|
219
          scm_cmd(cmd_args, :mode => "r+b") do |io|
220
            io.puts(revisions.join("\n"))
221
            io.close_write
222

  
218 223
            files=[]
219 224
            changeset = {}
220 225
            parsing_descr = 0  #0: not parsing desc or files, 1: parsing desc, 2: parsing files
......
317 322
          end
318 323
          cmd_args << "--" <<  scm_iconv(@path_encoding, 'UTF-8', path) unless path.empty?
319 324
          diff = []
320
          scm_cmd *cmd_args do |io|
325
          scm_cmd cmd_args do |io|
321 326
            io.each_line do |line|
322 327
              diff << line
323 328
            end
......
333 338
          cmd_args << "-p" << identifier << "--" <<  scm_iconv(@path_encoding, 'UTF-8', path)
334 339
          blame = Annotate.new
335 340
          content = nil
336
          scm_cmd(*cmd_args) { |io| io.binmode; content = io.read }
341
          scm_cmd(cmd_args) { |io| io.binmode; content = io.read }
337 342
          # git annotates binary files
338 343
          return nil if content.is_binary_data?
339 344
          identifier = ''
......
367 372
          cmd_args = %w|show --no-color|
368 373
          cmd_args << "#{identifier}:#{scm_iconv(@path_encoding, 'UTF-8', path)}"
369 374
          cat = nil
370
          scm_cmd(*cmd_args) do |io|
375
          scm_cmd(cmd_args) do |io|
371 376
            io.binmode
372 377
            cat = io.read
373 378
          end
......
383 388
          end
384 389
        end
385 390

  
386
        def scm_cmd(*args, &block)
391
        def scm_cmd(args, options = {}, &block)
387 392
          repo_path = root_url || url
388 393
          full_args = ['--git-dir', repo_path]
389 394
          if self.class.client_version_above?([1, 7, 2])
......
393 398
          full_args += args
394 399
          ret = shellout(
395 400
                   self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
401
                   options,
396 402
                   &block
397 403
                   )
398 404
          if $? && $?.exitstatus != 0
......
401 407
          ret
402 408
        end
403 409
        private :scm_cmd
410

  
411
        # Return an array containing only the given revisions that exist in the
412
        # repository.
413
        #
414
        # NOTE:
415
        # This can be removed once the minimum supported Git version supports
416
        # the --ignore-missing option for git-log and #revisions is modified to
417
        # use that option.
418
        def ignore_missing_revisions(revisions)
419
          revisions.select do |revision|
420
            begin
421
              cmd_args = %w|rev-parse --verify --quiet|
422
              cmd_args << revision
423
              scm_cmd(cmd_args) do |io|
424
                # Read and discard the output in order to make the command
425
                # happy.
426
                io.read
427
              end
428
              true
429
            rescue ScmCommandAborted
430
              false
431
            end
432
          end
433
        end
434
        private :ignore_missing_revisions
404 435
      end
405 436
    end
406 437
  end
test/unit/lib/redmine/scm/adapters/git_adapter_test.rb
289 289
      end
290 290

  
291 291
      def test_revisions_invalid_rev_excludes
292
        assert_equal [],
293
                     @adapter.revisions('', nil, nil,
294
                                        {:reverse => true,
295
                                         :includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c'],
296
                                         :excludes => ['0123abcd4567']})
297
        assert_raise Redmine::Scm::Adapters::CommandFailed do
298
          revs1 = []
299
          @adapter.revisions('', nil, nil,
300
                             {:reverse => true,
301
                              :includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c'],
302
                              :excludes => ['0123abcd4567']}) do |rev|
303
            revs1 << rev
304
          end
292
        revs1 = @adapter.revisions('', nil, nil,
293
                                   {:reverse => true,
294
                                    :includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c'],
295
                                    :excludes => ['0123abcd4567']})
296
        assert_equal 15, revs1.length
297
        assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[-1].identifier
298
        assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[ 0].identifier
299

  
300
        revs2 = []
301
        @adapter.revisions('', nil, nil,
302
                           {:reverse => true,
303
                            :includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c'],
304
                            :excludes => ['0123abcd4567']}) do |rev|
305
          revs2 << rev
305 306
        end
307
        assert_equal 15, revs2.length
308
        assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier
309
        assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier
306 310
      end
307 311

  
308 312
      def test_getting_revisions_with_spaces_in_filename
(1-1/2)