##// END OF EJS Templates
scm: add scm specific human_attribute_name for input validation....
Toshi MARUYAMA -
r4855:026c9e87c064
parent child
Show More
@@ -1,91 +1,98
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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/bazaar_adapter'
18 require 'redmine/scm/adapters/bazaar_adapter'
19
19
20 class Repository::Bazaar < Repository
20 class Repository::Bazaar < Repository
21 attr_protected :root_url
21 attr_protected :root_url
22 validates_presence_of :url
22 validates_presence_of :url
23
23
24 ATTRIBUTE_KEY_NAMES = {
25 "url" => "Root directory",
26 }
27 def self.human_attribute_name(attribute_key_name)
28 ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
29 end
30
24 def self.scm_adapter_class
31 def self.scm_adapter_class
25 Redmine::Scm::Adapters::BazaarAdapter
32 Redmine::Scm::Adapters::BazaarAdapter
26 end
33 end
27
34
28 def self.scm_name
35 def self.scm_name
29 'Bazaar'
36 'Bazaar'
30 end
37 end
31
38
32 def entries(path=nil, identifier=nil)
39 def entries(path=nil, identifier=nil)
33 entries = scm.entries(path, identifier)
40 entries = scm.entries(path, identifier)
34 if entries
41 if entries
35 entries.each do |e|
42 entries.each do |e|
36 next if e.lastrev.revision.blank?
43 next if e.lastrev.revision.blank?
37 # Set the filesize unless browsing a specific revision
44 # Set the filesize unless browsing a specific revision
38 if identifier.nil? && e.is_file?
45 if identifier.nil? && e.is_file?
39 full_path = File.join(root_url, e.path)
46 full_path = File.join(root_url, e.path)
40 e.size = File.stat(full_path).size if File.file?(full_path)
47 e.size = File.stat(full_path).size if File.file?(full_path)
41 end
48 end
42 c = Change.find(:first,
49 c = Change.find(:first,
43 :include => :changeset,
50 :include => :changeset,
44 :conditions => ["#{Change.table_name}.revision = ? and #{Changeset.table_name}.repository_id = ?", e.lastrev.revision, id],
51 :conditions => ["#{Change.table_name}.revision = ? and #{Changeset.table_name}.repository_id = ?", e.lastrev.revision, id],
45 :order => "#{Changeset.table_name}.revision DESC")
52 :order => "#{Changeset.table_name}.revision DESC")
46 if c
53 if c
47 e.lastrev.identifier = c.changeset.revision
54 e.lastrev.identifier = c.changeset.revision
48 e.lastrev.name = c.changeset.revision
55 e.lastrev.name = c.changeset.revision
49 e.lastrev.author = c.changeset.committer
56 e.lastrev.author = c.changeset.committer
50 end
57 end
51 end
58 end
52 end
59 end
53 end
60 end
54
61
55 def fetch_changesets
62 def fetch_changesets
56 scm_info = scm.info
63 scm_info = scm.info
57 if scm_info
64 if scm_info
58 # latest revision found in database
65 # latest revision found in database
59 db_revision = latest_changeset ? latest_changeset.revision.to_i : 0
66 db_revision = latest_changeset ? latest_changeset.revision.to_i : 0
60 # latest revision in the repository
67 # latest revision in the repository
61 scm_revision = scm_info.lastrev.identifier.to_i
68 scm_revision = scm_info.lastrev.identifier.to_i
62 if db_revision < scm_revision
69 if db_revision < scm_revision
63 logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug?
70 logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug?
64 identifier_from = db_revision + 1
71 identifier_from = db_revision + 1
65 while (identifier_from <= scm_revision)
72 while (identifier_from <= scm_revision)
66 # loads changesets by batches of 200
73 # loads changesets by batches of 200
67 identifier_to = [identifier_from + 199, scm_revision].min
74 identifier_to = [identifier_from + 199, scm_revision].min
68 revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true)
75 revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true)
69 transaction do
76 transaction do
70 revisions.reverse_each do |revision|
77 revisions.reverse_each do |revision|
71 changeset = Changeset.create(:repository => self,
78 changeset = Changeset.create(:repository => self,
72 :revision => revision.identifier,
79 :revision => revision.identifier,
73 :committer => revision.author,
80 :committer => revision.author,
74 :committed_on => revision.time,
81 :committed_on => revision.time,
75 :scmid => revision.scmid,
82 :scmid => revision.scmid,
76 :comments => revision.message)
83 :comments => revision.message)
77
84
78 revision.paths.each do |change|
85 revision.paths.each do |change|
79 Change.create(:changeset => changeset,
86 Change.create(:changeset => changeset,
80 :action => change[:action],
87 :action => change[:action],
81 :path => change[:path],
88 :path => change[:path],
82 :revision => change[:revision])
89 :revision => change[:revision])
83 end
90 end
84 end
91 end
85 end unless revisions.nil?
92 end unless revisions.nil?
86 identifier_from = identifier_to + 1
93 identifier_from = identifier_to + 1
87 end
94 end
88 end
95 end
89 end
96 end
90 end
97 end
91 end
98 end
@@ -1,171 +1,179
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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/cvs_adapter'
18 require 'redmine/scm/adapters/cvs_adapter'
19 require 'digest/sha1'
19 require 'digest/sha1'
20
20
21 class Repository::Cvs < Repository
21 class Repository::Cvs < Repository
22 validates_presence_of :url, :root_url
22 validates_presence_of :url, :root_url
23
23
24 ATTRIBUTE_KEY_NAMES = {
25 "url" => "CVSROOT",
26 "root_url" => "Module",
27 }
28 def self.human_attribute_name(attribute_key_name)
29 ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
30 end
31
24 def self.scm_adapter_class
32 def self.scm_adapter_class
25 Redmine::Scm::Adapters::CvsAdapter
33 Redmine::Scm::Adapters::CvsAdapter
26 end
34 end
27
35
28 def self.scm_name
36 def self.scm_name
29 'CVS'
37 'CVS'
30 end
38 end
31
39
32 def entry(path=nil, identifier=nil)
40 def entry(path=nil, identifier=nil)
33 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
41 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
34 scm.entry(path, rev.nil? ? nil : rev.committed_on)
42 scm.entry(path, rev.nil? ? nil : rev.committed_on)
35 end
43 end
36
44
37 def entries(path=nil, identifier=nil)
45 def entries(path=nil, identifier=nil)
38 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
46 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
39 entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
47 entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
40 if entries
48 if entries
41 entries.each() do |entry|
49 entries.each() do |entry|
42 unless entry.lastrev.nil? || entry.lastrev.identifier
50 unless entry.lastrev.nil? || entry.lastrev.identifier
43 change=changes.find_by_revision_and_path( entry.lastrev.revision, scm.with_leading_slash(entry.path) )
51 change=changes.find_by_revision_and_path( entry.lastrev.revision, scm.with_leading_slash(entry.path) )
44 if change
52 if change
45 entry.lastrev.identifier=change.changeset.revision
53 entry.lastrev.identifier=change.changeset.revision
46 entry.lastrev.author=change.changeset.committer
54 entry.lastrev.author=change.changeset.committer
47 entry.lastrev.revision=change.revision
55 entry.lastrev.revision=change.revision
48 entry.lastrev.branch=change.branch
56 entry.lastrev.branch=change.branch
49 end
57 end
50 end
58 end
51 end
59 end
52 end
60 end
53 entries
61 entries
54 end
62 end
55
63
56 def cat(path, identifier=nil)
64 def cat(path, identifier=nil)
57 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
65 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
58 scm.cat(path, rev.nil? ? nil : rev.committed_on)
66 scm.cat(path, rev.nil? ? nil : rev.committed_on)
59 end
67 end
60
68
61 def diff(path, rev, rev_to)
69 def diff(path, rev, rev_to)
62 #convert rev to revision. CVS can't handle changesets here
70 #convert rev to revision. CVS can't handle changesets here
63 diff=[]
71 diff=[]
64 changeset_from=changesets.find_by_revision(rev)
72 changeset_from=changesets.find_by_revision(rev)
65 if rev_to.to_i > 0
73 if rev_to.to_i > 0
66 changeset_to=changesets.find_by_revision(rev_to)
74 changeset_to=changesets.find_by_revision(rev_to)
67 end
75 end
68 changeset_from.changes.each() do |change_from|
76 changeset_from.changes.each() do |change_from|
69
77
70 revision_from=nil
78 revision_from=nil
71 revision_to=nil
79 revision_to=nil
72
80
73 revision_from=change_from.revision if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
81 revision_from=change_from.revision if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
74
82
75 if revision_from
83 if revision_from
76 if changeset_to
84 if changeset_to
77 changeset_to.changes.each() do |change_to|
85 changeset_to.changes.each() do |change_to|
78 revision_to=change_to.revision if change_to.path==change_from.path
86 revision_to=change_to.revision if change_to.path==change_from.path
79 end
87 end
80 end
88 end
81 unless revision_to
89 unless revision_to
82 revision_to=scm.get_previous_revision(revision_from)
90 revision_to=scm.get_previous_revision(revision_from)
83 end
91 end
84 file_diff = scm.diff(change_from.path, revision_from, revision_to)
92 file_diff = scm.diff(change_from.path, revision_from, revision_to)
85 diff = diff + file_diff unless file_diff.nil?
93 diff = diff + file_diff unless file_diff.nil?
86 end
94 end
87 end
95 end
88 return diff
96 return diff
89 end
97 end
90
98
91 def fetch_changesets
99 def fetch_changesets
92 # some nifty bits to introduce a commit-id with cvs
100 # some nifty bits to introduce a commit-id with cvs
93 # natively cvs doesn't provide any kind of changesets, there is only a revision per file.
101 # natively cvs doesn't provide any kind of changesets, there is only a revision per file.
94 # we now take a guess using the author, the commitlog and the commit-date.
102 # we now take a guess using the author, the commitlog and the commit-date.
95
103
96 # last one is the next step to take. the commit-date is not equal for all
104 # last one is the next step to take. the commit-date is not equal for all
97 # commits in one changeset. cvs update the commit-date when the *,v file was touched. so
105 # commits in one changeset. cvs update the commit-date when the *,v file was touched. so
98 # we use a small delta here, to merge all changes belonging to _one_ changeset
106 # we use a small delta here, to merge all changes belonging to _one_ changeset
99 time_delta=10.seconds
107 time_delta=10.seconds
100
108
101 fetch_since = latest_changeset ? latest_changeset.committed_on : nil
109 fetch_since = latest_changeset ? latest_changeset.committed_on : nil
102 transaction do
110 transaction do
103 tmp_rev_num = 1
111 tmp_rev_num = 1
104 scm.revisions('', fetch_since, nil, :with_paths => true) do |revision|
112 scm.revisions('', fetch_since, nil, :with_paths => true) do |revision|
105 # only add the change to the database, if it doen't exists. the cvs log
113 # only add the change to the database, if it doen't exists. the cvs log
106 # is not exclusive at all.
114 # is not exclusive at all.
107 tmp_time = revision.time.clone
115 tmp_time = revision.time.clone
108 unless changes.find_by_path_and_revision(
116 unless changes.find_by_path_and_revision(
109 scm.with_leading_slash(revision.paths[0][:path]), revision.paths[0][:revision])
117 scm.with_leading_slash(revision.paths[0][:path]), revision.paths[0][:revision])
110 cmt = Changeset.normalize_comments(revision.message, repo_log_encoding)
118 cmt = Changeset.normalize_comments(revision.message, repo_log_encoding)
111 cs = changesets.find(:first, :conditions=>{
119 cs = changesets.find(:first, :conditions=>{
112 :committed_on=>tmp_time - time_delta .. tmp_time + time_delta,
120 :committed_on=>tmp_time - time_delta .. tmp_time + time_delta,
113 :committer=>revision.author,
121 :committer=>revision.author,
114 :comments=>cmt
122 :comments=>cmt
115 })
123 })
116
124
117 # create a new changeset....
125 # create a new changeset....
118 unless cs
126 unless cs
119 # we use a temporaray revision number here (just for inserting)
127 # we use a temporaray revision number here (just for inserting)
120 # later on, we calculate a continous positive number
128 # later on, we calculate a continous positive number
121 tmp_time2 = tmp_time.clone.gmtime
129 tmp_time2 = tmp_time.clone.gmtime
122 branch = revision.paths[0][:branch]
130 branch = revision.paths[0][:branch]
123 scmid = branch + "-" + tmp_time2.strftime("%Y%m%d-%H%M%S")
131 scmid = branch + "-" + tmp_time2.strftime("%Y%m%d-%H%M%S")
124 cs = Changeset.create(:repository => self,
132 cs = Changeset.create(:repository => self,
125 :revision => "tmp#{tmp_rev_num}",
133 :revision => "tmp#{tmp_rev_num}",
126 :scmid => scmid,
134 :scmid => scmid,
127 :committer => revision.author,
135 :committer => revision.author,
128 :committed_on => tmp_time,
136 :committed_on => tmp_time,
129 :comments => revision.message)
137 :comments => revision.message)
130 tmp_rev_num += 1
138 tmp_rev_num += 1
131 end
139 end
132
140
133 #convert CVS-File-States to internal Action-abbrevations
141 #convert CVS-File-States to internal Action-abbrevations
134 #default action is (M)odified
142 #default action is (M)odified
135 action="M"
143 action="M"
136 if revision.paths[0][:action]=="Exp" && revision.paths[0][:revision]=="1.1"
144 if revision.paths[0][:action]=="Exp" && revision.paths[0][:revision]=="1.1"
137 action="A" #add-action always at first revision (= 1.1)
145 action="A" #add-action always at first revision (= 1.1)
138 elsif revision.paths[0][:action]=="dead"
146 elsif revision.paths[0][:action]=="dead"
139 action="D" #dead-state is similar to Delete
147 action="D" #dead-state is similar to Delete
140 end
148 end
141
149
142 Change.create(:changeset => cs,
150 Change.create(:changeset => cs,
143 :action => action,
151 :action => action,
144 :path => scm.with_leading_slash(revision.paths[0][:path]),
152 :path => scm.with_leading_slash(revision.paths[0][:path]),
145 :revision => revision.paths[0][:revision],
153 :revision => revision.paths[0][:revision],
146 :branch => revision.paths[0][:branch]
154 :branch => revision.paths[0][:branch]
147 )
155 )
148 end
156 end
149 end
157 end
150
158
151 # Renumber new changesets in chronological order
159 # Renumber new changesets in chronological order
152 changesets.find(
160 changesets.find(
153 :all, :order => 'committed_on ASC, id ASC', :conditions => "revision LIKE 'tmp%'"
161 :all, :order => 'committed_on ASC, id ASC', :conditions => "revision LIKE 'tmp%'"
154 ).each do |changeset|
162 ).each do |changeset|
155 changeset.update_attribute :revision, next_revision_number
163 changeset.update_attribute :revision, next_revision_number
156 end
164 end
157 end # transaction
165 end # transaction
158 @current_revision_number = nil
166 @current_revision_number = nil
159 end
167 end
160
168
161 private
169 private
162
170
163 # Returns the next revision number to assign to a CVS changeset
171 # Returns the next revision number to assign to a CVS changeset
164 def next_revision_number
172 def next_revision_number
165 # Need to retrieve existing revision numbers to sort them as integers
173 # Need to retrieve existing revision numbers to sort them as integers
166 sql = "SELECT revision FROM #{Changeset.table_name} "
174 sql = "SELECT revision FROM #{Changeset.table_name} "
167 sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
175 sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
168 @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
176 @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
169 @current_revision_number += 1
177 @current_revision_number += 1
170 end
178 end
171 end
179 end
@@ -1,96 +1,103
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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/darcs_adapter'
18 require 'redmine/scm/adapters/darcs_adapter'
19
19
20 class Repository::Darcs < Repository
20 class Repository::Darcs < Repository
21 validates_presence_of :url
21 validates_presence_of :url
22
22
23 ATTRIBUTE_KEY_NAMES = {
24 "url" => "Root directory",
25 }
26 def self.human_attribute_name(attribute_key_name)
27 ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
28 end
29
23 def self.scm_adapter_class
30 def self.scm_adapter_class
24 Redmine::Scm::Adapters::DarcsAdapter
31 Redmine::Scm::Adapters::DarcsAdapter
25 end
32 end
26
33
27 def self.scm_name
34 def self.scm_name
28 'Darcs'
35 'Darcs'
29 end
36 end
30
37
31 def entry(path=nil, identifier=nil)
38 def entry(path=nil, identifier=nil)
32 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier)
39 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier)
33 scm.entry(path, patch.nil? ? nil : patch.scmid)
40 scm.entry(path, patch.nil? ? nil : patch.scmid)
34 end
41 end
35
42
36 def entries(path=nil, identifier=nil)
43 def entries(path=nil, identifier=nil)
37 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier)
44 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier)
38 entries = scm.entries(path, patch.nil? ? nil : patch.scmid)
45 entries = scm.entries(path, patch.nil? ? nil : patch.scmid)
39 if entries
46 if entries
40 entries.each do |entry|
47 entries.each do |entry|
41 # Search the DB for the entry's last change
48 # Search the DB for the entry's last change
42 changeset = changesets.find_by_scmid(entry.lastrev.scmid) if entry.lastrev && !entry.lastrev.scmid.blank?
49 changeset = changesets.find_by_scmid(entry.lastrev.scmid) if entry.lastrev && !entry.lastrev.scmid.blank?
43 if changeset
50 if changeset
44 entry.lastrev.identifier = changeset.revision
51 entry.lastrev.identifier = changeset.revision
45 entry.lastrev.name = changeset.revision
52 entry.lastrev.name = changeset.revision
46 entry.lastrev.time = changeset.committed_on
53 entry.lastrev.time = changeset.committed_on
47 entry.lastrev.author = changeset.committer
54 entry.lastrev.author = changeset.committer
48 end
55 end
49 end
56 end
50 end
57 end
51 entries
58 entries
52 end
59 end
53
60
54 def cat(path, identifier=nil)
61 def cat(path, identifier=nil)
55 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier.to_s)
62 patch = identifier.nil? ? nil : changesets.find_by_revision(identifier.to_s)
56 scm.cat(path, patch.nil? ? nil : patch.scmid)
63 scm.cat(path, patch.nil? ? nil : patch.scmid)
57 end
64 end
58
65
59 def diff(path, rev, rev_to)
66 def diff(path, rev, rev_to)
60 patch_from = changesets.find_by_revision(rev)
67 patch_from = changesets.find_by_revision(rev)
61 return nil if patch_from.nil?
68 return nil if patch_from.nil?
62 patch_to = changesets.find_by_revision(rev_to) if rev_to
69 patch_to = changesets.find_by_revision(rev_to) if rev_to
63 if path.blank?
70 if path.blank?
64 path = patch_from.changes.collect{|change| change.path}.join(' ')
71 path = patch_from.changes.collect{|change| change.path}.join(' ')
65 end
72 end
66 patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil) : nil
73 patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil) : nil
67 end
74 end
68
75
69 def fetch_changesets
76 def fetch_changesets
70 scm_info = scm.info
77 scm_info = scm.info
71 if scm_info
78 if scm_info
72 db_last_id = latest_changeset ? latest_changeset.scmid : nil
79 db_last_id = latest_changeset ? latest_changeset.scmid : nil
73 next_rev = latest_changeset ? latest_changeset.revision.to_i + 1 : 1
80 next_rev = latest_changeset ? latest_changeset.revision.to_i + 1 : 1
74 # latest revision in the repository
81 # latest revision in the repository
75 scm_revision = scm_info.lastrev.scmid
82 scm_revision = scm_info.lastrev.scmid
76 unless changesets.find_by_scmid(scm_revision)
83 unless changesets.find_by_scmid(scm_revision)
77 revisions = scm.revisions('', db_last_id, nil, :with_path => true)
84 revisions = scm.revisions('', db_last_id, nil, :with_path => true)
78 transaction do
85 transaction do
79 revisions.reverse_each do |revision|
86 revisions.reverse_each do |revision|
80 changeset = Changeset.create(:repository => self,
87 changeset = Changeset.create(:repository => self,
81 :revision => next_rev,
88 :revision => next_rev,
82 :scmid => revision.scmid,
89 :scmid => revision.scmid,
83 :committer => revision.author,
90 :committer => revision.author,
84 :committed_on => revision.time,
91 :committed_on => revision.time,
85 :comments => revision.message)
92 :comments => revision.message)
86
93
87 revision.paths.each do |change|
94 revision.paths.each do |change|
88 changeset.create_change(change)
95 changeset.create_change(change)
89 end
96 end
90 next_rev += 1
97 next_rev += 1
91 end if revisions
98 end if revisions
92 end
99 end
93 end
100 end
94 end
101 end
95 end
102 end
96 end
103 end
@@ -1,43 +1,50
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # FileSystem adapter
4 # FileSystem adapter
5 # File written by Paul Rivier, at Demotera.
5 # File written by Paul Rivier, at Demotera.
6 #
6 #
7 # This program is free software; you can redistribute it and/or
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2
9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version.
10 # of the License, or (at your option) any later version.
11 #
11 #
12 # This program is distributed in the hope that it will be useful,
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
15 # GNU General Public License for more details.
16 #
16 #
17 # You should have received a copy of the GNU General Public License
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
21 require 'redmine/scm/adapters/filesystem_adapter'
21 require 'redmine/scm/adapters/filesystem_adapter'
22
22
23 class Repository::Filesystem < Repository
23 class Repository::Filesystem < Repository
24 attr_protected :root_url
24 attr_protected :root_url
25 validates_presence_of :url
25 validates_presence_of :url
26
26
27 ATTRIBUTE_KEY_NAMES = {
28 "url" => "Root directory",
29 }
30 def self.human_attribute_name(attribute_key_name)
31 ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
32 end
33
27 def self.scm_adapter_class
34 def self.scm_adapter_class
28 Redmine::Scm::Adapters::FilesystemAdapter
35 Redmine::Scm::Adapters::FilesystemAdapter
29 end
36 end
30
37
31 def self.scm_name
38 def self.scm_name
32 'Filesystem'
39 'Filesystem'
33 end
40 end
34
41
35 def entries(path=nil, identifier=nil)
42 def entries(path=nil, identifier=nil)
36 scm.entries(path, identifier)
43 scm.entries(path, identifier)
37 end
44 end
38
45
39 def fetch_changesets
46 def fetch_changesets
40 nil
47 nil
41 end
48 end
42
49
43 end
50 end
@@ -1,123 +1,130
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 # Copyright (C) 2007 Patrick Aljord patcito@Ε‹mail.com
3 # Copyright (C) 2007 Patrick Aljord patcito@Ε‹mail.com
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/git_adapter'
18 require 'redmine/scm/adapters/git_adapter'
19
19
20 class Repository::Git < Repository
20 class Repository::Git < Repository
21 attr_protected :root_url
21 attr_protected :root_url
22 validates_presence_of :url
22 validates_presence_of :url
23
23
24 ATTRIBUTE_KEY_NAMES = {
25 "url" => "Path to repository",
26 }
27 def self.human_attribute_name(attribute_key_name)
28 ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
29 end
30
24 def self.scm_adapter_class
31 def self.scm_adapter_class
25 Redmine::Scm::Adapters::GitAdapter
32 Redmine::Scm::Adapters::GitAdapter
26 end
33 end
27
34
28 def self.scm_name
35 def self.scm_name
29 'Git'
36 'Git'
30 end
37 end
31
38
32 def repo_log_encoding
39 def repo_log_encoding
33 'UTF-8'
40 'UTF-8'
34 end
41 end
35
42
36 # Returns the identifier for the given git changeset
43 # Returns the identifier for the given git changeset
37 def self.changeset_identifier(changeset)
44 def self.changeset_identifier(changeset)
38 changeset.scmid
45 changeset.scmid
39 end
46 end
40
47
41 # Returns the readable identifier for the given git changeset
48 # Returns the readable identifier for the given git changeset
42 def self.format_changeset_identifier(changeset)
49 def self.format_changeset_identifier(changeset)
43 changeset.revision[0, 8]
50 changeset.revision[0, 8]
44 end
51 end
45
52
46 def branches
53 def branches
47 scm.branches
54 scm.branches
48 end
55 end
49
56
50 def tags
57 def tags
51 scm.tags
58 scm.tags
52 end
59 end
53
60
54 def find_changeset_by_name(name)
61 def find_changeset_by_name(name)
55 return nil if name.nil? || name.empty?
62 return nil if name.nil? || name.empty?
56 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
63 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
57 return e if e
64 return e if e
58 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
65 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
59 end
66 end
60
67
61 # With SCM's that have a sequential commit numbering, redmine is able to be
68 # With SCM's that have a sequential commit numbering, redmine is able to be
62 # clever and only fetch changesets going forward from the most recent one
69 # clever and only fetch changesets going forward from the most recent one
63 # it knows about. However, with git, you never know if people have merged
70 # it knows about. However, with git, you never know if people have merged
64 # commits into the middle of the repository history, so we should parse
71 # commits into the middle of the repository history, so we should parse
65 # the entire log. Since it's way too slow for large repositories, we only
72 # the entire log. Since it's way too slow for large repositories, we only
66 # parse 1 week before the last known commit.
73 # parse 1 week before the last known commit.
67 # The repository can still be fully reloaded by calling #clear_changesets
74 # The repository can still be fully reloaded by calling #clear_changesets
68 # before fetching changesets (eg. for offline resync)
75 # before fetching changesets (eg. for offline resync)
69 def fetch_changesets
76 def fetch_changesets
70 c = changesets.find(:first, :order => 'committed_on DESC')
77 c = changesets.find(:first, :order => 'committed_on DESC')
71 since = (c ? c.committed_on - 7.days : nil)
78 since = (c ? c.committed_on - 7.days : nil)
72
79
73 revisions = scm.revisions('', nil, nil, :all => true, :since => since)
80 revisions = scm.revisions('', nil, nil, :all => true, :since => since)
74 return if revisions.nil? || revisions.empty?
81 return if revisions.nil? || revisions.empty?
75
82
76 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
83 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
77
84
78 # Clean out revisions that are no longer in git
85 # Clean out revisions that are no longer in git
79 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
86 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
80
87
81 # Subtract revisions that redmine already knows about
88 # Subtract revisions that redmine already knows about
82 recent_revisions = recent_changesets.map{|c| c.scmid}
89 recent_revisions = recent_changesets.map{|c| c.scmid}
83 revisions.reject!{|r| recent_revisions.include?(r.scmid)}
90 revisions.reject!{|r| recent_revisions.include?(r.scmid)}
84
91
85 # Save the remaining ones to the database
92 # Save the remaining ones to the database
86 unless revisions.nil?
93 unless revisions.nil?
87 revisions.each do |rev|
94 revisions.each do |rev|
88 transaction do
95 transaction do
89 changeset = Changeset.new(
96 changeset = Changeset.new(
90 :repository => self,
97 :repository => self,
91 :revision => rev.identifier,
98 :revision => rev.identifier,
92 :scmid => rev.scmid,
99 :scmid => rev.scmid,
93 :committer => rev.author,
100 :committer => rev.author,
94 :committed_on => rev.time,
101 :committed_on => rev.time,
95 :comments => rev.message)
102 :comments => rev.message)
96
103
97 if changeset.save
104 if changeset.save
98 rev.paths.each do |file|
105 rev.paths.each do |file|
99 Change.create(
106 Change.create(
100 :changeset => changeset,
107 :changeset => changeset,
101 :action => file[:action],
108 :action => file[:action],
102 :path => file[:path])
109 :path => file[:path])
103 end
110 end
104 end
111 end
105 end
112 end
106 end
113 end
107 end
114 end
108 end
115 end
109
116
110 def latest_changesets(path,rev,limit=10)
117 def latest_changesets(path,rev,limit=10)
111 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
118 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
112 return [] if revisions.nil? || revisions.empty?
119 return [] if revisions.nil? || revisions.empty?
113
120
114 changesets.find(
121 changesets.find(
115 :all,
122 :all,
116 :conditions => [
123 :conditions => [
117 "scmid IN (?)",
124 "scmid IN (?)",
118 revisions.map!{|c| c.scmid}
125 revisions.map!{|c| c.scmid}
119 ],
126 ],
120 :order => 'committed_on DESC'
127 :order => 'committed_on DESC'
121 )
128 )
122 end
129 end
123 end
130 end
@@ -1,111 +1,118
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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
21 # sort changesets by revision number
22 has_many :changesets, :order => "#{Changeset.table_name}.id DESC", :foreign_key => 'repository_id'
22 has_many :changesets, :order => "#{Changeset.table_name}.id DESC", :foreign_key => 'repository_id'
23
23
24 attr_protected :root_url
24 attr_protected :root_url
25 validates_presence_of :url
25 validates_presence_of :url
26
26
27 FETCH_AT_ONCE = 100 # number of changesets to fetch at once
27 FETCH_AT_ONCE = 100 # number of changesets to fetch at once
28
28
29 ATTRIBUTE_KEY_NAMES = {
30 "url" => "Root directory",
31 }
32 def self.human_attribute_name(attribute_key_name)
33 ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
34 end
35
29 def self.scm_adapter_class
36 def self.scm_adapter_class
30 Redmine::Scm::Adapters::MercurialAdapter
37 Redmine::Scm::Adapters::MercurialAdapter
31 end
38 end
32
39
33 def self.scm_name
40 def self.scm_name
34 'Mercurial'
41 'Mercurial'
35 end
42 end
36
43
37 def repo_log_encoding
44 def repo_log_encoding
38 'UTF-8'
45 'UTF-8'
39 end
46 end
40
47
41 # Returns the readable identifier for the given mercurial changeset
48 # Returns the readable identifier for the given mercurial changeset
42 def self.format_changeset_identifier(changeset)
49 def self.format_changeset_identifier(changeset)
43 "#{changeset.revision}:#{changeset.scmid}"
50 "#{changeset.revision}:#{changeset.scmid}"
44 end
51 end
45
52
46 # Returns the identifier for the given Mercurial changeset
53 # Returns the identifier for the given Mercurial changeset
47 def self.changeset_identifier(changeset)
54 def self.changeset_identifier(changeset)
48 changeset.scmid
55 changeset.scmid
49 end
56 end
50
57
51 def branches
58 def branches
52 nil
59 nil
53 end
60 end
54
61
55 def tags
62 def tags
56 nil
63 nil
57 end
64 end
58
65
59 def diff_format_revisions(cs, cs_to, sep=':')
66 def diff_format_revisions(cs, cs_to, sep=':')
60 super(cs, cs_to, ' ')
67 super(cs, cs_to, ' ')
61 end
68 end
62
69
63 # Finds and returns a revision with a number or the beginning of a hash
70 # Finds and returns a revision with a number or the beginning of a hash
64 def find_changeset_by_name(name)
71 def find_changeset_by_name(name)
65 return nil if name.nil? || name.empty?
72 return nil if name.nil? || name.empty?
66 if /[^\d]/ =~ name or name.to_s.size > 8
73 if /[^\d]/ =~ name or name.to_s.size > 8
67 e = changesets.find(:first, :conditions => ['scmid = ?', name.to_s])
74 e = changesets.find(:first, :conditions => ['scmid = ?', name.to_s])
68 else
75 else
69 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
76 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
70 end
77 end
71 return e if e
78 return e if e
72 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"]) # last ditch
79 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"]) # last ditch
73 end
80 end
74
81
75 # Returns the latest changesets for +path+; sorted by revision number
82 # Returns the latest changesets for +path+; sorted by revision number
76 # Default behavior is to search in cached changesets
83 # Default behavior is to search in cached changesets
77 def latest_changesets(path, rev, limit=10)
84 def latest_changesets(path, rev, limit=10)
78 if path.blank?
85 if path.blank?
79 changesets.find(:all, :include => :user, :limit => limit)
86 changesets.find(:all, :include => :user, :limit => limit)
80 else
87 else
81 changesets.find(:all, :select => "DISTINCT #{Changeset.table_name}.*",
88 changesets.find(:all, :select => "DISTINCT #{Changeset.table_name}.*",
82 :joins => :changes,
89 :joins => :changes,
83 :conditions => ["#{Change.table_name}.path = ? OR #{Change.table_name}.path LIKE ? ESCAPE ?",
90 :conditions => ["#{Change.table_name}.path = ? OR #{Change.table_name}.path LIKE ? ESCAPE ?",
84 path.with_leading_slash,
91 path.with_leading_slash,
85 "#{path.with_leading_slash.gsub(/[%_\\]/) { |s| "\\#{s}" }}/%", '\\'],
92 "#{path.with_leading_slash.gsub(/[%_\\]/) { |s| "\\#{s}" }}/%", '\\'],
86 :include => :user, :limit => limit)
93 :include => :user, :limit => limit)
87 end
94 end
88 end
95 end
89
96
90 def fetch_changesets
97 def fetch_changesets
91 scm_rev = scm.info.lastrev.revision.to_i
98 scm_rev = scm.info.lastrev.revision.to_i
92 db_rev = latest_changeset ? latest_changeset.revision.to_i : -1
99 db_rev = latest_changeset ? latest_changeset.revision.to_i : -1
93 return unless db_rev < scm_rev # already up-to-date
100 return unless db_rev < scm_rev # already up-to-date
94
101
95 logger.debug "Fetching changesets for repository #{url}" if logger
102 logger.debug "Fetching changesets for repository #{url}" if logger
96 (db_rev + 1).step(scm_rev, FETCH_AT_ONCE) do |i|
103 (db_rev + 1).step(scm_rev, FETCH_AT_ONCE) do |i|
97 transaction do
104 transaction do
98 scm.each_revision('', i, [i + FETCH_AT_ONCE - 1, scm_rev].min) do |re|
105 scm.each_revision('', i, [i + FETCH_AT_ONCE - 1, scm_rev].min) do |re|
99 cs = Changeset.create(:repository => self,
106 cs = Changeset.create(:repository => self,
100 :revision => re.revision,
107 :revision => re.revision,
101 :scmid => re.scmid,
108 :scmid => re.scmid,
102 :committer => re.author,
109 :committer => re.author,
103 :committed_on => re.time,
110 :committed_on => re.time,
104 :comments => re.message)
111 :comments => re.message)
105 re.paths.each { |e| cs.create_change(e) }
112 re.paths.each { |e| cs.create_change(e) }
106 end
113 end
107 end
114 end
108 end
115 end
109 self
116 self
110 end
117 end
111 end
118 end
General Comments 0
You need to be logged in to leave comments. Login now