summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2007-12-03 17:40:43 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2007-12-03 17:40:43 +0000
commit056e3703da194ade315004e7d91ce318eaf1e6b2 (patch)
tree2194839b5c68650cfcb4b9f467fce07dea800c65 /lib
parent92a23c05bb71e62426cec2298d90b39fadd0eb52 (diff)
downloadredmine-056e3703da194ade315004e7d91ce318eaf1e6b2.tar.gz
redmine-056e3703da194ade315004e7d91ce318eaf1e6b2.zip
Added Bazaar adapter.
Fixed 'quick jump to a revision' form on the revisions list. git-svn-id: http://redmine.rubyforge.org/svn/trunk@950 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'lib')
-rw-r--r--lib/redmine.rb2
-rw-r--r--lib/redmine/scm/adapters/bazaar_adapter.rb204
2 files changed, 205 insertions, 1 deletions
diff --git a/lib/redmine.rb b/lib/redmine.rb
index b74f00aec..32239ce59 100644
--- a/lib/redmine.rb
+++ b/lib/redmine.rb
@@ -10,7 +10,7 @@ rescue LoadError
# RMagick is not available
end
-REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs )
+REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar )
# Permissions
Redmine::AccessControl.map do |map|
diff --git a/lib/redmine/scm/adapters/bazaar_adapter.rb b/lib/redmine/scm/adapters/bazaar_adapter.rb
new file mode 100644
index 000000000..ec9fd741c
--- /dev/null
+++ b/lib/redmine/scm/adapters/bazaar_adapter.rb
@@ -0,0 +1,204 @@
+# 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/abstract_adapter'
+
+module Redmine
+ module Scm
+ module Adapters
+ class BazaarAdapter < AbstractAdapter
+
+ # Bazaar executable name
+ BZR_BIN = "bzr"
+
+ # Get info about the repository
+ def info
+ cmd = "#{BZR_BIN} revno #{target('')}"
+ info = nil
+ shellout(cmd) do |io|
+ if io.read =~ %r{^(\d+)$}
+ info = Info.new({:root_url => url,
+ :lastrev => Revision.new({
+ :identifier => $1
+ })
+ })
+ end
+ end
+ return nil if $? && $?.exitstatus != 0
+ info
+ rescue Errno::ENOENT => e
+ return nil
+ end
+
+ # Returns the entry identified by path and revision identifier
+ # or nil if entry doesn't exist in the repository
+ def entry(path=nil, identifier=nil)
+ path ||= ''
+ parts = path.split(%r{[\/\\]}).select {|p| !p.blank?}
+ if parts.size > 0
+ parent = parts[0..-2].join('/')
+ entries = entries(parent, identifier)
+ entries ? entries.detect {|e| e.name == parts.last} : nil
+ end
+ end
+
+ # Returns an Entries collection
+ # or nil if the given path doesn't exist in the repository
+ def entries(path=nil, identifier=nil)
+ path ||= ''
+ entries = Entries.new
+ cmd = "#{BZR_BIN} ls -v --show-ids"
+ cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
+ cmd << " #{target(path)}"
+ shellout(cmd) do |io|
+ prefix = "#{url}/#{path}".gsub('\\', '/')
+ logger.debug "PREFIX: #{prefix}"
+ re = %r{^V\s+#{Regexp.escape(prefix)}(\/?)([^\/]+)(\/?)\s+(\S+)$}
+ io.each_line do |line|
+ next unless line =~ re
+ entries << Entry.new({:name => $2.strip,
+ :path => ((path.empty? ? "" : "#{path}/") + $2.strip),
+ :kind => ($3.blank? ? 'file' : 'dir'),
+ :size => nil,
+ :lastrev => Revision.new(:revision => $4.strip)
+ })
+ end
+ end
+ return nil if $? && $?.exitstatus != 0
+ logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
+ entries.sort_by_name
+ rescue Errno::ENOENT => e
+ raise CommandFailed
+ end
+
+ def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
+ path ||= ''
+ identifier_from = 'last:1' unless identifier_from and identifier_from.to_i > 0
+ identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
+ revisions = Revisions.new
+ cmd = "#{BZR_BIN} log -v --show-ids -r#{identifier_to.to_i}..#{identifier_from} #{target(path)}"
+ shellout(cmd) do |io|
+ revision = nil
+ parsing = nil
+ io.each_line do |line|
+ if line =~ /^----/
+ revisions << revision if revision
+ revision = Revision.new(:paths => [], :message => '')
+ parsing = nil
+ else
+ next unless revision
+
+ if line =~ /^revno: (\d+)$/
+ revision.identifier = $1.to_i
+ elsif line =~ /^committer: (.+)$/
+ revision.author = $1.strip
+ elsif line =~ /^revision-id:(.+)$/
+ revision.scmid = $1.strip
+ elsif line =~ /^timestamp: (.+)$/
+ revision.time = Time.parse($1).localtime
+ elsif line =~ /^(message|added|modified|removed|renamed):/
+ parsing = $1
+ elsif line =~ /^ (.+)$/
+ if parsing == 'message'
+ revision.message << "#{$1}\n"
+ else
+ if $1 =~ /^(.*)\s+(\S+)$/
+ path = $1.strip
+ revid = $2
+ case parsing
+ when 'added'
+ revision.paths << {:action => 'A', :path => "/#{path}", :revision => revid}
+ when 'modified'
+ revision.paths << {:action => 'M', :path => "/#{path}", :revision => revid}
+ when 'removed'
+ revision.paths << {:action => 'D', :path => "/#{path}", :revision => revid}
+ when 'renamed'
+ new_path = path.split('=>').last
+ revision.paths << {:action => 'M', :path => "/#{new_path.strip}", :revision => revid} if new_path
+ end
+ end
+ end
+ else
+ parsing = nil
+ end
+ end
+ end
+ revisions << revision if revision
+ end
+ return nil if $? && $?.exitstatus != 0
+ revisions
+ rescue Errno::ENOENT => e
+ raise CommandFailed
+ end
+
+ def diff(path, identifier_from, identifier_to=nil, type="inline")
+ path ||= ''
+ if identifier_to
+ identifier_to = identifier_to.to_i
+ else
+ identifier_to = identifier_from.to_i - 1
+ end
+ cmd = "#{BZR_BIN} diff -r#{identifier_to}..#{identifier_from} #{target(path)}"
+ diff = []
+ shellout(cmd) do |io|
+ io.each_line do |line|
+ diff << line
+ end
+ end
+ #return nil if $? && $?.exitstatus != 0
+ DiffTableList.new diff, type
+ rescue Errno::ENOENT => e
+ raise CommandFailed
+ end
+
+ def cat(path, identifier=nil)
+ cmd = "#{BZR_BIN} cat"
+ cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
+ cmd << " #{target(path)}"
+ cat = nil
+ shellout(cmd) do |io|
+ io.binmode
+ cat = io.read
+ end
+ return nil if $? && $?.exitstatus != 0
+ cat
+ rescue Errno::ENOENT => e
+ raise CommandFailed
+ end
+
+ def annotate(path, identifier=nil)
+ cmd = "#{BZR_BIN} annotate --all"
+ cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
+ cmd << " #{target(path)}"
+ blame = Annotate.new
+ shellout(cmd) do |io|
+ author = nil
+ identifier = nil
+ io.each_line do |line|
+ next unless line =~ %r{^(\d+) ([^|]+)\| (.*)$}
+ blame.add_line($3.rstrip, Revision.new(:identifier => $1.to_i, :author => $2.strip))
+ end
+ end
+ return nil if $? && $?.exitstatus != 0
+ blame
+ rescue Errno::ENOENT => e
+ raise CommandFailed
+ end
+ end
+ end
+ end
+end