annotate app/models/repository/cvs.rb @ 8:0c83d98252d9 yuya

* Add custom repo prefix and proper auth realm, remove auth cache (seems like an unwise feature), pass DB handle around, various other bits of tidying
author Chris Cannam
date Thu, 12 Aug 2010 15:31:37 +0100
parents 513646585e45
children 0579821a129a
rev   line source
Chris@0 1 # redMine - project management software
Chris@0 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
Chris@0 3 #
Chris@0 4 # This program is free software; you can redistribute it and/or
Chris@0 5 # modify it under the terms of the GNU General Public License
Chris@0 6 # as published by the Free Software Foundation; either version 2
Chris@0 7 # of the License, or (at your option) any later version.
Chris@0 8 #
Chris@0 9 # This program is distributed in the hope that it will be useful,
Chris@0 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 12 # GNU General Public License for more details.
Chris@0 13 #
Chris@0 14 # You should have received a copy of the GNU General Public License
Chris@0 15 # along with this program; if not, write to the Free Software
Chris@0 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@0 17
Chris@0 18 require 'redmine/scm/adapters/cvs_adapter'
Chris@0 19 require 'digest/sha1'
Chris@0 20
Chris@0 21 class Repository::Cvs < Repository
Chris@0 22 validates_presence_of :url, :root_url
Chris@0 23
Chris@0 24 def scm_adapter
Chris@0 25 Redmine::Scm::Adapters::CvsAdapter
Chris@0 26 end
Chris@0 27
Chris@0 28 def self.scm_name
Chris@0 29 'CVS'
Chris@0 30 end
Chris@0 31
Chris@0 32 def entry(path=nil, identifier=nil)
Chris@0 33 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
Chris@0 34 scm.entry(path, rev.nil? ? nil : rev.committed_on)
Chris@0 35 end
Chris@0 36
Chris@0 37 def entries(path=nil, identifier=nil)
Chris@0 38 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
Chris@0 39 entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
Chris@0 40 if entries
Chris@0 41 entries.each() do |entry|
Chris@0 42 unless entry.lastrev.nil? || entry.lastrev.identifier
Chris@0 43 change=changes.find_by_revision_and_path( entry.lastrev.revision, scm.with_leading_slash(entry.path) )
Chris@0 44 if change
Chris@0 45 entry.lastrev.identifier=change.changeset.revision
Chris@0 46 entry.lastrev.author=change.changeset.committer
Chris@0 47 entry.lastrev.revision=change.revision
Chris@0 48 entry.lastrev.branch=change.branch
Chris@0 49 end
Chris@0 50 end
Chris@0 51 end
Chris@0 52 end
Chris@0 53 entries
Chris@0 54 end
Chris@0 55
Chris@0 56 def cat(path, identifier=nil)
Chris@0 57 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
Chris@0 58 scm.cat(path, rev.nil? ? nil : rev.committed_on)
Chris@0 59 end
Chris@0 60
Chris@0 61 def diff(path, rev, rev_to)
Chris@0 62 #convert rev to revision. CVS can't handle changesets here
Chris@0 63 diff=[]
Chris@0 64 changeset_from=changesets.find_by_revision(rev)
Chris@0 65 if rev_to.to_i > 0
Chris@0 66 changeset_to=changesets.find_by_revision(rev_to)
Chris@0 67 end
Chris@0 68 changeset_from.changes.each() do |change_from|
Chris@0 69
Chris@0 70 revision_from=nil
Chris@0 71 revision_to=nil
Chris@0 72
Chris@0 73 revision_from=change_from.revision if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
Chris@0 74
Chris@0 75 if revision_from
Chris@0 76 if changeset_to
Chris@0 77 changeset_to.changes.each() do |change_to|
Chris@0 78 revision_to=change_to.revision if change_to.path==change_from.path
Chris@0 79 end
Chris@0 80 end
Chris@0 81 unless revision_to
Chris@0 82 revision_to=scm.get_previous_revision(revision_from)
Chris@0 83 end
Chris@0 84 file_diff = scm.diff(change_from.path, revision_from, revision_to)
Chris@0 85 diff = diff + file_diff unless file_diff.nil?
Chris@0 86 end
Chris@0 87 end
Chris@0 88 return diff
Chris@0 89 end
Chris@0 90
Chris@0 91 def fetch_changesets
Chris@0 92 # some nifty bits to introduce a commit-id with cvs
Chris@0 93 # natively cvs doesn't provide any kind of changesets, there is only a revision per file.
Chris@0 94 # we now take a guess using the author, the commitlog and the commit-date.
Chris@0 95
Chris@0 96 # last one is the next step to take. the commit-date is not equal for all
Chris@0 97 # commits in one changeset. cvs update the commit-date when the *,v file was touched. so
Chris@0 98 # we use a small delta here, to merge all changes belonging to _one_ changeset
Chris@0 99 time_delta=10.seconds
Chris@0 100
Chris@0 101 fetch_since = latest_changeset ? latest_changeset.committed_on : nil
Chris@0 102 transaction do
Chris@0 103 tmp_rev_num = 1
Chris@0 104 scm.revisions('', fetch_since, nil, :with_paths => true) do |revision|
Chris@0 105 # only add the change to the database, if it doen't exists. the cvs log
Chris@0 106 # is not exclusive at all.
Chris@0 107 unless changes.find_by_path_and_revision(scm.with_leading_slash(revision.paths[0][:path]), revision.paths[0][:revision])
Chris@0 108 revision
Chris@0 109 cs = changesets.find(:first, :conditions=>{
Chris@0 110 :committed_on=>revision.time-time_delta..revision.time+time_delta,
Chris@0 111 :committer=>revision.author,
Chris@0 112 :comments=>Changeset.normalize_comments(revision.message)
Chris@0 113 })
Chris@0 114
Chris@0 115 # create a new changeset....
Chris@0 116 unless cs
Chris@0 117 # we use a temporaray revision number here (just for inserting)
Chris@0 118 # later on, we calculate a continous positive number
Chris@0 119 latest = changesets.find(:first, :order => 'id DESC')
Chris@0 120 cs = Changeset.create(:repository => self,
Chris@0 121 :revision => "_#{tmp_rev_num}",
Chris@0 122 :committer => revision.author,
Chris@0 123 :committed_on => revision.time,
Chris@0 124 :comments => revision.message)
Chris@0 125 tmp_rev_num += 1
Chris@0 126 end
Chris@0 127
Chris@0 128 #convert CVS-File-States to internal Action-abbrevations
Chris@0 129 #default action is (M)odified
Chris@0 130 action="M"
Chris@0 131 if revision.paths[0][:action]=="Exp" && revision.paths[0][:revision]=="1.1"
Chris@0 132 action="A" #add-action always at first revision (= 1.1)
Chris@0 133 elsif revision.paths[0][:action]=="dead"
Chris@0 134 action="D" #dead-state is similar to Delete
Chris@0 135 end
Chris@0 136
Chris@0 137 Change.create(:changeset => cs,
Chris@0 138 :action => action,
Chris@0 139 :path => scm.with_leading_slash(revision.paths[0][:path]),
Chris@0 140 :revision => revision.paths[0][:revision],
Chris@0 141 :branch => revision.paths[0][:branch]
Chris@0 142 )
Chris@0 143 end
Chris@0 144 end
Chris@0 145
Chris@0 146 # Renumber new changesets in chronological order
Chris@0 147 changesets.find(:all, :order => 'committed_on ASC, id ASC', :conditions => "revision LIKE '_%'").each do |changeset|
Chris@0 148 changeset.update_attribute :revision, next_revision_number
Chris@0 149 end
Chris@0 150 end # transaction
Chris@0 151 end
Chris@0 152
Chris@0 153 private
Chris@0 154
Chris@0 155 # Returns the next revision number to assign to a CVS changeset
Chris@0 156 def next_revision_number
Chris@0 157 # Need to retrieve existing revision numbers to sort them as integers
Chris@0 158 @current_revision_number ||= (connection.select_values("SELECT revision FROM #{Changeset.table_name} WHERE repository_id = #{id} AND revision NOT LIKE '_%'").collect(&:to_i).max || 0)
Chris@0 159 @current_revision_number += 1
Chris@0 160 end
Chris@0 161 end