'''
Manage git repositories and configuration.
'''

from __future__ import unicode_literals

import re

from pyinfra import logger
from pyinfra.api import operation, OperationError

from . import files, ssh
from .util.files import chmod, chown


@operation(pipeline_facts={
    'git_config': 'repo',
})
def config(
    state, host, key, value,
    repo=None,
):
    '''
    Manage git config for a repository or globally.

    + key: the key of the config to ensure
    + value: the value this key should have
    + repo: specify the git repo path to edit local config (defaults to global)

    Example:

    .. code:: python

        git.config(
            {'Ensure user name is set for a repo'},
            key='user.name',
            value='Anon E. Mouse',
            repo='/usr/local/src/pyinfra',
        )

    '''

    existing_config = host.fact.git_config(repo)

    if not existing_config or existing_config.get(key) != value:
        if repo is None:
            yield 'git config --global {0} "{1}"'.format(key, value)
        else:
            yield 'cd {0} && git config --local {1} "{2}"'.format(repo, key, value)


@operation(pipeline_facts={
    'git_branch': 'target',
})
def repo(
    state, host, source, target,
    branch='master', pull=True, rebase=False,
    user=None, group=None, use_ssh_user=False, ssh_keyscan=False,
    update_submodules=False, recursive_submodules=False,
):
    '''
    Clone/pull git repositories.

    + source: the git source URL
    + target: target directory to clone to
    + branch: branch to pull/checkout
    + pull: pull any changes for the branch
    + rebase: when pulling, use ``--rebase``
    + user: chown files to this user after
    + group: chown files to this group after
    + ssh_keyscan: keyscan the remote host if not in known_hosts before clone/pull
    + update_submodules: update any git submodules
    + recursive_submodules: update git submodules recursively

    + [DEPRECATED] use_ssh_user: whether to use the SSH user to clone/pull

    SSH user (deprecated, please use ``preserve_sudo_env``):
        This is an old hack from pyinfra <0.4 which did not support the global
        kwarg ``preserve_sudo_env``. It does the following:

        * makes the target directory writeable by all
        * clones/pulls w/o sudo as the connecting SSH user
        * removes other/group write permissions - unless group is defined, in
          which case only other

    Example:

    .. code:: python

        git.repo(
            {'Clone repo'},
            'https://github.com/Fizzadar/pyinfra.git',
            '/usr/local/src/pyinfra',
        )
    '''

    if use_ssh_user:
        logger.warning(
            'Use of `use_ssh_user` is deprecated, please use `preserve_sudo_env` instead.',
        )

    # Ensure our target directory exists
    yield files.directory(state, host, target)

    # If we're going to chown this after clone/pull, and we're sudo'd, we need to make the
    # directory writeable by the SSH user
    if use_ssh_user:
        yield chmod(target, 'go+w', recursive=True)

    # Do we need to scan for the remote host key?
    if ssh_keyscan:
        # Attempt to parse the domain from the git repository
        domain = re.match(r'^[a-zA-Z0-9]+@([0-9a-zA-Z\.\-]+)', source)

        if domain:
            yield ssh.keyscan(state, host, domain.group(1))
        else:
            raise OperationError(
                'Could not parse domain (to SSH keyscan) from: {0}'.format(source),
            )

    # Store git commands for directory prefix
    git_commands = []
    is_repo = host.fact.directory('/'.join((target, '.git')))

    # Cloning new repo?
    if not is_repo:
        git_commands.append('clone {0} --branch {1} .'.format(source, branch))

    # Ensuring existing repo
    else:
        current_branch = host.fact.git_branch(target)
        if current_branch != branch:
            git_commands.append('fetch')  # fetch to ensure we have the branch locally
            git_commands.append('checkout {0}'.format(branch))

        if pull:
            if rebase:
                git_commands.append('pull --rebase')
            else:
                git_commands.append('pull')

    if update_submodules:
        if recursive_submodules:
            git_commands.append('submodule update --init --recursive')
        else:
            git_commands.append('submodule update --init')

    # Attach prefixes for directory
    command_prefix = 'cd {0} && git'.format(target)
    git_commands = [
        '{0} {1}'.format(command_prefix, command)
        for command in git_commands
    ]

    if use_ssh_user:
        git_commands = [
            {
                'command': command,
                'sudo': False,
                'sudo_user': False,
            }
            for command in git_commands
        ]

    for cmd in git_commands:
        yield cmd

    if use_ssh_user:
        # Remove write permissions from other or other+group when no group
        yield chmod(
            target,
            'o-w' if group else 'go-w',
            recursive=True,
        )

    # Apply any user or group
    if user or group:
        yield chown(target, user, group, recursive=True)

@@ -101,35 +101,8 @@
 re%0A%0A
-from pyinfra import logger%0A
 from
@@ -200,15 +200,8 @@
 port
- chmod,
  cho
@@ -1272,28 +1272,8 @@
 one,
- use_ssh_user=False,
  ssh
@@ -1886,1140 +1886,284 @@
     
-+ %5BDEPRECATED%5D use_ssh_user: whether to use the SSH user to clone/pull%0A%0A    SSH user (deprecated, please use %60%60preserve_sudo_env%60%60):%0A        This is an old hack from pyinfra %3C0.4 which did not support the global%0A        kwarg %60%60preserve_sudo_env%60%60. It does the following:%0A%0A        * makes the target directory writeable by all%0A        * clones/pulls w/o sudo as the connecting SSH user%0A        * removes other/group write permissions - unless group is defined, in%0A          which case only other%0A%0A    Example:%0A%0A    .. code:: python%0A%0A        git.repo(%0A            %7B'Clone repo'%7D,%0A            'https://github.com/Fizzadar/pyinfra.git',%0A            '/usr/local/src/pyinfra',%0A        )%0A    '''%0A%0A    if use_ssh_user:%0A        logger.warning(%0A            'Use of %60use_ssh_user%60 is deprecated, please use %60preserve_sudo_env%60 instead.',%0A        )%0A%0A    # Ensure our target directory exists%0A    yield files.directory(state, host, target)%0A%0A    # If we're going to chown this after clone/pull, and we're sudo'd, we need to make the%0A    # directory writeable by the SSH user%0A    if use_ssh_user:%0A        yield chmod(target, 'go+w', recursive=True
+Example:%0A%0A    .. code:: python%0A%0A        git.repo(%0A            %7B'Clone repo'%7D,%0A            'https://github.com/Fizzadar/pyinfra.git',%0A            '/usr/local/src/pyinfra',%0A        )%0A    '''%0A%0A    # Ensure our target directory exists%0A    yield files.directory(state, host, target
 )%0A%0A 
@@ -3697,494 +3697,50 @@
     
-if use_ssh_user:%0A        git_commands = %5B%0A            %7B%0A                'command': command,%0A                'sudo': False,%0A                'sudo_user': False,%0A            %7D%0A            for command in git_commands%0A        %5D%0A%0A    for cmd in git_commands:%0A        yield cmd%0A%0A    if use_ssh_user:%0A        # Remove write permissions from other or other+group when no group%0A        yield chmod(%0A            target,%0A            'o-w' if group else 'go-w',%0A            recursive=True,%0A        )
+for cmd in git_commands:%0A        yield cmd
 %0A%0A  

Remove deprecated `use_ssh_user` kwarg from `git.repo` operation.