content_tag('p', form.password_field(:password, :size => 30, :name => 'ignore',
:value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)),
:onfocus => "this.value=''; this.name='repository[password]';",
- :onchange => "this.name='repository[password]';"))
+ :onchange => "this.name='repository[password]';")) +
+ content_tag('p', form.check_box(:cache))
end
def darcs_field_tags(form, repository)
+
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
belongs_to :project
has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
has_many :changes, :through => :changesets
-
+
# Raw SQL to delete changesets and changes in the database
# has_many :changesets, :dependent => :destroy is too slow for big repositories
before_destroy :clear_changesets
-
+
# Checks if the SCM is enabled when creating a repository
validate_on_create { |r| r.errors.add(:type, :activerecord_error_invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) }
-
+
# Removes leading and trailing whitespace
def url=(arg)
write_attribute(:url, arg ? arg.to_s.strip : nil)
end
def scm
- @scm ||= self.scm_adapter.new url, root_url, login, password
+ init_cache if cache_path.blank? and respond_to?(:init_cache)
+ @scm ||= self.scm_adapter.new(url, root_url, login, password, cache_path)
update_attribute(:root_url, @scm.root_url) if root_url.blank?
@scm
end
rescue
nil
end
-
+
+ def remove_cache
+ scm.remove_cache if cache
+ end
+
+ def create_or_sync_cache
+ begin
+ scm.create_cache
+ rescue => e
+ # clean if problem in creation
+ scm.remove_cache
+ end
+ scm.synchronize
+ end
+
private
-
+
+ def repositories_cache_directory
+ dir = Setting.repositories_cache_directory.gsub(/^([^#{File::SEPARATOR}].*)/, RAILS_ROOT + '/\1')
+ return dir if File.directory?(dir)
+ end
+
def before_save
# Strips url and root_url
url.strip!
attr_protected :root_url
validates_presence_of :url
+ before_destroy :remove_cache
+
+ def init_cache
+ return unless dir = repositories_cache_directory
+ # we need to use a cache only if repository isn't local and dir exists
+ if url[/^(rsync|https?|git|ssh):\/\//]
+ update_attribute(:cache_path, dir + project.identifier)
+ update_attribute(:cache, true)
+ end
+ end
+
def scm_adapter
Redmine::Scm::Adapters::GitAdapter
end
end
def fetch_changesets
+ create_or_sync_cache if cache
+
scm_info = scm.info
if scm_info
# latest revision found in database
validates_presence_of :url
validates_format_of :url, :with => /^(http|https|svn|svn\+ssh|file):\/\/.+/i
+ before_destroy :remove_cache
+
+ def init_cache
+ return unless dir = repositories_cache_directory
+ # we need to use a cache only if repository isn't local and dir exists
+ if cache and url[/^(svn|https?|svn\+ssh):\/\//]
+ update_attribute(:cache_path, dir + project.identifier)
+ end
+ end
+
def scm_adapter
Redmine::Scm::Adapters::SubversionAdapter
end
end
def fetch_changesets
+ create_or_sync_cache if cache
+
scm_info = scm.info
if scm_info
# latest revision found in database
setting = find_by_name(name)
setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name
end
+
+ protected
+
+ def validate
+ if self.name.to_s == "repositories_cache_directory" and not File.directory?(self.value.to_s)
+ logger.error("Le repertoire #{self.value.to_s} n'existe pas")
+ errors.add("Le repertoire #{self.value.to_s} n'existe pas")
+ end
+ end
+
end
<p><label><%= l(:setting_repositories_encodings) %></label>
<%= text_field_tag 'settings[repositories_encodings]', Setting.repositories_encodings, :size => 60 %><br /><em><%= l(:text_comma_separated) %></em></p>
+<p><label><%= l(:setting_repositories_cache_directory) %></label>
+<%= text_field_tag 'settings[repositories_cache_directory]', Setting.repositories_cache_directory, :size => 60 %></p>
+
<p><label><%= l(:setting_commit_logs_encoding) %></label>
<%= select_tag 'settings[commit_logs_encoding]', options_for_select(Setting::ENCODINGS, Setting.commit_logs_encoding) %></p>
</div>
# multiple values accepted, comma separated
repositories_encodings:
default: ''
+repositories_cache_directory:
+ default: 'tmp/scm/'
# encoding used to convert commit logs to UTF-8
commit_logs_encoding:
default: 'UTF-8'
--- /dev/null
+class AddLocalCopy < ActiveRecord::Migration
+ def self.up
+ add_column :repositories, :cache, :boolean
+ add_column :repositories, :cache_path, :string, :limit => 255, :default => ""
+
+ end
+
+ def self.down
+ remove_column :repositories, :cache
+ remove_column :repositories, :cache_path
+ end
+end
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
setting_commit_logs_encoding: Commit messages encoding
label_renamed: renamed\r
label_copied: copied\r
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
enumeration_issue_priorities: Sagsprioriteter
enumeration_doc_categories: Dokumentkategorier
enumeration_activities: Aktiviteter (tidsregistrering)
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
enumeration_issue_priorities: Ticket-Prioritäten
enumeration_doc_categories: Dokumentenkategorien
enumeration_activities: Aktivitäten (Zeiterfassung)
+field_cache: Local cache
+setting_repositories_cache_directory: Cache directory for repositories
field_default_value: Default value
field_comments_sorting: Display comments
field_parent_title: Parent page
+field_cache: Local cache
setting_app_title: Application title
setting_app_subtitle: Application subtitle
setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
setting_sequential_project_identifiers: Generate sequential project identifiers
+setting_repositories_cache_directory: Cache directory for repositories
project_module_issue_tracking: Issue tracking
project_module_time_tracking: Time tracking
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
setting_mail_handler_api_enabled: "Activer le WS pour la réception d'emails"
setting_mail_handler_api_key: Clé de protection de l'API
setting_sequential_project_identifiers: Générer des identifiants de projet séquentiels
+setting_repositories_cache_directory: Répertoire du cache pour les dépôts
project_module_issue_tracking: Suivi des demandes
project_module_time_tracking: Suivi du temps passé
enumeration_doc_categories: Catégories des documents
enumeration_activities: Activités (suivi du temps)
notice_unable_delete_version: Unable to delete version
+field_cache: Cache local
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: A verziót nem lehet törölni
label_renamed: átnevezve
label_copied: lemásolva
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Impossibile cancellare la versione
label_renamed: rinominato
label_copied: copiato
+field_cache: Local cache
+setting_repositories_cache_directory: Cache directory for repositories
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Neimanoma panaikinti versiją
label_renamed: pervardintas
label_copied: nukopijuotas
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Onmogelijk om deze versie te verwijderen.
label_renamed: hernoemt
label_copied: gekopieerd
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed\r
label_copied: copied\r
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Impossível apagar esta versão
label_renamed: renomeado
label_copied: copiado
+field_cache: Local cache
+setting_repositories_cache_directory: Cache directory for repositories
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
text_wiki_destroy_confirmation: Вы уверены, что хотите удалить данную Wiki и все содержимое?
text_workflow_edit: Выберите роль и трекер для редактирования последовательности состояний
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
notice_unable_delete_version: Unable to delete version
label_renamed: renamed
label_copied: copied
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
enumeration_issue_priorities: 項目優先權
enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (時間追蹤)
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
enumeration_issue_priorities: 问题优先级
enumeration_doc_categories: 文档类别
enumeration_activities: 活动(时间跟踪)
+setting_repositories_cache_directory: Cache directory for repositories
+field_cache: Local cache
end
end
- def initialize(url, root_url=nil, login=nil, password=nil)
+ def initialize(url, root_url=nil, login=nil, password=nil, cache_path=nil)
@url = url
@login = login if login && !login.empty?
@password = (password || "") if @login
- @root_url = root_url.blank? ? retrieve_root_url : root_url
+
+ if cache_path.blank?
+ @root_url = root_url.blank? ? retrieve_root_url : root_url
+ else
+ @orig_url = @url
+ @url = @root_url = cache_path
+ end
end
def adapter_name
end
end
+ def remove_cache
+ remove_directory(@root_url) if not @orig_url.blank? and File.directory?(@root_url)
+ end
+
private
+ def remove_directory(path)
+ Dir.entries(path).each do |f|
+ next if %w[. ..].include?(f)
+ name = "#{path}/#{f}"
+ File.directory?(name) ? remove_directory(name) : File.unlink(name)
+ end
+ Dir.rmdir path
+ rescue Errno::ENOENT => e
+ logger.error(e.to_s)
+ end
+
def retrieve_root_url
info = self.info
info ? info.root_url : nil
self.class.strip_credential(cmd)
end
end
-
+
class Entries < Array
def sort_by_name
sort {|x,y|
# Git executable name
GIT_BIN = "git"
+ def initialize(url, root_url=nil, login=nil, password=nil, cache_path=nil)
+ super(url, root_url, login, password, cache_path)
+ @url += "/.git/" unless cache_path.blank?
+ end
+
# Get the revision of a particuliar file
def get_rev (rev,path)
return nil if $? && $?.exitstatus != 0
cat
end
+
+ def create_cache
+ cmd = "#{GIT_BIN} clone #{@orig_url} #{@root_url}"
+ shellout(cmd) { |io| io.read }
+ end
+
+ def synchronize
+ return unless File.directory?(@url)
+ cmd = "#{GIT_BIN} --git-dir #{@url} pull"
+ shellout(cmd)
+ end
+
end
end
end
-
end
\r
# SVN executable name\r
SVN_BIN = "svn"\r
- \r
+\r
class << self\r
def client_version\r
@@client_version ||= (svn_binary_version || [])\r
return nil if $? && $?.exitstatus != 0\r
blame\r
end\r
+\r
+ def create_cache\r
+ return if @orig_url.blank?\r
+ cmd = "#{SVN_BIN} checkout --non-interactive #{@orig_url} #{@root_url}"\r
+ shellout(cmd) { |io| io.read }\r
+ end\r
+\r
+ def synchronize\r
+ return if @orig_url.blank?\r
+ cmd = "#{SVN_BIN} update --non-interactive"\r
+ Dir.chdir(@root_url) { shellout(cmd) { |io| io.read } }\r
+ end\r
\r
private\r
\r
str << " --password #{shell_quote(@password)}" unless @login.blank? || @password.blank?\r
str\r
end\r
+\r
end\r
end\r
end\r
assert_equal ':pserver:login:password@host:/path/to/the/repository', repository.url
assert_equal 'foo', repository.root_url
end
+
+ def test_local_cache
+ dir = Setting.repositories_cache_directory.gsub(/^([^#{File::SEPARATOR}].*)/, RAILS_ROOT + '/\1')
+
+ project = projects(:projects_001)
+
+ repository = Repository::Git.new(:project => Project.find_by_name(project.name), :url => "git://github.com/olabini/paipr.git")
+ repository.scm
+ assert_equal(dir + project.identifier, repository.cache_path)
+
+ repository = Repository::Git.new(:project => Project.find(:first), :url => "/var/cache/git/paipr/.git")
+ repository.init_cache
+ assert repository.cache_path.blank?
+
+ repository = Repository::Subversion.new(:project => Project.find(:first), :url => "svn://github.com/olabini/paipr.git")
+ repository.init_cache
+ assert repository.cache_path.blank?
+
+ repository = Repository::Subversion.new(:project => Project.find_by_name(project.name), :url => "svn://github.com/olabini/paipr.git", :cache => true)
+ repository.init_cache
+ assert_equal(dir + project.identifier, repository.cache_path)
+ end
end