Mercurial > hg > soundsoftware-site
comparison app/models/repository/mercurial.rb @ 511:107d36338b70 live
Merge from branch "cannam"
author | Chris Cannam |
---|---|
date | Thu, 14 Jul 2011 10:43:07 +0100 |
parents | 851510f1b535 |
children | 5e80956cc792 |
comparison
equal
deleted
inserted
replaced
451:a9f6345cb43d | 511:107d36338b70 |
---|---|
1 # redMine - project management software | 1 # Redmine - project management software |
2 # Copyright (C) 2006-2007 Jean-Philippe Lang | 2 # Copyright (C) 2006-2011 Jean-Philippe Lang |
3 # | 3 # |
4 # This program is free software; you can redistribute it and/or | 4 # This program is free software; you can redistribute it and/or |
5 # modify it under the terms of the GNU General Public License | 5 # modify it under the terms of the GNU General Public License |
6 # as published by the Free Software Foundation; either version 2 | 6 # as published by the Free Software Foundation; either version 2 |
7 # of the License, or (at your option) any later version. | 7 # of the License, or (at your option) any later version. |
8 # | 8 # |
9 # This program is distributed in the hope that it will be useful, | 9 # This program is distributed in the hope that it will be useful, |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 # GNU General Public License for more details. | 12 # GNU General Public License for more details. |
13 # | 13 # |
14 # You should have received a copy of the GNU General Public License | 14 # You should have received a copy of the GNU General Public License |
15 # along with this program; if not, write to the Free Software | 15 # along with this program; if not, write to the Free Software |
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 |
18 require 'redmine/scm/adapters/mercurial_adapter' | 18 require 'redmine/scm/adapters/mercurial_adapter' |
19 | 19 |
20 class Repository::Mercurial < Repository | 20 class Repository::Mercurial < Repository |
21 # sort changesets by revision number | |
22 has_many :changesets, :order => "#{Changeset.table_name}.id DESC", :foreign_key => 'repository_id' | |
23 | |
21 attr_protected :root_url | 24 attr_protected :root_url |
22 # validates_presence_of :url | 25 # validates_presence_of :url |
23 | 26 |
24 FETCH_AT_ONCE = 100 # number of changesets to fetch at once | 27 FETCH_AT_ONCE = 100 # number of changesets to fetch at once |
25 | 28 |
26 def scm_adapter | 29 def self.human_attribute_name(attribute_key_name) |
30 attr_name = attribute_key_name | |
31 if attr_name == "url" | |
32 attr_name = "path_to_repository" | |
33 end | |
34 super(attr_name) | |
35 end | |
36 | |
37 def self.scm_adapter_class | |
27 Redmine::Scm::Adapters::MercurialAdapter | 38 Redmine::Scm::Adapters::MercurialAdapter |
28 end | 39 end |
29 | 40 |
30 def self.scm_name | 41 def self.scm_name |
31 'Mercurial' | 42 'Mercurial' |
32 end | 43 end |
33 | 44 |
34 def entries(path=nil, identifier=nil) | 45 def supports_directory_revisions? |
35 scm.entries(path, identifier) | 46 true |
36 end | 47 end |
37 | 48 |
38 def branches | 49 def repo_log_encoding |
39 bras = scm.branches | 50 'UTF-8' |
40 bras.sort unless bras == %w|default| | |
41 end | 51 end |
42 | 52 |
43 # Returns the latest changesets for +path+ | 53 # Returns the readable identifier for the given mercurial changeset |
54 def self.format_changeset_identifier(changeset) | |
55 "#{changeset.revision}:#{changeset.scmid}" | |
56 end | |
57 | |
58 # Returns the identifier for the given Mercurial changeset | |
59 def self.changeset_identifier(changeset) | |
60 changeset.scmid | |
61 end | |
62 | |
63 def diff_format_revisions(cs, cs_to, sep=':') | |
64 super(cs, cs_to, ' ') | |
65 end | |
66 | |
67 # Finds and returns a revision with a number or the beginning of a hash | |
68 def find_changeset_by_name(name) | |
69 return nil if name.nil? || name.empty? | |
70 if /[^\d]/ =~ name or name.to_s.size > 8 | |
71 e = changesets.find(:first, :conditions => ['scmid = ?', name.to_s]) | |
72 else | |
73 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s]) | |
74 end | |
75 return e if e | |
76 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"]) # last ditch | |
77 end | |
78 | |
79 # Returns the latest changesets for +path+; sorted by revision number | |
80 # | |
81 # Because :order => 'id DESC' is defined at 'has_many', | |
82 # there is no need to set 'order'. | |
83 # But, MySQL test fails. | |
84 # Sqlite3 and PostgreSQL pass. | |
85 # Is this MySQL bug? | |
44 def latest_changesets(path, rev, limit=10) | 86 def latest_changesets(path, rev, limit=10) |
45 changesets.find(:all, :include => :user, | 87 changesets.find(:all, :include => :user, |
46 :conditions => latest_changesets_cond(path, rev, limit), | 88 :conditions => latest_changesets_cond(path, rev, limit), |
47 :limit => limit) | 89 :limit => limit, :order => "#{Changeset.table_name}.id DESC") |
48 end | 90 end |
49 | 91 |
50 def latest_changesets_cond(path, rev, limit) | 92 def latest_changesets_cond(path, rev, limit) |
51 cond, args = [], [] | 93 cond, args = [], [] |
52 | |
53 if scm.branchmap.member? rev | 94 if scm.branchmap.member? rev |
54 # dirty hack to filter by branch. branch name should be in database. | 95 # Mercurial named branch is *stable* in each revision. |
96 # So, named branch can be stored in database. | |
97 # Mercurial provides *bookmark* which is equivalent with git branch. | |
98 # But, bookmark is not implemented. | |
55 cond << "#{Changeset.table_name}.scmid IN (?)" | 99 cond << "#{Changeset.table_name}.scmid IN (?)" |
56 args << scm.nodes_in_branch(rev, path, rev, 0, :limit => limit) | 100 # Revisions in root directory and sub directory are not equal. |
101 # So, in order to get correct limit, we need to get all revisions. | |
102 # But, it is very heavy. | |
103 # Mercurial does not treat direcotry. | |
104 # So, "hg log DIR" is very heavy. | |
105 branch_limit = path.blank? ? limit : ( limit * 5 ) | |
106 args << scm.nodes_in_branch(rev, :limit => branch_limit) | |
57 elsif last = rev ? find_changeset_by_name(scm.tagmap[rev] || rev) : nil | 107 elsif last = rev ? find_changeset_by_name(scm.tagmap[rev] || rev) : nil |
58 cond << "#{Changeset.table_name}.id <= ?" | 108 cond << "#{Changeset.table_name}.id <= ?" |
59 args << last.id | 109 args << last.id |
60 end | 110 end |
61 | 111 |
62 unless path.blank? | 112 unless path.blank? |
63 # TODO: there must be a better way to build sub-query | |
64 cond << "EXISTS (SELECT * FROM #{Change.table_name} | 113 cond << "EXISTS (SELECT * FROM #{Change.table_name} |
65 WHERE #{Change.table_name}.changeset_id = #{Changeset.table_name}.id | 114 WHERE #{Change.table_name}.changeset_id = #{Changeset.table_name}.id |
66 AND (#{Change.table_name}.path = ? OR #{Change.table_name}.path LIKE ?))" | 115 AND (#{Change.table_name}.path = ? |
67 args << path.with_leading_slash << "#{path.with_leading_slash}/%" | 116 OR #{Change.table_name}.path LIKE ? ESCAPE ?))" |
117 args << path.with_leading_slash | |
118 args << "#{path.with_leading_slash.gsub(/[%_\\]/) { |s| "\\#{s}" }}/%" << '\\' | |
68 end | 119 end |
69 | 120 |
70 [cond.join(' AND '), *args] unless cond.empty? | 121 [cond.join(' AND '), *args] unless cond.empty? |
71 end | 122 end |
72 private :latest_changesets_cond | 123 private :latest_changesets_cond |
73 | 124 |
74 def fetch_changesets | 125 def fetch_changesets |
126 return if scm.info.nil? | |
75 scm_rev = scm.info.lastrev.revision.to_i | 127 scm_rev = scm.info.lastrev.revision.to_i |
76 db_rev = latest_changeset ? latest_changeset.revision.to_i : -1 | 128 db_rev = latest_changeset ? latest_changeset.revision.to_i : -1 |
77 return unless db_rev < scm_rev # already up-to-date | 129 return unless db_rev < scm_rev # already up-to-date |
78 | 130 |
79 logger.debug "Fetching changesets for repository #{url}" if logger | 131 logger.debug "Fetching changesets for repository #{url}" if logger |