/app/controllers/repositories_controller.rb
Ruby | 434 lines | 344 code | 56 blank | 34 comment | 46 complexity | 10db44f1b8a57ed122888c7cac243820 MD5 | raw file
- # Redmine - project management software
- # Copyright (C) 2006-2013 Jean-Philippe Lang
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License
- # as published by the Free Software Foundation; either version 2
- # of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- require 'SVG/Graph/Bar'
- require 'SVG/Graph/BarHorizontal'
- require 'digest/sha1'
- require 'redmine/scm/adapters/abstract_adapter'
- class ChangesetNotFound < Exception; end
- class InvalidRevisionParam < Exception; end
- class RepositoriesController < ApplicationController
- menu_item :repository
- menu_item :settings, :only => [:new, :create, :edit, :update, :destroy, :committers]
- default_search_scope :changesets
- before_filter :find_project_by_project_id, :only => [:new, :create]
- before_filter :find_repository, :only => [:edit, :update, :destroy, :committers]
- before_filter :find_project_repository, :except => [:new, :create, :edit, :update, :destroy, :committers]
- before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue]
- before_filter :authorize
- accept_rss_auth :revisions
- rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
- def new
- scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first
- @repository = Repository.factory(scm)
- @repository.is_default = @project.repository.nil?
- @repository.project = @project
- end
- def create
- attrs = pickup_extra_info
- @repository = Repository.factory(params[:repository_scm])
- @repository.safe_attributes = params[:repository]
- if attrs[:attrs_extra].keys.any?
- @repository.merge_extra_info(attrs[:attrs_extra])
- end
- @repository.project = @project
- if request.post? && @repository.save
- redirect_to settings_project_path(@project, :tab => 'repositories')
- else
- render :action => 'new'
- end
- end
- def edit
- end
- def update
- attrs = pickup_extra_info
- @repository.safe_attributes = attrs[:attrs]
- if attrs[:attrs_extra].keys.any?
- @repository.merge_extra_info(attrs[:attrs_extra])
- end
- @repository.project = @project
- if request.put? && @repository.save
- redirect_to settings_project_path(@project, :tab => 'repositories')
- else
- render :action => 'edit'
- end
- end
- def pickup_extra_info
- p = {}
- p_extra = {}
- params[:repository].each do |k, v|
- if k =~ /^extra_/
- p_extra[k] = v
- else
- p[k] = v
- end
- end
- {:attrs => p, :attrs_extra => p_extra}
- end
- private :pickup_extra_info
- def committers
- @committers = @repository.committers
- @users = @project.users
- additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
- @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
- @users.compact!
- @users.sort!
- if request.post? && params[:committers].is_a?(Hash)
- # Build a hash with repository usernames as keys and corresponding user ids as values
- @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
- flash[:notice] = l(:notice_successful_update)
- redirect_to settings_project_path(@project, :tab => 'repositories')
- end
- end
- def destroy
- @repository.destroy if request.delete?
- redirect_to settings_project_path(@project, :tab => 'repositories')
- end
- def show
- @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
- @entries = @repository.entries(@path, @rev)
- @changeset = @repository.find_changeset_by_name(@rev)
- if request.xhr?
- @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
- else
- (show_error_not_found; return) unless @entries
- @changesets = @repository.latest_changesets(@path, @rev)
- @properties = @repository.properties(@path, @rev)
- @repositories = @project.repositories
- render :action => 'show'
- end
- end
- alias_method :browse, :show
- def changes
- @entry = @repository.entry(@path, @rev)
- (show_error_not_found; return) unless @entry
- @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
- @properties = @repository.properties(@path, @rev)
- @changeset = @repository.find_changeset_by_name(@rev)
- end
- def revisions
- @changeset_count = @repository.changesets.count
- @changeset_pages = Paginator.new @changeset_count,
- per_page_option,
- params['page']
- @changesets = @repository.changesets.
- limit(@changeset_pages.per_page).
- offset(@changeset_pages.offset).
- includes(:user, :repository, :parents).
- all
- respond_to do |format|
- format.html { render :layout => false if request.xhr? }
- format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
- end
- end
- def raw
- entry_and_raw(true)
- end
- def entry
- entry_and_raw(false)
- end
- def entry_and_raw(is_raw)
- @entry = @repository.entry(@path, @rev)
- (show_error_not_found; return) unless @entry
- # If the entry is a dir, show the browser
- (show; return) if @entry.is_dir?
- @content = @repository.cat(@path, @rev)
- (show_error_not_found; return) unless @content
- if is_raw ||
- (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) ||
- ! is_entry_text_data?(@content, @path)
- # Force the download
- send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
- send_type = Redmine::MimeType.of(@path)
- send_opt[:type] = send_type.to_s if send_type
- send_opt[:disposition] = (Redmine::MimeType.is_type?('image', @path) && !is_raw ? 'inline' : 'attachment')
- send_data @content, send_opt
- else
- # Prevent empty lines when displaying a file with Windows style eol
- # TODO: UTF-16
- # Is this needs? AttachmentsController reads file simply.
- @content.gsub!("\r\n", "\n")
- @changeset = @repository.find_changeset_by_name(@rev)
- end
- end
- private :entry_and_raw
- def is_entry_text_data?(ent, path)
- # UTF-16 contains "\x00".
- # It is very strict that file contains less than 30% of ascii symbols
- # in non Western Europe.
- return true if Redmine::MimeType.is_type?('text', path)
- # Ruby 1.8.6 has a bug of integer divisions.
- # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
- return false if ent.is_binary_data?
- true
- end
- private :is_entry_text_data?
- def annotate
- @entry = @repository.entry(@path, @rev)
- (show_error_not_found; return) unless @entry
- @annotate = @repository.scm.annotate(@path, @rev)
- if @annotate.nil? || @annotate.empty?
- (render_error l(:error_scm_annotate); return)
- end
- ann_buf_size = 0
- @annotate.lines.each do |buf|
- ann_buf_size += buf.size
- end
- if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte
- (render_error l(:error_scm_annotate_big_text_file); return)
- end
- @changeset = @repository.find_changeset_by_name(@rev)
- end
- def revision
- respond_to do |format|
- format.html
- format.js {render :layout => false}
- end
- end
- # Adds a related issue to a changeset
- # POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues
- def add_related_issue
- @issue = @changeset.find_referenced_issue_by_id(params[:issue_id])
- if @issue && (!@issue.visible? || @changeset.issues.include?(@issue))
- @issue = nil
- end
- if @issue
- @changeset.issues << @issue
- end
- end
- # Removes a related issue from a changeset
- # DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id
- def remove_related_issue
- @issue = Issue.visible.find_by_id(params[:issue_id])
- if @issue
- @changeset.issues.delete(@issue)
-