diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index ad19014..216fb26 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -72,9 +72,12 @@ class RepositoriesController < ApplicationController def show @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty? - @entries = @repository.entries(@path, @rev) + json_lookup = request.xhr? && 'all' == params[:details] + @entries = @repository.entries(@path, @rev, json_lookup ? false : true) @changeset = @repository.find_changeset_by_name(@rev) - if request.xhr? + if json_lookup + @entries ? render(:partial => 'dir_list_json') : render(:nothing => true) + elsif request.xhr? @entries ? render(:partial => 'dir_list_content') : render(:nothing => true) else (show_error_not_found; return) unless @entries diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index a3268df..ce7d963 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -111,6 +111,24 @@ module RepositoriesHelper output << '' output end + + def render_content_json(entries) + data = {} + entries.each do |entry| + next if !entry.lastrev + changeset = @project.repository.find_changeset_by_name(entry.lastrev.identifier) if entry.lastrev.identifier + + info = {} + info["revision"] = link_to_revision(changeset, @project) if changeset + info["age"] = distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev.time + info["author"] = changeset.nil? ? h(replace_invalid_utf8(entry.lastrev.author.to_s.split('<').first)) : h(changeset.author) + info["comments"] =truncate(Changeset.to_utf8(changeset.comments, changeset.repository.repo_log_encoding), :length => 50) unless changeset.nil? + + hash = Digest::MD5.hexdigest(entry.path) + data[hash] = info + end + data.to_json + end def to_utf8_for_repositories(str) return str if str.nil? diff --git a/app/models/repository.rb b/app/models/repository.rb index eaf0cdb..194b717 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -76,11 +76,11 @@ class Repository < ActiveRecord::Base end def entry(path=nil, identifier=nil) - scm.entry(path, identifier) + scm.entry(path, identifier, true) end - def entries(path=nil, identifier=nil) - scm.entries(path, identifier) + def entries(path=nil, identifier=nil, skip_rev_lookup=false) + scm.entries(path, identifier, skip_rev_lookup) end def branches diff --git a/app/views/repositories/_dir_list_content.rhtml b/app/views/repositories/_dir_list_content.rhtml index 5207e3f..1d46cba 100644 --- a/app/views/repositories/_dir_list_content.rhtml +++ b/app/views/repositories/_dir_list_content.rhtml @@ -1,3 +1,4 @@ +<% extern_load = false %> <% @entries.each do |entry| %> <% tr_id = Digest::MD5.hexdigest(entry.path) depth = params[:depth].to_i %> @@ -18,10 +19,27 @@ :class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(ent_name)}")%> <%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %> +<% if entry.lastrev.nil? %> +<% if !extern_load %> + +<% javascript_tag :defer => "defer" do -%> +<%= remote_function :url => {:action => 'show', :id => @project, :path => to_path_param(@path), :rev => @rev, :details => 'all'}, + :method => :get, :complete => "scmRevisionsLoaded(request.responseText)" %> +<% end -%> + +<% extern_load = true %> +<% else %> + +<% end %> + + + +<% else %> <% changeset = @project.repository.find_changeset_by_name(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> <%= link_to_revision(changeset, @project) if changeset %> <%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %> <%= changeset.nil? ? h(replace_invalid_utf8(entry.lastrev.author.to_s.split('<').first)) : h(changeset.author) if entry.lastrev %> <%=h truncate(Changeset.to_utf8(changeset.comments, changeset.repository.repo_log_encoding), :length => 50) unless changeset.nil? %> +<% end %> <% end %> diff --git a/lib/redmine/scm/adapters/abstract_adapter.rb b/lib/redmine/scm/adapters/abstract_adapter.rb index 5192618..0d8994e 100644 --- a/lib/redmine/scm/adapters/abstract_adapter.rb +++ b/lib/redmine/scm/adapters/abstract_adapter.rb @@ -94,7 +94,7 @@ module Redmine # Returns the entry identified by path and revision identifier # or nil if entry doesn't exist in the repository - def entry(path=nil, identifier=nil) + def entry(path=nil, identifier=nil, skip_rev_lookup=false) parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?} search_path = parts[0..-2].join('/') search_name = parts[-1] @@ -103,14 +103,14 @@ module Redmine Entry.new(:path => '', :kind => 'dir') else # Search for the entry in the parent directory - es = entries(search_path, identifier) + es = entries(search_path, identifier, skip_rev_lookup) es ? es.detect {|e| e.name == search_name} : nil end end # Returns an Entries collection # or nil if the given path doesn't exist in the repository - def entries(path=nil, identifier=nil) + def entries(path=nil, identifier=nil, skip_rev_lookup=false) return nil end diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb index 798a556..8ae1851 100644 --- a/lib/redmine/scm/adapters/git_adapter.rb +++ b/lib/redmine/scm/adapters/git_adapter.rb @@ -102,7 +102,7 @@ module Redmine bras.include?('master') ? 'master' : bras.first end - def entries(path=nil, identifier=nil) + def entries(path=nil, identifier=nil, skip_rev_lookup=false) path ||= '' p = scm_iconv(@path_encoding, 'UTF-8', path) entries = Entries.new @@ -127,7 +127,7 @@ module Redmine :path => full_p, :kind => (type == "tree") ? 'dir' : 'file', :size => (type == "tree") ? nil : size, - :lastrev => @flag_report_last_commit ? lastrev(full_path, identifier) : Revision.new + :lastrev => @flag_report_last_commit ? lastrev(full_path, identifier, skip_rev_lookup) : Revision.new }) unless entries.detect{|entry| entry.name == name} end end @@ -137,8 +137,13 @@ module Redmine nil end - def lastrev(path, rev) + def lastrev(path, rev, skip_rev_lookup) return nil if path.nil? + cached_data = Rails.cache.read("repository_#{rev}_#{path}") + if skip_rev_lookup || cached_data + return Revision.new(cached_data) if cached_data + return nil + end cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1| cmd_args << rev if rev cmd_args << "--" << path unless path.empty? @@ -149,14 +154,16 @@ module Redmine author = lines[1].match('Author:\s+(.*)$')[1] time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1]) - Revision.new({ + data = { :identifier => id, :scmid => id, :author => author, :time => time, :message => nil, :paths => nil - }) + } + Rails.cache.write("repository_#{rev}_#{path}", data) + Revision.new(data) rescue NoMethodError => e logger.error("The revision '#{path}' has a wrong format") return nil diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 11940f3..d06d900 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -234,6 +234,17 @@ function scmEntryLoaded(id) { Element.removeClassName(id, 'loading'); } +function scmRevisionsLoaded(jsondata) { + var data = JSON.parse( jsondata ) + for( var file in data ) { + var el = document.getElementById(file) + el.getElementsByClassName("revision")[0].innerHTML = data[file]["revision"] + el.getElementsByClassName("age")[0].innerHTML = data[file]["age"] + el.getElementsByClassName("author")[0].innerHTML = data[file]["author"] + el.getElementsByClassName("comments")[0].innerHTML = data[file]["comments"] + } +} + function randomKey(size) { var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); var key = '';