from parallels.core import get_logger
from parallels.core.utils.common import default
from parallels.core.utils.common_constants import SSH_DEFAULT_PORT
from parallels.core.utils.unix_utils import format_command
from parallels.plesk.source.web.utils.copy_content.linux.ssh_based import CopyContentLinuxSSHBased

logger = get_logger(__name__)


class CopyContentLinuxRsync(CopyContentLinuxSSHBased):
    def _get_copy_command(
        self, source_host, source_username, source_port, private_ssh_key, source_dir, target_dir, excludes
    ):
        """Get shell command which should be used to copy directories using SSH

        :type source_host: str | unicode
        :type source_username: str | unicode
        :type source_port: int | None
        :type private_ssh_key: str | unicode
        :type source_dir: str | unicode
        :type target_dir: str | unicode
        :type excludes: list[str | unicode]
        :rtype: str | unicode
        """
        ssh_command = format_command(
            'ssh -i {key} -p {port} '
            '-o PasswordAuthentication=no -o StrictHostKeyChecking=no -o GSSAPIAuthentication=no',
            key=private_ssh_key,
            port=default(source_port, SSH_DEFAULT_PORT)
        )

        rsync_command = "rsync -e {ssh_command} -az --timeout=30 --exclude {agent_dir_pattern}"

        rsync_args = dict(
            ssh_command=ssh_command,
            # skip migrator agent files when transferring - they are garbage for the target server
            # now simply match by name pattern, better implementation should pass specific directory to include
            agent_dir_pattern='plesk-migrator-agent-*'
        )

        for num, exclude_value in enumerate(excludes):
            key = 'exclude_%s' % num
            rsync_command += ' --exclude={%s}' % key
            rsync_args[key] = '/%s' % exclude_value

        rsync_command += " {user}@{host}:{source_dir} {target_dir}"
        rsync_args.update(
            user=source_username,
            host=source_host,
            # Double escape source directory name, for rsync and for local shell.
            # Check "--protect-args" option of rsync for details (we can not use this option as
            # we don't know version of rsync on the source).
            source_dir=format_command("{source_dir}/", source_dir=source_dir),
            target_dir=target_dir + '/',
        )

        return format_command(rsync_command, **rsync_args)

    def get_method_title(self):
        """Get transfer method title as string

        :rtype: str | unicode
        """
        return 'rsync'
