diff --git a/Gemfile b/Gemfile
index 6a2e3a54f..5b3de9bfa 100644
--- a/Gemfile
+++ b/Gemfile
@@ -30,7 +30,7 @@ gem 'state_machines-activerecord'
gem 'redis-rails'
gem 'grack', git: 'git://github.com/rosa-abf/grack.git', require: 'git_http'
-gem 'grit', git: 'git://github.com/rosa-abf/grit.git', tag: '2.6.16'
+gem 'grit', git: 'git://github.com/rosa-abf/grit.git', tag: '2.6.17'
gem 'charlock_holmes'
gem 'github-linguist', '3.1.5', require: 'linguist'
gem 'diff-display'
diff --git a/Gemfile.lock b/Gemfile.lock
index f62782e8b..ea370ee06 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -41,8 +41,8 @@ GIT
GIT
remote: git://github.com/rosa-abf/grit.git
- revision: a9548c92188cc307e7af1dd41a733e7000a783a9
- tag: 2.6.16
+ revision: b733f0ceefb44b18a9dec8f509ba5493dab59e4e
+ tag: 2.6.17
specs:
grit (2.5.0)
diff-lcs (~> 1.1)
diff --git a/app/helpers/commit_helper.rb b/app/helpers/commit_helper.rb
index f3282580b..2935e2f0d 100644
--- a/app/helpers/commit_helper.rb
+++ b/app/helpers/commit_helper.rb
@@ -1,23 +1,35 @@
module CommitHelper
MAX_FILES_WITHOUT_COLLAPSE = 25
- def render_commit_stats(stats)
- res = ["
"]
+ def render_commit_stats(stats, diff)
+ res = [""]
ind=0
stats.files.each do |filename, adds, deletes, total|
- res << ""
- res << "#{h(filename.rtruncate 120)} | "
- res << ""
- res << I18n.t("layout.projects.inline_changes_count", count: total).strip +
- " (" +
- I18n.t("layout.projects.inline_additions_count", count: adds).strip +
- ", " +
- I18n.t("layout.projects.inline_deletions_count", count: deletes).strip +
- ")"
- res << " | "
+ file_name = if diff[ind].renamed_file
+ "#{diff[ind].a_path.rtruncate 60}=>#{diff[ind].b_path.rtruncate 60}"
+ else
+ filename.rtruncate(120)
+ end
+
+ res << "- "
+ res << "
"
+ res << "
"
+
+ res << "
"
+ res << "
"
+ res << "+#{adds} -#{deletes}"
+ res << "
"
+ res << "
"
+
+ res << "
"
+ res << render_progress_bar(adds, deletes)
+ res << "
"
+
+ res << "
"
ind +=1
end
- res << "
"
+ res << ""
wrap_commit_header_list(stats, res)
end
@@ -73,9 +85,41 @@ module CommitHelper
Russian.p(commits_count, *commits_pluralization_arr)
end
+ def is_file_open_in_diff(blob, diff)
+ return true if blob.binary? && blob.render_as == :image
+ return true if diff.diff.blank? && diff.a_mode != diff.b_mode
+ diff.diff.present? && diff.diff.split("\n").count <= DiffHelper::MAX_LINES_WITHOUT_COLLAPSE
+ end
+
protected
def commits_pluralization_arr
pluralize ||= t('layout.commits.pluralize').map {|base, title| title.to_s}
end
+
+ def render_progress_bar(adds, deletes)
+ return if adds+deletes == 0
+ res = ''
+ pluses = ((adds/(adds+deletes).to_f)*100).round
+ minuses = 100 - pluses
+
+ res << ""
+ res << "
"
+ res << "
"
+ res << "
"
+ res
+ end
+
+ def diff_file_icon(diff)
+ icon = if diff.renamed_file
+ 'fa-caret-square-o-right text-info'
+ elsif diff.new_file
+ 'fa-plus-square text-success'
+ elsif diff.deleted_file
+ 'fa-minus-square text-danger'
+ else
+ 'fa-pencil-square text-warning'
+ end
+ ""
+ end
end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index afa4b193a..f9877b22f 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -2,7 +2,7 @@ module DiffHelper
MAX_FILES_WITHOUT_COLLAPSE = 25
MAX_LINES_WITHOUT_COLLAPSE = 50
- def render_diff_stats(stats)
+ def render_diff_stats(stats, diff)
res = [""]
stats.each_with_index do |stat, ind|
res << ""
diff --git a/app/views/projects/git/commits/_diff.html.slim b/app/views/projects/git/commits/_diff.html.slim
index 2d3189d13..395fb34f7 100644
--- a/app/views/projects/git/commits/_diff.html.slim
+++ b/app/views/projects/git/commits/_diff.html.slim
@@ -1,9 +1,11 @@
- commit_id = diff.deleted_file ? parent_commit.try(:id) : @commit.id
- diff_counter_content = "diff-#{diff_counter}_content"
-
-- if diff.diff.present?
+- if diff.renamed_file
+ - blob = @project.repo.tree(commit_id) / diff.b_path
+- else
- blob = @project.repo.tree(commit_id) / diff.a_path
- - is_file_open = 'in' if !blob.binary? && diff.diff.split("\n").count <= DiffHelper::MAX_LINES_WITHOUT_COLLAPSE
+
+- is_file_open = 'in' if is_file_open_in_diff(blob, diff)
.file.offset10
a name = "diff-#{diff_counter}"
@@ -34,3 +36,5 @@
- if (@project.repo.tree(commit_id) / diff.b_path).nil?
= "a_path=#{diff.a_path}; b_path=#{diff.b_path}"
== render_diff(diff, diff_counter: diff_counter, comments: @comments)
+ - if diff.a_mode != diff.b_mode && diff.diff.blank?
+ == render 'file_change_mode', blob: blob, diff: diff, diff_counter_content: diff_counter_content
diff --git a/app/views/projects/git/commits/_show.html.slim b/app/views/projects/git/commits/_show.html.slim
index bc9187fba..ecec19721 100644
--- a/app/views/projects/git/commits/_show.html.slim
+++ b/app/views/projects/git/commits/_show.html.slim
@@ -1,6 +1,7 @@
- begin
- - stats = @commit.stats
- = render_commit_stats(stats)
+ - diffs = @commit.show
+ - stats = Grit::CommitStats.find_all(@project.repo, @commit.sha, max_count: 1, skip: 0, M: true)[0][-1]
+ = render_commit_stats(stats, diffs)
.pull-right
=> link_to 'raw diff', commit_path(@project, @commit.id, :diff)
@@ -8,6 +9,6 @@
=< link_to 'patch', commit_path(@project, @commit.id, :patch)
.clearfix
- == render partial: 'diff', collection: @commit.diffs, locals: { parent_commit: @commit.parents.try(:first) }
+ == render partial: 'diff', collection: diffs, locals: { parent_commit: @commit.parents.try(:first) }
- rescue Grit::Git::GitTimeout
h3.text-danger= t('layout.git.repositories.commit_diff_too_big')
diff --git a/app/views/projects/git/commits/diff.html.slim b/app/views/projects/git/commits/diff.html.slim
index 7a04db0b4..d11e63f4e 100644
--- a/app/views/projects/git/commits/diff.html.slim
+++ b/app/views/projects/git/commits/diff.html.slim
@@ -21,8 +21,9 @@
deletions: t("layout.projects.commit_deletions_count", count: total_deletions))
-begin
- == render_diff_stats @stats
- - diffs = Grit::Commit.diff(@project.repo, @common_ancestor.id, @commit.id)
+ - diffs = @project.repo.diff @common_ancestor.id, @commit.id
+ == render_diff_stats @stats, diffs
+ -# diffs = Grit::Commit.diff(@project.repo, @common_ancestor.id, @commit.id)
== render partial: 'projects/git/commits/diff', collection: diffs, locals: { parent_commit: @common_ancestor }
- rescue Grit::Git::GitTimeout
diff --git a/app/views/projects/pull_requests/_diff_tab.html.slim b/app/views/projects/pull_requests/_diff_tab.html.slim
index 095c93fe9..fc9c3df14 100644
--- a/app/views/projects/pull_requests/_diff_tab.html.slim
+++ b/app/views/projects/pull_requests/_diff_tab.html.slim
@@ -1,6 +1,7 @@
-begin
- == render_diff_stats(@stats)
- == render partial: 'pull_diff', collection: @pull.diff
+ - diff = @pull.diff
+ == render_diff_stats(@stats, diff)
+ == render partial: 'pull_diff', collection: diff
- rescue => ex
-if ex.try(:message) == 'Grit::Git::GitTimeout'
p= t 'layout.git.repositories.commit_diff_too_big'
diff --git a/lib/ext/core/string.rb b/lib/ext/core/string.rb
index b22e3dee6..b8837a085 100644
--- a/lib/ext/core/string.rb
+++ b/lib/ext/core/string.rb
@@ -7,7 +7,9 @@ class String
force_encoding(default_encoding)
else # should encode
options = {invalid: :replace, undef: :replace, replace: ''}
- if (detected = detect_encoding) && detected[:encoding]
+ if encoding.name == 'UTF-8'
+ encode!(default_encoding, 'UTF-8', options)
+ elsif (detected = detect_encoding) && detected[:encoding]
force_encoding(detected[:encoding]).encode!(default_encoding, detected[:encoding], options)
end
scrub('')
diff --git a/lib/ext/git/grit.rb b/lib/ext/git/grit.rb
index 62ca5dc6a..0b1a70980 100644
--- a/lib/ext/git/grit.rb
+++ b/lib/ext/git/grit.rb
@@ -64,7 +64,6 @@ module Grit
def diff(a, b, *paths)
diff = self.git.native('diff', {M: true}, "#{a}...#{b}", '--', *paths)
-
if diff =~ /diff --git a/
diff = diff.sub(/.*?(diff --git a)/m, '\1')
else
diff --git a/lib/ext/posix_spawn.rb b/lib/ext/posix_spawn.rb
new file mode 100644
index 000000000..bd708da07
--- /dev/null
+++ b/lib/ext/posix_spawn.rb
@@ -0,0 +1,101 @@
+require 'posix/spawn'
+
+module POSIX
+ module Spawn
+ class Child
+ include POSIX::Spawn
+ private
+ # Start a select loop writing any input on the child's stdin and reading
+ # any output from the child's stdout or stderr.
+ #
+ # input - String input to write on stdin. May be nil.
+ # stdin - The write side IO object for the child's stdin stream.
+ # stdout - The read side IO object for the child's stdout stream.
+ # stderr - The read side IO object for the child's stderr stream.
+ # timeout - An optional Numeric specifying the total number of seconds
+ # the read/write operations should occur for.
+ #
+ # Returns an [out, err] tuple where both elements are strings with all
+ # data written to the stdout and stderr streams, respectively.
+ # Raises TimeoutExceeded when all data has not been read / written within
+ # the duration specified in the timeout argument.
+ # Raises MaximumOutputExceeded when the total number of bytes output
+ # exceeds the amount specified by the max argument.
+ def read_and_write(input, stdin, stdout, stderr, timeout=nil, max=nil)
+ max = nil if max && max <= 0
+ @out, @err = '', ''
+ offset = 0
+
+ # force all string and IO encodings to BINARY under 1.9 for now
+ #if @out.respond_to?(:force_encoding) and stdin.respond_to?(:set_encoding)
+ # [stdin, stdout, stderr].each do |fd|
+ # fd.set_encoding('BINARY', 'BINARY')
+ # end
+ # @out.force_encoding('BINARY')
+ # @err.force_encoding('BINARY')
+ # input = input.dup.force_encoding('BINARY') if input
+ #end
+
+ timeout = nil if timeout && timeout <= 0.0
+ @runtime = 0.0
+ start = Time.now
+
+ readers = [stdout, stderr]
+ writers =
+ if input
+ [stdin]
+ else
+ stdin.close
+ []
+ end
+ slice_method = input.respond_to?(:byteslice) ? :byteslice : :slice
+ t = timeout
+
+ while readers.any? || writers.any?
+ ready = IO.select(readers, writers, readers + writers, t)
+ raise TimeoutExceeded if ready.nil?
+
+ # write to stdin stream
+ ready[1].each do |fd|
+ begin
+ boom = nil
+ size = fd.write_nonblock(input)
+ input = input.send(slice_method, size..-1)
+ rescue Errno::EPIPE => boom
+ rescue Errno::EAGAIN, Errno::EINTR
+ end
+ if boom || input.bytesize == 0
+ stdin.close
+ writers.delete(stdin)
+ end
+ end
+
+ # read from stdout and stderr streams
+ ready[0].each do |fd|
+ buf = (fd == stdout) ? @out : @err
+ begin
+ buf << fd.readpartial(BUFSIZE)
+ rescue Errno::EAGAIN, Errno::EINTR
+ rescue EOFError
+ readers.delete(fd)
+ fd.close
+ end
+ end
+
+ # keep tabs on the total amount of time we've spent here
+ @runtime = Time.now - start
+ if timeout
+ t = timeout - @runtime
+ raise TimeoutExceeded if t < 0.0
+ end
+
+ # maybe we've hit our max output
+ if max && ready[0].any? && (@out.size + @err.size) > max
+ raise MaximumOutputExceeded
+ end
+ end
+ [@out.mb_chars.default_encoding!, @err.mb_chars.default_encoding!]
+ end
+ end
+ end
+end