module XMigra::SubversionSpecifics
Constants
- PRODUCTION_PATH_PROPERTY
Public Class Methods
init_schema(schema_config)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 40 def init_schema(schema_config) Console.output_section "Subversion Integration" do puts "Establishing a \"production pattern,\" a regular expression for" puts "recognizing branch identifiers of branches used for production" puts "script generation, simplifies the process of resolving conflicts" puts "in the migration chain, should any arise." puts puts "No escaping (either shell or Ruby) of the regular expression is" puts "necessary when entered here." puts puts "Common choices are:" puts " ^trunk/" puts " ^version/" puts print "Production pattern (empty to skip): " production_pattern = $stdin.gets.chomp return if production_pattern.empty? schema_config.after_dbinfo_creation do tool = SchemaManipulator.new(schema_config.root_path).extend(WarnToStderr) tool.production_pattern = production_pattern end end end
manages(path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 10 def manages(path) begin return true if File.directory?(File.join(path, '.svn')) rescue TypeError return false end `svn info "#{path}" 2>&1` return $?.success? end
run_svn(subcmd, *args)
click to toggle source
Run the svn command line client in XML mode and return a REXML::Document
# File lib/xmigra/vcs_support/svn.rb, line 22 def run_svn(subcmd, *args) options = (Hash === args[-1]) ? args.pop : {} no_result = !options.fetch(:get_result, true) raw_result = options.fetch(:raw, false) || subcmd.to_s == 'cat' cmd_parts = ["svn", subcmd.to_s] cmd_parts << "--xml" unless no_result || raw_result cmd_parts.concat( args.collect {|a| '""'.insert(1, a.to_s)} ) cmd_str = cmd_parts.join(' ') output = `#{cmd_str} 2>#{XMigra::NULL_FILE}` raise(VersionControlError, "Subversion command failed with exit code #{$?.exitstatus}") unless $?.success? return output if raw_result && !no_result return REXML::Document.new(output) unless no_result end
Public Instance Methods
branch_identifier()
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 206 def branch_identifier return @subversion_branch_id if defined? @subversion_branch_id dir_info = subversion_info return @subversion_branch_id = dir_info.elements['info/entry/url'].text[ dir_info.elements['info/entry/repository/root'].text.length..-1 ] end
branch_use() { |use| ... }
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 192 def branch_use # Look for xmigra:production-path on the database directory (self.path) return nil unless prod_path_element = subversion(:propget, PRODUCTION_PATH_PROPERTY, self.path).elements['properties/target/property'] prod_path_pattern = Regexp.new(prod_path_element.text) use = prod_path_pattern.match(branch_identifier) ? :production : :development if block_given? yield use else return use end end
check_working_copy!()
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 70 def check_working_copy! return unless production schema_info = subversion_info file_paths = Array.from_generator(method(:each_file_path)) status = subversion(:status, '--no-ignore', path) unversioned_files = status.elements.each("status/target/entry/@path") unversioned_files = unversioned_files.collect {|a| File.expand_path(a.to_s)} unless (file_paths & unversioned_files).empty? raise VersionControlError, "Some source files are not versions found in the repository" end status = nil wc_rev = {} working_rev = schema_info.elements["info/entry/@revision"].value.to_i file_paths.each do |fp| fp_info = subversion(:info, fp) wc_rev[fp] = fp_wc_rev = fp_info.elements["info/entry/@revision"].value.to_i if working_rev != fp_wc_rev raise VersionControlError, "The working copy contains objects at multiple revisions" end end migrations.each do |m| fpath = m.file_path log = subversion(:log, "-r#{wc_rev[fpath]}:1", "--stop-on-copy", fpath) if log.elements["log/logentry[2]"] raise VersionControlError, "'#{fpath}' has been modified in the repository since it was created or copied" end end # Since a production script was requested, warn if we are not generating # from a production branch if branch_use != :production and self.respond_to? :warning self.warning(<<END_OF_MESSAGE) The branch backing the target working copy is not marked as a production branch. END_OF_MESSAGE end end
get_conflict_info()
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 120 def get_conflict_info # Check if the structure head is conflicted structure_dir = Pathname.new(self.path) + SchemaManipulator::STRUCTURE_SUBDIR status = subversion(:status, structure_dir + MigrationChain::HEAD_FILE) return nil if status.elements["status/target/entry/wc-status/@item"].value != "conflicted" chain_head = lambda do |extension| pattern = MigrationChain::HEAD_FILE + extension if extension.include? '*' files = structure_dir.glob(MigrationChain::HEAD_FILE + extension) raise VersionControlError, "Multiple #{pattern} files in structure directory" if files.length > 1 raise VersionControlError, "#{pattern} file missing from structure directory" if files.length < 1 else files = [structure_dir.join(pattern)] end # Using YAML.parse_file and YAML::Syck::Node#transform rerenders # scalars in the same style they were read from the source file: return YAML.parse_file(files[0]).transform end if (structure_dir + (MigrationChain::HEAD_FILE + ".working")).exist? # This is a merge conflict # structure/head.yaml.working is from the current branch # structure/head.yaml.merge-left.r* is the branch point # structure/head.yaml.merge-right.r* is from the merged-in branch this_head = chain_head.call(".working") other_head = chain_head.call(".merge-right.r*") branch_point = chain_head.call(".merge-left.r*")[MigrationChain::LATEST_CHANGE] conflict = MigrationConflict.new(structure_dir, branch_point, [other_head, this_head]) branch_use {|u| conflict.branch_use = u} else # This is an update conflict # structure/head.yaml.mine is from the working copy # structure/head.yaml.r<lower> is the common ancestor # structure/head.yaml.r<higher> is the newer revision working_head = chain_head.call('.mine') oldrev, newrev = nil, 0 structure_dir.glob(MigrationChain::HEAD_FILE + '.r*') do |fn| if fn.to_s =~ /.r(\d+)$/ rev = $1.to_i if oldrev.nil? or rev < oldrev oldrev = rev end if newrev < rev newrev = rev end end end repo_head = chain_head.call(".r#{newrev}") branch_point = chain_head.call(".r#{oldrev}")[MigrationChain::LATEST_CHANGE] conflict = MigrationConflict.new(structure_dir, branch_point, [repo_head, working_head]) branch_use {|u| conflict.branch_use = u} fix_target, = conflict.migration_tweak fix_target_st = subversion(:status, fix_target) if fix_target_st.elements['status/target/entry/wc-status/@item'].value == 'modified' conflict.scope = :working_copy end end tool = self conflict.after_fix = proc {tool.resolve_conflict!(structure_dir + MigrationChain::HEAD_FILE)} return conflict end
production_pattern()
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 214 def production_pattern subversion(:propget, PRODUCTION_PATH_PROPERTY, self.path, :raw=>true) end
production_pattern=(pattern)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 217 def production_pattern=(pattern) subversion(:propset, PRODUCTION_PATH_PROPERTY, pattern, self.path, :get_result=>false) end
resolve_conflict!(path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 221 def resolve_conflict!(path) subversion(:resolve, '--accept=working', path, :get_result=>false) end
subversion(*args)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 66 def subversion(*args) SubversionSpecifics.run_svn(*args) end
subversion_info()
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 313 def subversion_info return @subversion_info if defined? @subversion_info return @subversion_info = subversion(:info, self.path) end
subversion_retrieve_status(file_path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 380 def subversion_retrieve_status(file_path) subversion(:status, '-v', file_path).elements['status/target'] end
vcs_changes_from(from_revision, file_path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 372 def vcs_changes_from(from_revision, file_path) subversion(:diff, '-r', from_revision, file_path, :raw=>true) end
vcs_comparator(options={})
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 301 def vcs_comparator(options={}) VersionComparator.new(self, options) end
vcs_contents(path, options={})
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 347 def vcs_contents(path, options={}) args = [] if options[:revision] args << "-r#{options[:revision]}" end args << path.to_s subversion(:cat, *args) end
vcs_file_modified?(file_path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 230 def vcs_file_modified?(file_path) status = subversion_retrieve_status(file_path).elements['entry/wc-status'] !status.nil? && status.attributes['item'] == 'modified' end
vcs_information()
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 112 def vcs_information info = subversion_info return [ "Repository URL: #{info.elements["info/entry/url"].text}", "Revision: #{info.elements["info/entry/@revision"].value}" ].join("\n") end
vcs_latest_revision(a_file=nil)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 359 def vcs_latest_revision(a_file=nil) if a_file.nil? && defined? @vcs_latest_revision return @vcs_latest_revision end val = subversion(:status, '-v', a_file || file_path).elements[ 'string(status/target/entry/wc-status/commit/@revision)' ] (val.nil? ? val : val.to_i).tap do |val| @vcs_latest_revision = val if a_file.nil? end end
vcs_most_recent_committed_contents(file_path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 376 def vcs_most_recent_committed_contents(file_path) subversion(:cat, file_path) end
vcs_move(old_path, new_path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 305 def vcs_move(old_path, new_path) subversion(:move, old_path, new_path, :get_result=>false) end
vcs_production_contents(path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 318 def vcs_production_contents(path) path = Pathname(path) # Check for a production pattern. If none exists, there is no way to # identify which branches are production, so essentially no production # content: prod_pat = self.production_pattern return nil if prod_pat.nil? prod_pat = Regexp.compile(prod_pat.chomp) # Is the current branch a production branch? If so, cat the committed # version: if branch_identifier =~ prod_pat return svn(:cat, path.to_s) end # Use an SvnHistoryTracer to walk back through the history of self.path # looking for a copy from a production branch. tracer = SvnHistoryTracer.new(self.path) while !(match = tracer.earliest_loaded_repopath =~ prod_pat) && tracer.load_parent_commit # loop end if match subversion(:cat, "-r#{tracer.earliest_loaded_revision}", path.to_s) end end
vcs_remove(path)
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 309 def vcs_remove(path) subversion(:remove, path, :get_result=>false) end
vcs_uncommitted?()
click to toggle source
# File lib/xmigra/vcs_support/svn.rb, line 225 def vcs_uncommitted? status = subversion_retrieve_status(file_path).elements['entry/wc-status'] status.nil? || status.attributes['item'] == 'unversioned' end