summaryrefslogtreecommitdiffstats
path: root/app/models/repository/mercurial.rb
blob: 557b9a4dc8ec07b8ba4d45ec25f8250655ac6c2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# redMine - project management software
# Copyright (C) 2006-2007  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 'redmine/scm/adapters/mercurial_adapter'

class Repository::Mercurial < Repository
  # sort changesets by revision number
  has_many :changesets, :order => "#{Changeset.table_name}.id DESC", :foreign_key => 'repository_id'

  attr_protected :root_url
  validates_presence_of :url

  def self.scm_adapter_class
    Redmine::Scm::Adapters::MercurialAdapter
  end

  def self.scm_name
    'Mercurial'
  end

  # Returns the readable identifier for the given mercurial changeset
  def self.format_changeset_identifier(changeset)
    "#{changeset.revision}:#{changeset.scmid}"
  end

  # Returns the identifier for the given Mercurial changeset
  def self.changeset_identifier(changeset)
    changeset.scmid
  end

  def diff_format_revisions(cs, cs_to, sep=':')
    super(cs, cs_to, ' ')
  end

  def entries(path=nil, identifier=nil)
    entries=scm.entries(path, identifier)
    if entries
      entries.each do |entry|
        next unless entry.is_file?
        # Set the filesize unless browsing a specific revision
        if identifier.nil?
          full_path = File.join(root_url, entry.path)
          entry.size = File.stat(full_path).size if File.file?(full_path)
        end
        # Search the DB for the entry's last change
        change = changes.find(:first, :conditions => ["path = ?", scm.with_leading_slash(entry.path)], :order => "#{Changeset.table_name}.committed_on DESC")
        if change
          entry.lastrev.identifier = change.changeset.revision
          entry.lastrev.name = change.changeset.revision
          entry.lastrev.author = change.changeset.committer
          entry.lastrev.revision = change.revision
        end
      end
    end
    entries
  end

  # Finds and returns a revision with a number or the beginning of a hash
  def find_changeset_by_name(name)
    return nil if name.nil? || name.empty?
    if /[^\d]/ =~ name or name.to_s.size > 8
      e = changesets.find(:first, :conditions => ['scmid = ?', name.to_s])
    else
      e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
    end
    return e if e
    changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])  # last ditch
  end

  # Returns the latest changesets for +path+; sorted by revision number
  def latest_changesets(path, rev, limit=10)
    if path.blank?
      changesets.find(:all, :include => :user, :limit => limit)
    else
      changes.find(:all, :include => {:changeset => :user},
                         :conditions => ["path = ?", path.with_leading_slash],
                         :order => "#{Changeset.table_name}.id DESC",
                         :limit => limit).collect(&:changeset)
    end
  end

  def fetch_changesets
    scm_info = scm.info
    if scm_info
      # latest revision found in database
      db_revision = latest_changeset ? latest_changeset.revision.to_i : -1
      # latest revision in the repository
      latest_revision = scm_info.lastrev
      return if latest_revision.nil?
      scm_revision = latest_revision.identifier.to_i
      if db_revision < scm_revision
        logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug?
        identifier_from = db_revision + 1
        while (identifier_from <= scm_revision)
          # loads changesets by batches of 100
          identifier_to = [identifier_from + 99, scm_revision].min
          revisions = scm.revisions('', identifier_from, identifier_to, :with_paths => true)
          transaction do
            revisions.each do |revision|
              changeset = Changeset.create(:repository => self,
                                           :revision => revision.identifier,
                                           :scmid => revision.scmid,
                                           :committer => revision.author, 
                                           :committed_on => revision.time,
                                           :comments => revision.message)
              
              revision.paths.each do |change|
                changeset.create_change(change)
              end
            end
          end unless revisions.nil?
          identifier_from = identifier_to + 1
        end
      end
    end
  end
end