# File lib/piston/commands/update.rb, line 14
      def update(dir)
        return unless File.directory?(dir)
        return skip(dir, "locked") unless svn(:propget, Piston::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

        logging_stream.puts "  Fetching remote repository's latest revision and UUID"
        info = YAML::load(svn(:info, repos))
        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 = info['Last Changed Rev'].to_i
        return skip(dir, "unchanged from revision #{remote_revision}", false) if remote_revision == new_remote_rev

        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, dir.tmp

        logging_stream.puts "  Updating remote repository to r#{revisions.last}"
        updates = svn :update, '--ignore-externals', '--revision', revisions.last, 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::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