annotate app/models/repository/git.rb @ 1477:f2ad2199b49a bibplugin_integration

Close obsolete branch bibplugin_integration
author Chris Cannam
date Fri, 30 Nov 2012 14:41:31 +0000
parents 5e80956cc792
children bb32da3bea34
rev   line source
Chris@441 1 # Redmine - project management software
Chris@441 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
Chris@0 3 # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com
Chris@441 4 #
Chris@0 5 # This program is free software; you can redistribute it and/or
Chris@0 6 # modify it under the terms of the GNU General Public License
Chris@0 7 # as published by the Free Software Foundation; either version 2
Chris@0 8 # of the License, or (at your option) any later version.
Chris@441 9 #
Chris@0 10 # This program is distributed in the hope that it will be useful,
Chris@0 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 13 # GNU General Public License for more details.
Chris@441 14 #
Chris@0 15 # You should have received a copy of the GNU General Public License
Chris@0 16 # along with this program; if not, write to the Free Software
Chris@0 17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@0 18
Chris@0 19 require 'redmine/scm/adapters/git_adapter'
Chris@0 20
Chris@0 21 class Repository::Git < Repository
Chris@0 22 attr_protected :root_url
Chris@0 23 validates_presence_of :url
Chris@0 24
Chris@245 25 def self.human_attribute_name(attribute_key_name)
Chris@441 26 attr_name = attribute_key_name
Chris@441 27 if attr_name == "url"
Chris@441 28 attr_name = "path_to_repository"
Chris@441 29 end
Chris@441 30 super(attr_name)
Chris@245 31 end
Chris@245 32
Chris@245 33 def self.scm_adapter_class
Chris@0 34 Redmine::Scm::Adapters::GitAdapter
Chris@0 35 end
Chris@245 36
Chris@0 37 def self.scm_name
Chris@0 38 'Git'
Chris@0 39 end
Chris@0 40
Chris@441 41 def report_last_commit
Chris@441 42 extra_report_last_commit
Chris@441 43 end
Chris@441 44
Chris@441 45 def extra_report_last_commit
Chris@441 46 return false if extra_info.nil?
Chris@441 47 v = extra_info["extra_report_last_commit"]
Chris@441 48 return false if v.nil?
Chris@441 49 v.to_s != '0'
Chris@441 50 end
Chris@441 51
Chris@441 52 def supports_directory_revisions?
Chris@441 53 true
Chris@441 54 end
Chris@441 55
Chris@909 56 def supports_revision_graph?
Chris@909 57 true
Chris@909 58 end
Chris@909 59
Chris@245 60 def repo_log_encoding
Chris@245 61 'UTF-8'
Chris@245 62 end
Chris@245 63
Chris@117 64 # Returns the identifier for the given git changeset
Chris@117 65 def self.changeset_identifier(changeset)
Chris@117 66 changeset.scmid
Chris@117 67 end
Chris@117 68
Chris@117 69 # Returns the readable identifier for the given git changeset
Chris@117 70 def self.format_changeset_identifier(changeset)
Chris@117 71 changeset.revision[0, 8]
Chris@117 72 end
Chris@117 73
Chris@0 74 def branches
Chris@0 75 scm.branches
Chris@0 76 end
Chris@0 77
Chris@0 78 def tags
Chris@0 79 scm.tags
Chris@0 80 end
Chris@0 81
Chris@507 82 def default_branch
Chris@507 83 scm.default_branch
Chris@909 84 rescue Exception => e
Chris@909 85 logger.error "git: error during get default branch: #{e.message}"
Chris@909 86 nil
Chris@507 87 end
Chris@507 88
Chris@245 89 def find_changeset_by_name(name)
Chris@245 90 return nil if name.nil? || name.empty?
Chris@245 91 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
Chris@245 92 return e if e
Chris@245 93 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
Chris@245 94 end
Chris@245 95
Chris@441 96 def entries(path=nil, identifier=nil)
Chris@441 97 scm.entries(path,
Chris@441 98 identifier,
Chris@441 99 options = {:report_last_commit => extra_report_last_commit})
Chris@441 100 end
Chris@441 101
Chris@909 102 # With SCMs that have a sequential commit numbering,
Chris@909 103 # such as Subversion and Mercurial,
Chris@909 104 # Redmine is able to be clever and only fetch changesets
Chris@909 105 # going forward from the most recent one it knows about.
Chris@909 106 #
Chris@909 107 # However, Git does not have a sequential commit numbering.
Chris@909 108 #
Chris@909 109 # In order to fetch only new adding revisions,
Chris@909 110 # Redmine needs to parse revisions per branch.
Chris@909 111 # Branch "last_scmid" is for this requirement.
Chris@909 112 #
Chris@441 113 # In Git and Mercurial, revisions are not in date order.
Chris@441 114 # Redmine Mercurial fixed issues.
Chris@441 115 # * Redmine Takes Too Long On Large Mercurial Repository
Chris@441 116 # http://www.redmine.org/issues/3449
Chris@441 117 # * Sorting for changesets might go wrong on Mercurial repos
Chris@441 118 # http://www.redmine.org/issues/3567
Chris@441 119 #
Chris@441 120 # Database revision column is text, so Redmine can not sort by revision.
Chris@441 121 # Mercurial has revision number, and revision number guarantees revision order.
Chris@441 122 # Redmine Mercurial model stored revisions ordered by database id to database.
Chris@441 123 # So, Redmine Mercurial model can use correct ordering revisions.
Chris@441 124 #
Chris@441 125 # Redmine Mercurial adapter uses "hg log -r 0:tip --limit 10"
Chris@441 126 # to get limited revisions from old to new.
Chris@441 127 # But, Git 1.7.3.4 does not support --reverse with -n or --skip.
Chris@441 128 #
Chris@0 129 # The repository can still be fully reloaded by calling #clear_changesets
Chris@0 130 # before fetching changesets (eg. for offline resync)
Chris@0 131 def fetch_changesets
Chris@441 132 scm_brs = branches
Chris@441 133 return if scm_brs.nil? || scm_brs.empty?
Chris@441 134 h1 = extra_info || {}
Chris@441 135 h = h1.dup
Chris@441 136 h["branches"] ||= {}
Chris@441 137 h["db_consistent"] ||= {}
Chris@441 138 if changesets.count == 0
Chris@441 139 h["db_consistent"]["ordering"] = 1
Chris@441 140 merge_extra_info(h)
Chris@441 141 self.save
Chris@441 142 elsif ! h["db_consistent"].has_key?("ordering")
Chris@441 143 h["db_consistent"]["ordering"] = 0
Chris@441 144 merge_extra_info(h)
Chris@441 145 self.save
Chris@441 146 end
Chris@909 147 scm_brs.each do |br1|
Chris@909 148 br = br1.to_s
Chris@441 149 from_scmid = nil
Chris@441 150 from_scmid = h["branches"][br]["last_scmid"] if h["branches"][br]
Chris@441 151 h["branches"][br] ||= {}
Chris@441 152 scm.revisions('', from_scmid, br, {:reverse => true}) do |rev|
Chris@441 153 db_rev = find_changeset_by_name(rev.revision)
Chris@245 154 transaction do
Chris@441 155 if db_rev.nil?
Chris@909 156 db_saved_rev = save_revision(rev)
Chris@909 157 parents = {}
Chris@909 158 parents[db_saved_rev] = rev.parents unless rev.parents.nil?
Chris@909 159 parents.each do |ch, chparents|
Chris@909 160 ch.parents = chparents.collect{|rp| find_changeset_by_name(rp)}.compact
Chris@909 161 end
Chris@245 162 end
Chris@441 163 h["branches"][br]["last_scmid"] = rev.scmid
Chris@441 164 merge_extra_info(h)
Chris@441 165 self.save
Chris@245 166 end
Chris@245 167 end
Chris@245 168 end
Chris@0 169 end
Chris@0 170
Chris@441 171 def save_revision(rev)
Chris@441 172 changeset = Changeset.new(
Chris@441 173 :repository => self,
Chris@441 174 :revision => rev.identifier,
Chris@441 175 :scmid => rev.scmid,
Chris@441 176 :committer => rev.author,
Chris@441 177 :committed_on => rev.time,
Chris@441 178 :comments => rev.message
Chris@441 179 )
Chris@441 180 if changeset.save
Chris@441 181 rev.paths.each do |file|
Chris@441 182 Change.create(
Chris@441 183 :changeset => changeset,
Chris@441 184 :action => file[:action],
Chris@441 185 :path => file[:path])
Chris@441 186 end
Chris@441 187 end
Chris@909 188 changeset
Chris@441 189 end
Chris@441 190 private :save_revision
Chris@441 191
Chris@0 192 def latest_changesets(path,rev,limit=10)
Chris@0 193 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
Chris@0 194 return [] if revisions.nil? || revisions.empty?
Chris@0 195
Chris@0 196 changesets.find(
Chris@441 197 :all,
Chris@0 198 :conditions => [
Chris@441 199 "scmid IN (?)",
Chris@0 200 revisions.map!{|c| c.scmid}
Chris@0 201 ],
Chris@0 202 :order => 'committed_on DESC'
Chris@0 203 )
Chris@0 204 end
Chris@0 205 end