class Piston::Commands::Switch
Public Class Methods
aliases()
click to toggle source
# File lib/piston/commands/switch.rb, line 134 def self.aliases %w(sw) end
detailed_help()
click to toggle source
# File lib/piston/commands/switch.rb, line 119 def self.detailed_help <<EOF usage: switch NEW_REPOSITORY_ROOT DIR This operation changes the remote location from A to B, keeping local changes. If any local modifications were done, they will be preserved. If merge conflicts occur, they will not be taken care of, and your subsequent commit will fail. Piston will refuse to update a folder if it has pending updates. Run 'svn update' on the target folder to update it before running Piston again. EOF end
help()
click to toggle source
# File lib/piston/commands/switch.rb, line 115 def self.help "Switches a single directory to a new repository root" end
Public Instance Methods
copy(dir, file)
click to toggle source
# File lib/piston/commands/switch.rb, line 106 def copy(dir, file) FileUtils.cp(File.join(dir.tmp, file), File.join(dir, file)) end
run()
click to toggle source
# File lib/piston/commands/switch.rb, line 7 def run new_root, dir = args.shift, args.shift raise Piston::CommandError, "Expected two arguments only to switch. Unrecognized arguments: #{args.inspect}" unless args.empty? raise Piston::CommandError, "Expected a new vendor repository URL." if new_root.nil? raise Piston::CommandError, "Expected a directory to update." if dir.nil? switch(dir, new_root) end
skip(dir, msg, header=true)
click to toggle source
# File lib/piston/commands/switch.rb, line 110 def skip(dir, msg, header=true) logging_stream.print "Skipping '#{dir}': " if header logging_stream.puts msg end
switch(dir, new_repos)
click to toggle source
# File lib/piston/commands/switch.rb, line 15 def switch(dir, new_repos) return unless File.directory?(dir) return skip(dir, "locked") unless svn(:propget, LOCKED, dir) == '' status = svn(:status, '--show-updates', dir) new_local_rev = nil new_status = Array.new status.each_line do |line| if line =~ /status.+\s(\d+)$/i then new_local_rev = $1.to_i else new_status << line unless line =~ /^\?/ end end raise "Unable to parse status\n#{status}" unless new_local_rev return skip(dir, "pending updates -- run \"svn update #{dir}\"\n#{new_status}") if new_status.size > 0 logging_stream.puts "Processing '#{dir}'..." repos = svn(:propget, Piston::ROOT, dir).chomp uuid = svn(:propget, Piston::UUID, dir).chomp remote_revision = svn(:propget, Piston::REMOTE_REV, dir).chomp.to_i local_revision = svn(:propget, Piston::LOCAL_REV, dir).chomp.to_i local_revision = local_revision.succ new_info = YAML::load(svn(:info, new_repos)) raise Piston::CommandError, "Switching repositories is not supported at this time\nYou initially imported from #{uuid}, but are now importing from #{new_info['Repository UUID']}" unless uuid == new_info['Repository UUID'] logging_stream.puts " Fetching remote repository's latest revision and UUID" info = YAML::load(svn(:info, "#{repos}@#{remote_revision}")) return skip(dir, "Repository UUID changed\n Expected #{uuid}\n Found #{info['Repository UUID']}\n Repository: #{repos}") unless uuid == info['Repository UUID'] new_remote_rev = new_info['Last Changed Rev'].to_i revisions = (remote_revision .. (revision || new_remote_rev)) logging_stream.puts " Restoring remote repository to known state at r#{revisions.first}" svn :checkout, '--ignore-externals', '--quiet', '--revision', revisions.first, "#{repos}@#{remote_revision}", dir.tmp logging_stream.puts " Updating remote repository to #{new_repos}@#{revisions.last}" updates = svn :switch, '--revision', revisions.last, new_repos, dir.tmp logging_stream.puts " Processing adds/deletes" merges = Array.new changes = 0 updates.each_line do |line| next unless line =~ %r{^([A-Z]).*\s+#{Regexp.escape(dir.tmp)}[\/](.+)$} op, file = $1, $2 changes += 1 case op when 'A' if File.directory?(File.join(dir.tmp, file)) then svn :mkdir, '--quiet', File.join(dir, file) else copy(dir, file) svn :add, '--quiet', '--force', File.join(dir, file) end when 'D' svn :remove, '--quiet', '--force', File.join(dir, file) else copy(dir, file) merges << file end end # Determine if there are any local changes in the pistoned directory log = svn(:log, '--quiet', '--revision', (local_revision .. new_local_rev).to_svn, '--limit', '2', dir) # If none, we skip the merge process if local_revision < new_local_rev && log.count("\n") > 3 then logging_stream.puts " Merging local changes back in" merges.each do |file| begin svn(:merge, '--quiet', '--revision', (local_revision .. new_local_rev).to_svn, File.join(dir, file), File.join(dir, file)) rescue RuntimeError next if $!.message =~ /Unable to find repository location for/ end end end logging_stream.puts " Removing temporary files / folders" FileUtils.rm_rf dir.tmp logging_stream.puts " Updating Piston properties" svn :propset, Piston::ROOT, new_repos, dir svn :propset, Piston::REMOTE_REV, revisions.last, dir svn :propset, Piston::LOCAL_REV, new_local_rev, dir svn :propset, Piston::LOCKED, revisions.last, dir if lock logging_stream.puts " Updated to r#{revisions.last} (#{changes} changes)" end