##// END OF EJS Templates
Added Bazaar adapter....
Jean-Philippe Lang -
r937:056e3703da19
parent child
Show More
@@ -0,0 +1,86
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require 'redmine/scm/adapters/bazaar_adapter'
19
20 class Repository::Bazaar < Repository
21 attr_protected :root_url
22 validates_presence_of :url
23
24 def scm_adapter
25 Redmine::Scm::Adapters::BazaarAdapter
26 end
27
28 def self.scm_name
29 'Bazaar'
30 end
31
32 def entries(path=nil, identifier=nil)
33 entries = scm.entries(path, identifier)
34 if entries
35 entries.each do |e|
36 next if e.lastrev.revision.blank?
37 c = Change.find(:first,
38 :include => :changeset,
39 :conditions => ["#{Change.table_name}.revision = ? and #{Changeset.table_name}.repository_id = ?", e.lastrev.revision, id],
40 :order => "#{Changeset.table_name}.revision DESC")
41 if c
42 e.lastrev.identifier = c.changeset.revision
43 e.lastrev.name = c.changeset.revision
44 e.lastrev.author = c.changeset.committer
45 end
46 end
47 end
48 end
49
50 def fetch_changesets
51 scm_info = scm.info
52 if scm_info
53 # latest revision found in database
54 db_revision = latest_changeset ? latest_changeset.revision : 0
55 # latest revision in the repository
56 scm_revision = scm_info.lastrev.identifier.to_i
57 if db_revision < scm_revision
58 logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug?
59 identifier_from = db_revision + 1
60 while (identifier_from <= scm_revision)
61 # loads changesets by batches of 200
62 identifier_to = [identifier_from + 199, scm_revision].min
63 revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true)
64 transaction do
65 revisions.reverse_each do |revision|
66 changeset = Changeset.create(:repository => self,
67 :revision => revision.identifier,
68 :committer => revision.author,
69 :committed_on => revision.time,
70 :scmid => revision.scmid,
71 :comments => revision.message)
72
73 revision.paths.each do |change|
74 Change.create(:changeset => changeset,
75 :action => change[:action],
76 :path => change[:path],
77 :revision => change[:revision])
78 end
79 end
80 end unless revisions.nil?
81 identifier_from = identifier_to + 1
82 end
83 end
84 end
85 end
86 end
@@ -0,0 +1,204
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require 'redmine/scm/adapters/abstract_adapter'
19
20 module Redmine
21 module Scm
22 module Adapters
23 class BazaarAdapter < AbstractAdapter
24
25 # Bazaar executable name
26 BZR_BIN = "bzr"
27
28 # Get info about the repository
29 def info
30 cmd = "#{BZR_BIN} revno #{target('')}"
31 info = nil
32 shellout(cmd) do |io|
33 if io.read =~ %r{^(\d+)$}
34 info = Info.new({:root_url => url,
35 :lastrev => Revision.new({
36 :identifier => $1
37 })
38 })
39 end
40 end
41 return nil if $? && $?.exitstatus != 0
42 info
43 rescue Errno::ENOENT => e
44 return nil
45 end
46
47 # Returns the entry identified by path and revision identifier
48 # or nil if entry doesn't exist in the repository
49 def entry(path=nil, identifier=nil)
50 path ||= ''
51 parts = path.split(%r{[\/\\]}).select {|p| !p.blank?}
52 if parts.size > 0
53 parent = parts[0..-2].join('/')
54 entries = entries(parent, identifier)
55 entries ? entries.detect {|e| e.name == parts.last} : nil
56 end
57 end
58
59 # Returns an Entries collection
60 # or nil if the given path doesn't exist in the repository
61 def entries(path=nil, identifier=nil)
62 path ||= ''
63 entries = Entries.new
64 cmd = "#{BZR_BIN} ls -v --show-ids"
65 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
66 cmd << " #{target(path)}"
67 shellout(cmd) do |io|
68 prefix = "#{url}/#{path}".gsub('\\', '/')
69 logger.debug "PREFIX: #{prefix}"
70 re = %r{^V\s+#{Regexp.escape(prefix)}(\/?)([^\/]+)(\/?)\s+(\S+)$}
71 io.each_line do |line|
72 next unless line =~ re
73 entries << Entry.new({:name => $2.strip,
74 :path => ((path.empty? ? "" : "#{path}/") + $2.strip),
75 :kind => ($3.blank? ? 'file' : 'dir'),
76 :size => nil,
77 :lastrev => Revision.new(:revision => $4.strip)
78 })
79 end
80 end
81 return nil if $? && $?.exitstatus != 0
82 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
83 entries.sort_by_name
84 rescue Errno::ENOENT => e
85 raise CommandFailed
86 end
87
88 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
89 path ||= ''
90 identifier_from = 'last:1' unless identifier_from and identifier_from.to_i > 0
91 identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
92 revisions = Revisions.new
93 cmd = "#{BZR_BIN} log -v --show-ids -r#{identifier_to.to_i}..#{identifier_from} #{target(path)}"
94 shellout(cmd) do |io|
95 revision = nil
96 parsing = nil
97 io.each_line do |line|
98 if line =~ /^----/
99 revisions << revision if revision
100 revision = Revision.new(:paths => [], :message => '')
101 parsing = nil
102 else
103 next unless revision
104
105 if line =~ /^revno: (\d+)$/
106 revision.identifier = $1.to_i
107 elsif line =~ /^committer: (.+)$/
108 revision.author = $1.strip
109 elsif line =~ /^revision-id:(.+)$/
110 revision.scmid = $1.strip
111 elsif line =~ /^timestamp: (.+)$/
112 revision.time = Time.parse($1).localtime
113 elsif line =~ /^(message|added|modified|removed|renamed):/
114 parsing = $1
115 elsif line =~ /^ (.+)$/
116 if parsing == 'message'
117 revision.message << "#{$1}\n"
118 else
119 if $1 =~ /^(.*)\s+(\S+)$/
120 path = $1.strip
121 revid = $2
122 case parsing
123 when 'added'
124 revision.paths << {:action => 'A', :path => "/#{path}", :revision => revid}
125 when 'modified'
126 revision.paths << {:action => 'M', :path => "/#{path}", :revision => revid}
127 when 'removed'
128 revision.paths << {:action => 'D', :path => "/#{path}", :revision => revid}
129 when 'renamed'
130 new_path = path.split('=>').last
131 revision.paths << {:action => 'M', :path => "/#{new_path.strip}", :revision => revid} if new_path
132 end
133 end
134 end
135 else
136 parsing = nil
137 end
138 end
139 end
140 revisions << revision if revision
141 end
142 return nil if $? && $?.exitstatus != 0
143 revisions
144 rescue Errno::ENOENT => e
145 raise CommandFailed
146 end
147
148 def diff(path, identifier_from, identifier_to=nil, type="inline")
149 path ||= ''
150 if identifier_to
151 identifier_to = identifier_to.to_i
152 else
153 identifier_to = identifier_from.to_i - 1
154 end
155 cmd = "#{BZR_BIN} diff -r#{identifier_to}..#{identifier_from} #{target(path)}"
156 diff = []
157 shellout(cmd) do |io|
158 io.each_line do |line|
159 diff << line
160 end
161 end
162 #return nil if $? && $?.exitstatus != 0
163 DiffTableList.new diff, type
164 rescue Errno::ENOENT => e
165 raise CommandFailed
166 end
167
168 def cat(path, identifier=nil)
169 cmd = "#{BZR_BIN} cat"
170 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
171 cmd << " #{target(path)}"
172 cat = nil
173 shellout(cmd) do |io|
174 io.binmode
175 cat = io.read
176 end
177 return nil if $? && $?.exitstatus != 0
178 cat
179 rescue Errno::ENOENT => e
180 raise CommandFailed
181 end
182
183 def annotate(path, identifier=nil)
184 cmd = "#{BZR_BIN} annotate --all"
185 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
186 cmd << " #{target(path)}"
187 blame = Annotate.new
188 shellout(cmd) do |io|
189 author = nil
190 identifier = nil
191 io.each_line do |line|
192 next unless line =~ %r{^(\d+) ([^|]+)\| (.*)$}
193 blame.add_line($3.rstrip, Revision.new(:identifier => $1.to_i, :author => $2.strip))
194 end
195 end
196 return nil if $? && $?.exitstatus != 0
197 blame
198 rescue Errno::ENOENT => e
199 raise CommandFailed
200 end
201 end
202 end
203 end
204 end
@@ -80,4 +80,8 module RepositoriesHelper
80 content_tag('p', form.text_field(:root_url, :label => 'CVSROOT', :size => 60, :required => true, :disabled => !repository.new_record?)) +
80 content_tag('p', form.text_field(:root_url, :label => 'CVSROOT', :size => 60, :required => true, :disabled => !repository.new_record?)) +
81 content_tag('p', form.text_field(:url, :label => 'Module', :size => 30, :required => true, :disabled => !repository.new_record?))
81 content_tag('p', form.text_field(:url, :label => 'Module', :size => 30, :required => true, :disabled => !repository.new_record?))
82 end
82 end
83
84 def bazaar_field_tags(form, repository)
85 content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.new_record?)))
86 end
83 end
87 end
@@ -1,7 +1,7
1 <div class="contextual">
1 <div class="contextual">
2 <% form_tag do %>
2 <% form_tag({:action => 'revision', :id => @project}) do %>
3 <p><%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %>
3 <%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %>
4 <%= submit_tag 'OK' %></p>
4 <%= submit_tag 'OK' %>
5 <% end %>
5 <% end %>
6 </div>
6 </div>
7
7
@@ -10,7 +10,7 rescue LoadError
10 # RMagick is not available
10 # RMagick is not available
11 end
11 end
12
12
13 REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs )
13 REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar )
14
14
15 # Permissions
15 # Permissions
16 Redmine::AccessControl.map do |map|
16 Redmine::AccessControl.map do |map|
General Comments 0
You need to be logged in to leave comments. Login now