Commit 21ae869d authored by Enrique García Cota's avatar Enrique García Cota

increased scm file download in scm views

parent c4f80d5e
...@@ -118,41 +118,48 @@ class RepositoriesController < ApplicationController ...@@ -118,41 +118,48 @@ class RepositoriesController < ApplicationController
# If the entry is a dir, show the browser # If the entry is a dir, show the browser
(show; return) if @entry.is_dir? (show; return) if @entry.is_dir?
@content = @repository.cat(@path, @rev) @repository.cat_to_tempfile(@path, @rev) do |f|
(show_error_not_found; return) unless @content if params[:format] == 'raw' || is_too_large_to_show?(f) || is_binary?(f, @path)
if 'raw' == params[:format] || send_type = Redmine::MimeType.of(@path)
(@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) || options = {
! is_entry_text_data?(@content, @path) :filename => filename_for_content_disposition(@path.split('/').last),
# Force the download :disposition => 'attachment',
send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) } :x_sendfile => false # x_sendfile does not work well with tempfiles
send_type = Redmine::MimeType.of(@path) }
send_opt[:type] = send_type.to_s if send_type options[:type] = send_type.to_s if send_type
send_data @content, send_opt send_file(f.path, options)
else else
# Prevent empty lines when displaying a file with Windows style eol @content = f.read
# TODO: UTF-16 @changeset = @repository.find_changeset_by_name(@rev)
# Is this needs? AttachmentsController reads file simply. end
@content.gsub!("\r\n", "\n")
@changeset = @repository.find_changeset_by_name(@rev)
end end
rescue Errno::ENOENT
show_error_not_found
end end
def is_entry_text_data?(ent, path) def is_too_large_to_show?(f)
# UTF-16 contains "\x00". f.size > Setting.file_max_size_displayed.to_i.kilobyte
# It is very strict that file contains less than 30% of ascii symbols end
# in non Western Europe. private :is_too_large_to_show?
return true if Redmine::MimeType.is_type?('text', path)
# Ruby 1.8.6 has a bug of integer divisions. def is_binary?(file, path)
# http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
if ent.respond_to?("is_binary_data?") && ent.is_binary_data? # Ruby 1.8.x and <1.9.2 return false if Redmine::MimeType.is_type?('text', path)
return false
elsif ent.respond_to?(:force_encoding) && (ent.dup.force_encoding("UTF-8") != ent.dup.force_encoding("BINARY") ) # Ruby 1.9.2 # First block of the file is examined for odd
# TODO: need to handle edge cases of non-binary content that isn't UTF-8 # characters such as strange control codes or char-
return false # acters with the high bit set. If too many strange
end # characters (>30%) are found, it's a binary file,
true # otherwise it's a text file. Also, any file con-
# taining null in the first block is considered a
# binary file.
blk = file.read(Setting.file_max_size_displayed.to_i.kilobyte)
return blk.size == 0 ||
blk.count("^ -~", "^\r\n") / blk.size > 0.3 ||
blk.count("\x00") > 0
end end
private :is_entry_text_data? private :is_binary?
def annotate def annotate
@entry = @repository.entry(@path, @rev) @entry = @repository.entry(@path, @rev)
......
...@@ -104,6 +104,10 @@ class Repository < ActiveRecord::Base ...@@ -104,6 +104,10 @@ class Repository < ActiveRecord::Base
scm.cat(path, identifier) scm.cat(path, identifier)
end end
def cat_to_tempfile(path, identifier, &block)
scm.cat_to_tempfile(path, identifier, &block)
end
def diff(path, rev, rev_to) def diff(path, rev, rev_to)
scm.diff(path, rev, rev_to) scm.diff(path, rev, rev_to)
end end
......
...@@ -69,7 +69,7 @@ module Redmine ...@@ -69,7 +69,7 @@ module Redmine
end end
def adapter_name def adapter_name
'Abstract' self.class.name.gsub("Adapter","")
end end
def supports_cat? def supports_cat?
...@@ -143,6 +143,19 @@ module Redmine ...@@ -143,6 +143,19 @@ module Redmine
return nil return nil
end end
def cat_to_tempfile(path, identifier, &block)
prefix = path.split("/").last
tmp_path = Rails.root.join('tmp')
Tempfile.open(prefix, tmp_path) do |f|
save_entry_in_file(f,path,identifier)
block.call(f)
end
end
def save_entry_in_file(file, path, identifier)
return nil
end
def with_leading_slash(path) def with_leading_slash(path)
path ||= '' path ||= ''
(path[0,1]!="/") ? "/#{path}" : path (path[0,1]!="/") ? "/#{path}" : path
...@@ -183,34 +196,56 @@ module Redmine ...@@ -183,34 +196,56 @@ module Redmine
self.class.logger self.class.logger
end end
def shellout(cmd, &block) def shellout(cmd, output_path=nil, &block)
self.class.shellout(cmd, &block) self.class.shellout(cmd, output_path, &block)
end
def build_scm_cmd(cmd_args)
([ self.class.sq_bin ] + cmd_args).join(' ')
end
def scm_cmd(cmd_args, output_path=nil, &block)
cmd = build_scm_cmd(cmd_args)
begin
ret = shellout(cmd, output_path, &block)
rescue Exception => e
msg = strip_credential(e.message)
cmd = strip_credential(cmd)
logger.error("Error executing #{adapter_name} command [#{cmd}]: #{msg}")
end
return nil if $? && $?.exitstatus != 0
ret
end end
def self.logger def self.logger
RAILS_DEFAULT_LOGGER RAILS_DEFAULT_LOGGER
end end
def self.shellout(cmd, &block) def self.process_cmd(cmd, output_path)
logger.debug "Shelling out: #{strip_credential(cmd)}" if logger && logger.debug? cmd = Rails.env == 'development' ? "#{cmd} 2>>#{RAILS_ROOT}/log/scm.stderr.log" : cmd
if Rails.env == 'development' cmd = "#{cmd} >> #{output_path}" if output_path.present?
# Capture stderr when running in dev environment cmd
cmd = "#{cmd} 2>>#{RAILS_ROOT}/log/scm.stderr.log" end
end
def self.get_reading_mode_for_ruby_version
RUBY_VERSION < '1.9' ? 'r+' : 'r+:ASCII-8BIT'
end
def self.shellout(cmd, output_path=nil, &block)
logger.debug("Shelling out: #{strip_credential(cmd)}") if logger && logger.respond_to?(:debug)
cmd = process_cmd(cmd, output_path)
mode = get_reading_mode_for_ruby_version
begin begin
if RUBY_VERSION < '1.9' result = nil
mode = "r+"
else
mode = "r+:ASCII-8BIT"
end
IO.popen(cmd, mode) do |io| IO.popen(cmd, mode) do |io|
io.close_write io.close_write
block.call(io) if block_given? result = block.call(io) if block_given?
end end
result
rescue Errno::ENOENT => e rescue Errno::ENOENT => e
msg = strip_credential(e.message) msg = strip_credential(e.message)
# The command failed, log it and re-raise cmd = strip_credential(cmd)
logger.error("SCM command failed, make sure that your SCM binary (eg. svn) is in PATH (#{ENV['PATH']}): #{strip_credential(cmd)}\n with: #{msg}") logger.error("SCM command failed, make sure that your SCM binary (eg. svn) is in PATH (#{ENV['PATH']}): #{cmd}\n with: #{msg}")
raise CommandFailed.new(msg) raise CommandFailed.new(msg)
end end
end end
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/abstract_adapter' require_dependency 'redmine/scm/adapters/abstract_adapter'
module Redmine module Redmine
module Scm module Scm
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/abstract_adapter' require_dependency 'redmine/scm/adapters/abstract_adapter'
module Redmine module Redmine
module Scm module Scm
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/abstract_adapter' require_dependency 'redmine/scm/adapters/abstract_adapter'
require 'rexml/document' require 'rexml/document'
module Redmine module Redmine
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/abstract_adapter' require_dependency 'redmine/scm/adapters/abstract_adapter'
require 'find' require 'find'
module Redmine module Redmine
...@@ -91,6 +91,14 @@ module Redmine ...@@ -91,6 +91,14 @@ module Redmine
raise CommandFailed.new(err.message) raise CommandFailed.new(err.message)
end end
def save_entry_in_file(f, path, identifier)
p = scm_iconv(@path_encoding, 'UTF-8', target(path))
FileUtils.cp(p, f.path)
rescue => err
logger.error "scm: filesystem: error: #{err.message}"
raise CommandFailed.new(err.message)
end
private private
# AbstractAdapter::target is implicitly made to quote paths. # AbstractAdapter::target is implicitly made to quote paths.
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment