##// END OF EJS Templates
scm: git: code clean up model....
Toshi MARUYAMA -
r5630:cddc5f70a32b
parent child
Show More
@@ -1,169 +1,170
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 # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com
3 # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com
4 #
4 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 # of the License, or (at your option) any later version.
8 #
9 #
9 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 # GNU General Public License for more details.
13 #
14 #
14 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18
18 require 'redmine/scm/adapters/git_adapter'
19 require 'redmine/scm/adapters/git_adapter'
19
20
20 class Repository::Git < Repository
21 class Repository::Git < Repository
21 attr_protected :root_url
22 attr_protected :root_url
22 validates_presence_of :url
23 validates_presence_of :url
23
24
24 def self.human_attribute_name(attribute_key_name)
25 def self.human_attribute_name(attribute_key_name)
25 attr_name = attribute_key_name
26 attr_name = attribute_key_name
26 if attr_name == "url"
27 if attr_name == "url"
27 attr_name = "path_to_repository"
28 attr_name = "path_to_repository"
28 end
29 end
29 super(attr_name)
30 super(attr_name)
30 end
31 end
31
32
32 def self.scm_adapter_class
33 def self.scm_adapter_class
33 Redmine::Scm::Adapters::GitAdapter
34 Redmine::Scm::Adapters::GitAdapter
34 end
35 end
35
36
36 def self.scm_name
37 def self.scm_name
37 'Git'
38 'Git'
38 end
39 end
39
40
40 def extra_report_last_commit
41 def extra_report_last_commit
41 true
42 true
42 end
43 end
43
44
44 def supports_directory_revisions?
45 def supports_directory_revisions?
45 true
46 true
46 end
47 end
47
48
48 def repo_log_encoding
49 def repo_log_encoding
49 'UTF-8'
50 'UTF-8'
50 end
51 end
51
52
52 # Returns the identifier for the given git changeset
53 # Returns the identifier for the given git changeset
53 def self.changeset_identifier(changeset)
54 def self.changeset_identifier(changeset)
54 changeset.scmid
55 changeset.scmid
55 end
56 end
56
57
57 # Returns the readable identifier for the given git changeset
58 # Returns the readable identifier for the given git changeset
58 def self.format_changeset_identifier(changeset)
59 def self.format_changeset_identifier(changeset)
59 changeset.revision[0, 8]
60 changeset.revision[0, 8]
60 end
61 end
61
62
62 def branches
63 def branches
63 scm.branches
64 scm.branches
64 end
65 end
65
66
66 def tags
67 def tags
67 scm.tags
68 scm.tags
68 end
69 end
69
70
70 def find_changeset_by_name(name)
71 def find_changeset_by_name(name)
71 return nil if name.nil? || name.empty?
72 return nil if name.nil? || name.empty?
72 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
73 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
73 return e if e
74 return e if e
74 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
75 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
75 end
76 end
76
77
77 def entries(path=nil, identifier=nil)
78 def entries(path=nil, identifier=nil)
78 scm.entries(path,
79 scm.entries(path,
79 identifier,
80 identifier,
80 options = {:report_last_commit => extra_report_last_commit})
81 options = {:report_last_commit => extra_report_last_commit})
81 end
82 end
82
83
83 # In Git and Mercurial, revisions are not in date order.
84 # In Git and Mercurial, revisions are not in date order.
84 # Mercurial fixed issues.
85 # Mercurial fixed issues.
85 # * Redmine Takes Too Long On Large Mercurial Repository
86 # * Redmine Takes Too Long On Large Mercurial Repository
86 # http://www.redmine.org/issues/3449
87 # http://www.redmine.org/issues/3449
87 # * Sorting for changesets might go wrong on Mercurial repos
88 # * Sorting for changesets might go wrong on Mercurial repos
88 # http://www.redmine.org/issues/3567
89 # http://www.redmine.org/issues/3567
89 # Database revision column is text, so Redmine can not sort by revision.
90 # Database revision column is text, so Redmine can not sort by revision.
90 # Mercurial has revision number, and revision number guarantees revision order.
91 # Mercurial has revision number, and revision number guarantees revision order.
91 # Mercurial adapter uses "hg log -r 0:tip --limit 10"
92 # Mercurial adapter uses "hg log -r 0:tip --limit 10"
92 # to get limited revisions from old to new.
93 # to get limited revisions from old to new.
93 # And Mercurial model stored revisions ordered by database id in database.
94 # And Mercurial model stored revisions ordered by database id in database.
94 # So, Mercurial can use correct order revisions.
95 # So, Mercurial can use correct order revisions.
95 #
96 #
96 # But, Git 1.7.3.4 does not support --reverse with -n or --skip.
97 # But, Git 1.7.3.4 does not support --reverse with -n or --skip.
97 #
98 #
98 # With SCM's that have a sequential commit numbering, redmine is able to be
99 # With SCM's that have a sequential commit numbering, redmine is able to be
99 # clever and only fetch changesets going forward from the most recent one
100 # clever and only fetch changesets going forward from the most recent one
100 # it knows about.
101 # it knows about.
101 # However, with git, you never know if people have merged
102 # However, with git, you never know if people have merged
102 # commits into the middle of the repository history, so we should parse
103 # commits into the middle of the repository history, so we should parse
103 # the entire log.
104 # the entire log.
104 #
105 #
105 # Since it's way too slow for large repositories,
106 # Since it's way too slow for large repositories,
106 # we only parse 1 week before the last known commit.
107 # we only parse 1 week before the last known commit.
107 #
108 #
108 # The repository can still be fully reloaded by calling #clear_changesets
109 # The repository can still be fully reloaded by calling #clear_changesets
109 # before fetching changesets (eg. for offline resync)
110 # before fetching changesets (eg. for offline resync)
110 def fetch_changesets
111 def fetch_changesets
111 c = changesets.find(:first, :order => 'committed_on DESC')
112 c = changesets.find(:first, :order => 'committed_on DESC')
112 since = (c ? c.committed_on - 7.days : nil)
113 since = (c ? c.committed_on - 7.days : nil)
113
114
114 revisions = scm.revisions('', nil, nil, {:all => true, :since => since, :reverse => true})
115 revisions = scm.revisions('', nil, nil, {:all => true, :since => since, :reverse => true})
115 return if revisions.nil? || revisions.empty?
116 return if revisions.nil? || revisions.empty?
116
117
117 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
118 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
118
119
119 # Clean out revisions that are no longer in git
120 # Clean out revisions that are no longer in git
120 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
121 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
121
122
122 # Subtract revisions that redmine already knows about
123 # Subtract revisions that redmine already knows about
123 recent_revisions = recent_changesets.map{|c| c.scmid}
124 recent_revisions = recent_changesets.map{|c| c.scmid}
124 revisions.reject!{|r| recent_revisions.include?(r.scmid)}
125 revisions.reject!{|r| recent_revisions.include?(r.scmid)}
125
126
126 # Save the remaining ones to the database
127 # Save the remaining ones to the database
127 unless revisions.nil?
128 unless revisions.nil?
128 revisions.each do |rev|
129 revisions.each do |rev|
129 transaction do
130 transaction do
130 save_revision(rev)
131 save_revision(rev)
131 end
132 end
132 end
133 end
133 end
134 end
134 end
135 end
135
136
136 def save_revision(rev)
137 def save_revision(rev)
137 changeset = Changeset.new(
138 changeset = Changeset.new(
138 :repository => self,
139 :repository => self,
139 :revision => rev.identifier,
140 :revision => rev.identifier,
140 :scmid => rev.scmid,
141 :scmid => rev.scmid,
141 :committer => rev.author,
142 :committer => rev.author,
142 :committed_on => rev.time,
143 :committed_on => rev.time,
143 :comments => rev.message
144 :comments => rev.message
144 )
145 )
145 if changeset.save
146 if changeset.save
146 rev.paths.each do |file|
147 rev.paths.each do |file|
147 Change.create(
148 Change.create(
148 :changeset => changeset,
149 :changeset => changeset,
149 :action => file[:action],
150 :action => file[:action],
150 :path => file[:path])
151 :path => file[:path])
151 end
152 end
152 end
153 end
153 end
154 end
154 private :save_revision
155 private :save_revision
155
156
156 def latest_changesets(path,rev,limit=10)
157 def latest_changesets(path,rev,limit=10)
157 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
158 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
158 return [] if revisions.nil? || revisions.empty?
159 return [] if revisions.nil? || revisions.empty?
159
160
160 changesets.find(
161 changesets.find(
161 :all,
162 :all,
162 :conditions => [
163 :conditions => [
163 "scmid IN (?)",
164 "scmid IN (?)",
164 revisions.map!{|c| c.scmid}
165 revisions.map!{|c| c.scmid}
165 ],
166 ],
166 :order => 'committed_on DESC'
167 :order => 'committed_on DESC'
167 )
168 )
168 end
169 end
169 end
170 end
General Comments 0
You need to be logged in to leave comments. Login now