new diff; in progress

This commit is contained in:
Alexander Machehin 2015-04-06 22:44:37 +05:00
parent f5a68ed4ae
commit f202d1d449
11 changed files with 182 additions and 29 deletions

View File

@ -30,7 +30,7 @@ gem 'state_machines-activerecord'
gem 'redis-rails' gem 'redis-rails'
gem 'grack', git: 'git://github.com/rosa-abf/grack.git', require: 'git_http' 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 'charlock_holmes'
gem 'github-linguist', '3.1.5', require: 'linguist' gem 'github-linguist', '3.1.5', require: 'linguist'
gem 'diff-display' gem 'diff-display'

View File

@ -41,8 +41,8 @@ GIT
GIT GIT
remote: git://github.com/rosa-abf/grit.git remote: git://github.com/rosa-abf/grit.git
revision: a9548c92188cc307e7af1dd41a733e7000a783a9 revision: b733f0ceefb44b18a9dec8f509ba5493dab59e4e
tag: 2.6.16 tag: 2.6.17
specs: specs:
grit (2.5.0) grit (2.5.0)
diff-lcs (~> 1.1) diff-lcs (~> 1.1)

View File

@ -1,23 +1,35 @@
module CommitHelper module CommitHelper
MAX_FILES_WITHOUT_COLLAPSE = 25 MAX_FILES_WITHOUT_COLLAPSE = 25
def render_commit_stats(stats) def render_commit_stats(stats, diff)
res = ["<table class='table table-responsive boffset0'>"] res = ["<ul class='list-group boffset0'>"]
ind=0 ind=0
stats.files.each do |filename, adds, deletes, total| stats.files.each do |filename, adds, deletes, total|
res << "<tr>" file_name = if diff[ind].renamed_file
res << "<td><a href='#diff-#{ind}'>#{h(filename.rtruncate 120)}</a></td>" "#{diff[ind].a_path.rtruncate 60}=>#{diff[ind].b_path.rtruncate 60}"
res << "<td class='diffstat'>" else
res << I18n.t("layout.projects.inline_changes_count", count: total).strip + filename.rtruncate(120)
" (" + end
I18n.t("layout.projects.inline_additions_count", count: adds).strip +
", " + res << "<li class='list-group-item'>"
I18n.t("layout.projects.inline_deletions_count", count: deletes).strip + res << "<div class='row'>"
")" res << "<div class='col-sm-8'><a href='#diff-#{ind}'>#{diff_file_icon(diff[ind])} #{h(file_name)}</a></div>"
res << "</td>"
res << "<div class='col-sm-2'>"
res << "<div class='pull-right'>"
res << "<strong class='text-success'>+#{adds}</strong> <strong class='text-danger'>-#{deletes}</strong>"
res << "</div>"
res << "</div>"
res << "<div class='col-sm-2'>"
res << render_progress_bar(adds, deletes)
res << "</div>"
res << "</div"
res << "</li>"
ind +=1 ind +=1
end end
res << "</table>" res << "</ul>"
wrap_commit_header_list(stats, res) wrap_commit_header_list(stats, res)
end end
@ -73,9 +85,41 @@ module CommitHelper
Russian.p(commits_count, *commits_pluralization_arr) Russian.p(commits_count, *commits_pluralization_arr)
end 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 protected
def commits_pluralization_arr def commits_pluralization_arr
pluralize ||= t('layout.commits.pluralize').map {|base, title| title.to_s} pluralize ||= t('layout.commits.pluralize').map {|base, title| title.to_s}
end 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 << "<div class='progress' style='margin-bottom: 0'>"
res << "<div class='progress-bar progress-bar-success' style='width: #{pluses}%'></div>"
res << "<div class='progress-bar progress-bar-danger' style='width: #{minuses}%'></div>"
res << "</div>"
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
"<i class='fa #{icon}'></i>"
end
end end

View File

@ -2,7 +2,7 @@ module DiffHelper
MAX_FILES_WITHOUT_COLLAPSE = 25 MAX_FILES_WITHOUT_COLLAPSE = 25
MAX_LINES_WITHOUT_COLLAPSE = 50 MAX_LINES_WITHOUT_COLLAPSE = 50
def render_diff_stats(stats) def render_diff_stats(stats, diff)
res = ["<table class='table table-responsive boffset0'>"] res = ["<table class='table table-responsive boffset0'>"]
stats.each_with_index do |stat, ind| stats.each_with_index do |stat, ind|
res << "<tr>" res << "<tr>"

View File

@ -1,9 +1,11 @@
- commit_id = diff.deleted_file ? parent_commit.try(:id) : @commit.id - commit_id = diff.deleted_file ? parent_commit.try(:id) : @commit.id
- diff_counter_content = "diff-#{diff_counter}_content" - diff_counter_content = "diff-#{diff_counter}_content"
- if diff.renamed_file
- if diff.diff.present? - blob = @project.repo.tree(commit_id) / diff.b_path
- else
- blob = @project.repo.tree(commit_id) / diff.a_path - 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 .file.offset10
a name = "diff-#{diff_counter}" a name = "diff-#{diff_counter}"
@ -34,3 +36,5 @@
- if (@project.repo.tree(commit_id) / diff.b_path).nil? - if (@project.repo.tree(commit_id) / diff.b_path).nil?
= "a_path=#{diff.a_path}; b_path=#{diff.b_path}" = "a_path=#{diff.a_path}; b_path=#{diff.b_path}"
== render_diff(diff, diff_counter: diff_counter, comments: @comments) == 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

View File

@ -1,6 +1,7 @@
- begin - begin
- stats = @commit.stats - diffs = @commit.show
= render_commit_stats(stats) - 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 .pull-right
=> link_to 'raw diff', commit_path(@project, @commit.id, :diff) => link_to 'raw diff', commit_path(@project, @commit.id, :diff)
@ -8,6 +9,6 @@
=< link_to 'patch', commit_path(@project, @commit.id, :patch) =< link_to 'patch', commit_path(@project, @commit.id, :patch)
.clearfix .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 - rescue Grit::Git::GitTimeout
h3.text-danger= t('layout.git.repositories.commit_diff_too_big') h3.text-danger= t('layout.git.repositories.commit_diff_too_big')

View File

@ -21,8 +21,9 @@
deletions: t("layout.projects.commit_deletions_count", count: total_deletions)) deletions: t("layout.projects.commit_deletions_count", count: total_deletions))
-begin -begin
== render_diff_stats @stats - diffs = @project.repo.diff @common_ancestor.id, @commit.id
- diffs = Grit::Commit.diff(@project.repo, @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 } == render partial: 'projects/git/commits/diff', collection: diffs, locals: { parent_commit: @common_ancestor }
- rescue Grit::Git::GitTimeout - rescue Grit::Git::GitTimeout

View File

@ -1,6 +1,7 @@
-begin -begin
== render_diff_stats(@stats) - diff = @pull.diff
== render partial: 'pull_diff', collection: @pull.diff == render_diff_stats(@stats, diff)
== render partial: 'pull_diff', collection: diff
- rescue => ex - rescue => ex
-if ex.try(:message) == 'Grit::Git::GitTimeout' -if ex.try(:message) == 'Grit::Git::GitTimeout'
p= t 'layout.git.repositories.commit_diff_too_big' p= t 'layout.git.repositories.commit_diff_too_big'

View File

@ -7,7 +7,9 @@ class String
force_encoding(default_encoding) force_encoding(default_encoding)
else # should encode else # should encode
options = {invalid: :replace, undef: :replace, replace: ''} 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) force_encoding(detected[:encoding]).encode!(default_encoding, detected[:encoding], options)
end end
scrub('') scrub('')

View File

@ -64,7 +64,6 @@ module Grit
def diff(a, b, *paths) def diff(a, b, *paths)
diff = self.git.native('diff', {M: true}, "#{a}...#{b}", '--', *paths) diff = self.git.native('diff', {M: true}, "#{a}...#{b}", '--', *paths)
if diff =~ /diff --git a/ if diff =~ /diff --git a/
diff = diff.sub(/.*?(diff --git a)/m, '\1') diff = diff.sub(/.*?(diff --git a)/m, '\1')
else else

101
lib/ext/posix_spawn.rb Normal file
View File

@ -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