class RSCM::Subversion
RSCM implementation for Subversion.
You need the svn/svnadmin executable on the PATH in order for it to work.
NOTE: On Cygwin these have to be the win32 builds of svn/svnadmin and not the Cygwin ones.
Attributes
password[RW]
path[RW]
Must be specified in order to create repo and install triggers. Must also be specified as “” if the url represents the root of the repository, or files in revisions will not be detected.
url[RW]
username[RW]
Public Class Methods
new(url="", path="")
click to toggle source
# File lib/rscm/scm/subversion.rb, line 26 def initialize(url="", path="") @url, @path = url, path @username = "" @password = "" end
Public Instance Methods
add(relative_filename, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 49 def add(relative_filename, options={}) svn("add #{checkout_dir}/#{relative_filename}", options) end
can_create_central?()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 95 def can_create_central? local? && !path.nil? && !(path == "") end
central_exists?()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 107 def central_exists? if(local?) File.exists?("#{svnrootdir}/db") else # Do a simple command over the network # If the repo/path doesn't exist, we'll get zero output # on stdout (and an error msg on std err). exists = false cmd = "svn log #{url} -r HEAD" execute(cmd) do |stdout| stdout.each_line do |line| exists = true end end exists end end
checked_out?()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 203 def checked_out? rootentries = File.expand_path("#{checkout_dir}/.svn/entries") result = File.exists?(rootentries) result end
commit(message, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 70 def commit(message, options={}) svn(commit_command(message), options) # We have to do an update to get the local revision right checkout_silent(nil, options) end
create_central(options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 136 def create_central(options={}) options = options.dup.merge({:dir => svnrootdir}) native_path = PathConverter.filepath_to_nativepath(svnrootdir, false) mkdir_p(PathConverter.nativepath_to_filepath(native_path)) svnadmin("create #{native_path}", options) if(path != "") options = options.dup.merge({:dir => "."}) # create the directories paths = path.split("/") paths.each_with_index do |p,i| p = paths[0..i] u = "#{repourl}/#{p.join('/')}" svn("mkdir #{u} -m \"Adding directories\"", options) end end end
destroy_central()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 99 def destroy_central if(File.exist?(svnrootdir) && local?) FileUtils.rm_rf(svnrootdir) else raise "Cannot destroy central repository. '#{svnrootdir}' doesn't exist or central repo isn't local to this machine" end end
diff(path, from, to, options={}, &block)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 80 def diff(path, from, to, options={}, &block) cmd = "svn diff --revision #{from}:#{to} \"#{url}/#{path}\"" execute(cmd, options) do |io| return(block.call(io)) end end
import_central(dir, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 171 def import_central(dir, options={}) import_cmd = "import #{dir} #{url} -m \"#{options[:message]}\"" svn(import_cmd, options) end
install_trigger(trigger_command, trigger_files_checkout_dir, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 153 def install_trigger(trigger_command, trigger_files_checkout_dir, options={}) if (WINDOWS) install_win_trigger(trigger_command, trigger_files_checkout_dir, options) else install_unix_trigger(trigger_command, trigger_files_checkout_dir, options) end end
installed?()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 36 def installed? begin svn("--version", {}) true rescue false end end
label()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 76 def label local_revision_identifier.to_s end
move(relative_src, relative_dest, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 53 def move(relative_src, relative_dest, options={}) svn("mv #{checkout_dir}/#{relative_src} #{checkout_dir}/#{relative_dest}", options) end
open(path, native_revision_identifier, options={}, &block)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 87 def open(path, native_revision_identifier, options={}, &block) raise "native_revision_identifier cannot be nil" if native_revision_identifier.nil? cmd = "svn cat #{url}/#{path}@#{native_revision_identifier}" execute(cmd, options) do |io| return(block.call(io)) end end
repourl()
click to toggle source
url pointing to the root of the repo
# File lib/rscm/scm/subversion.rb, line 198 def repourl last = (path.nil? || path == "") ? -1 : -(path.length)-2 url[0..last] end
revisions(from_identifier=Time.new.utc, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 176 def revisions(from_identifier=Time.new.utc, options={}) raise "from_identifer cannot be nil" if from_identifier.nil? options = { :from_identifier => from_identifier, :to_identifier => Time.infinity, :relative_path => "", :dir => Dir.pwd }.merge(options) checkout_dir = PathConverter.filepath_to_nativepath(@checkout_dir, false) revisions = nil command = "svn #{changes_command(options[:from_identifier], options[:to_identifier], options[:relative_path])}" execute(command, options) do |stdout| stdout = StringIO.new(stdout.read) parser = SubversionLogParser.new(stdout, @url, options[:from_identifier], options[:to_identifier], path) revisions = parser.parse_revisions end revisions.cmd = command if store_revisions_command? revisions end
supports_trigger?()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 125 def supports_trigger? true # we'll assume it supports trigger even if not local. this is to ensure user interfaces # can display appropriate options, even if the object is not 'fully initialised' # local? end
to_identifier(raw_identifier)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 45 def to_identifier(raw_identifier) raw_identifier.to_i end
transactional?()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 57 def transactional? true end
trigger_installed?(trigger_command, trigger_files_checkout_dir, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 165 def trigger_installed?(trigger_command, trigger_files_checkout_dir, options={}) return false unless File.exist?(post_commit_file) not_already_commented = LineEditor.comment_out(File.new(post_commit_file), /#{Regexp.escape(trigger_command)}/, "# ", "") not_already_commented end
trigger_mechanism()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 132 def trigger_mechanism "hooks/post-commit" end
uninstall_trigger(trigger_command, trigger_files_checkout_dir, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 161 def uninstall_trigger(trigger_command, trigger_files_checkout_dir, options={}) File.comment_out(post_commit_file, /#{Regexp.escape(trigger_command)}/, nil) end
uptodate?(identifier, options={})
click to toggle source
# File lib/rscm/scm/subversion.rb, line 61 def uptodate?(identifier, options={}) if(!checked_out?) false else rev = identifier.nil? ? head_revision_identifier(options) : identifier local_revision_identifier(options) == rev end end
Protected Instance Methods
checkout_silent(to_identifier, options)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 211 def checkout_silent(to_identifier, options) checkout_dir = PathConverter.filepath_to_nativepath(@checkout_dir, false) mkdir_p(@checkout_dir) if(checked_out?) svn(update_command(to_identifier), options) else svn(checkout_command(to_identifier), options) end end
ignore_paths()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 221 def ignore_paths [/\.svn\/.*/] end
Private Instance Methods
changes_command(from_identifier, to_identifier, relative_path)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 315 def changes_command(from_identifier, to_identifier, relative_path) # http://svnbook.red-bean.com/svnbook-1.1/svn-book.html#svn-ch-3-sect-3.3 # file_list = files.join('\n') "log --verbose #{login_options} #{revision_option(from_identifier, to_identifier)} #{@url}" end
checkout_command(to_identifier)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 307 def checkout_command(to_identifier) "checkout #{login_options} #{url} #{revision_option(nil,to_identifier)} #{quoted_checkout_dir}" end
commit_command(message)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 368 def commit_command(message) "commit #{login_options} --force-log -m \"#{message}\" #{quoted_checkout_dir}" end
head_revision_identifier(options)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 236 def head_revision_identifier(options) # This command only seems to yield any changesets if the url is the root of # the repo, which we don't know in the case where path is not specified (likely) # We therefore don't specify it and get the latest revision from the full url instead. # cmd = "svn log #{login_options} #{repourl} -r HEAD" cmd = "svn log #{login_options} #{url}" execute(cmd, options) do |stdout| parser = SubversionLogParser.new(stdout, @url) revisions = parser.parse_revisions revisions[0].identifier end end
install_unix_trigger(trigger_command, damagecontrol_install_dir, options)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 249 def install_unix_trigger(trigger_command, damagecontrol_install_dir, options) post_commit_exists = File.exists?(post_commit_file) mode = post_commit_exists ? File::APPEND|File::WRONLY : File::CREAT|File::WRONLY begin File.open(post_commit_file, mode) do |file| file.puts("#!/bin/sh") unless post_commit_exists file.puts("#{trigger_command}\n" ) end File.chmod(0744, post_commit_file) rescue raise ["Didn't have permission to write to #{post_commit_file}.", "Try to manually add the following line:", trigger_command, "Finally make it executable with chmod g+x #{post_commit_file}"] end end
install_win_trigger(trigger_command, damagecontrol_install_dir, options)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 266 def install_win_trigger(trigger_command, damagecontrol_install_dir, options) post_commit_exists = File.exists?(post_commit_file) mode = post_commit_exists ? File::APPEND|File::WRONLY : File::CREAT|File::WRONLY begin File.open(post_commit_file, mode) do |file| file.puts("#{trigger_command}\n" ) end rescue raise ["Didn't have permission to write to #{post_commit_file}.", "Try to manually add the following line:", trigger_command] end end
local?()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 378 def local? if(url =~ /^file:/) return true else return false end end
local_revision_identifier(options)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 227 def local_revision_identifier(options) local_revision_identifier = nil svn("info #{quoted_checkout_dir}", options) do |line| if(line =~ /Revision: ([0-9]*)/) return $1.to_i end end end
login_options()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 321 def login_options result = "" u = @username ? @username.strip : "" p = @password ? @password.strip : "" result << "--username #{u} " unless u == "" result << "--password #{p} " unless p == "" result end
post_commit_file()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 386 def post_commit_file # We actualy need to use the .cmd when on cygwin. The cygwin svn post-commit # hook is hosed. We'll be relying on native windows if(local?) WINDOWS ? "#{svnrootdir}/hooks/post-commit.cmd" : "#{svnrootdir}/hooks/post-commit" else raise "The repository is not local. Cannot install or uninstall trigger." end end
quoted_checkout_dir()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 372 def quoted_checkout_dir cd = '"' + PathConverter.filepath_to_nativepath(checkout_dir, false) + '"' raise "checkout_dir not set" if cd == "" cd end
revision_option(from_identifier, to_identifier)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 330 def revision_option(from_identifier, to_identifier) # The inclusive start from = nil if(from_identifier.is_a?(Time)) from = svndate(from_identifier) elsif(from_identifier.is_a?(Numeric)) from = from_identifier elsif(!from_identifier.nil?) raise "from_identifier must be Numeric, Time or nil. Was: #{from_identifier} (#{from_identifier.class.name})" end to = nil if(to_identifier.is_a?(Time)) to = svndate(to_identifier) elsif(to_identifier.is_a?(Numeric)) to = to_identifier elsif(!from_identifier.nil?) raise "to_identifier must be Numeric, Time or nil. Was: #{to_identifier} (#{to_identifier.class.name})" end revision_option = nil if(from && to.nil?) revision_option = "--revision #{from}:HEAD" elsif(from.nil? && to) revision_option = "--revision #{to}" elsif(from.nil? && to.nil?) revision_option = "" elsif(from && to) revision_option = "--revision #{from}:#{to}" end revision_option end
svn(cmd, options={}, &proc)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 294 def svn(cmd, options={}, &proc) svncommand("svn", cmd, options, &proc) end
svnadmin(cmd, options={}, &proc)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 290 def svnadmin(cmd, options={}, &proc) svncommand("svnadmin", cmd, options, &proc) end
svncommand(executable, cmd, options) { |line| ... }
click to toggle source
# File lib/rscm/scm/subversion.rb, line 298 def svncommand(executable, cmd, options, &proc) command_line = "#{executable} #{cmd}" execute(command_line, options) do |stdout| stdout.each_line do |line| yield line if block_given? end end end
svndate(time)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 363 def svndate(time) return nil unless time time.utc.strftime("{\"%Y-%m-%d %H:%M:%S\"}") end
svnrootdir()
click to toggle source
# File lib/rscm/scm/subversion.rb, line 280 def svnrootdir last = (path.nil? || path == "") ? -1 : -(path.length)-2 result = url["file://".length..last] # for windows, turn /c:/blabla into c:/blabla" if(result =~ /^\/[a-zA-Z]:/) result = result[1..-1] end result end
update_command(to_identifier)
click to toggle source
# File lib/rscm/scm/subversion.rb, line 311 def update_command(to_identifier) "update #{login_options} #{revision_option(nil,to_identifier)} #{quoted_checkout_dir}" end