import os.path
import pprint
import subprocess
import sys

import transfer.protocol


class RsyncOverSsh(transfer.protocol.Protocol):
    def __init__(self, options, config):
        super(RsyncOverSsh, self).__init__(options, config)
        self.ssh_config = config.get_value("ssh")

    def build_rsync_command(self, transfer_spec, dry_run):
        dest_path = os.path.join(
            self.ssh_config["root_dir"],
            transfer_spec.dest_path)
        flags = "-avz"
        if dry_run:
            flags += "n"
        cmd = [
            "rsync",
            flags,
            "-e",
            "ssh -p {}".format(self.ssh_config["port"]),
            "--rsync-path",
            # The following command needs to know the right way to do
            # this on the dest platform - ensures the target dir exists.
            "mkdir -p {} && rsync".format(dest_path)
        ]

        # Add source dir exclusions
        if transfer_spec.exclude_paths:
            for exclude_path in transfer_spec.exclude_paths:
                cmd.append("--exclude")
                cmd.append(exclude_path)

        cmd.extend([
            "--delete",
            transfer_spec.source_path + "/",
            "{}@{}:{}".format(
                self.ssh_config["user"],
                self.ssh_config["dest_host"],
                dest_path)])
        return cmd

    def transfer(self, transfer_specs, dry_run):
        if self.options.verbose:
            printer = pprint.PrettyPrinter()
            for spec in transfer_specs:
                printer.pprint(spec)

        for spec in transfer_specs:
            cmd = self.build_rsync_command(spec, dry_run)
            if self.options.verbose:
                print "executing the following command:\n{}".format(cmd)
            result = subprocess.call(
                cmd, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)
            if result != 0:
                return result
