Ensure that a repository exists in the given directory

    .. warning::
        If the minion has Git 2.5 or later installed, ``name`` points to a
        worktree_, and ``force`` is set to ``True``, then the worktree will be
        deleted. This has been corrected in Salt 2015.8.0.

    name
        Path to the directory

        .. versionchanged:: 2015.8.0
            This path must now be absolute

    force : False
        If ``True``, and if ``name`` points to an existing directory which does
        not contain a git repository, then the contents of that directory will
        be recursively removed and a new repository will be initialized in its
        place.

    bare : True
        If ``True``, and a repository must be initialized, then the repository
        will be a bare repository.

        .. note::
            This differs from the default behavior of :py:func:`git.init
            <salt.modules.git.init>`, make sure to set this value to ``False``
            if a bare repo is not desired.

    template
        If a new repository is initialized, this argument will specify an
        alternate template directory.

        .. versionadded:: 2015.8.0

    separate_git_dir
        If a new repository is initialized, this argument will specify an
        alternate ``$GIT_DIR``

        .. versionadded:: 2015.8.0

    shared
        Set sharing permissions on git repo. See `git-init(1)`_ for more
        details.

        .. versionadded:: 2015.5.0

    user
        User under which to run git commands. By default, commands are run by
        the user under which the minion is running.

        .. versionadded:: 0.17.0

    password
        Windows only. Required when specifying ``user``. This parameter will be
        ignored on non-Windows platforms.

      .. versionadded:: 2016.3.4

    output_encoding
        Use this option to specify which encoding to use to decode the output
        from any git commands which are run. This should not be needed in most
        cases.

        .. note::
            This should only be needed if the files in the repository were
            created with filenames using an encoding other than UTF-8 to handle
            Unicode characters.

        .. versionadded:: 2018.3.1

    .. _`git-init(1)`: http://git-scm.com/docs/git-init
    .. _`worktree`: http://git-scm.com/docs/git-worktree

def present(name,
            force=False,
            bare=True,
            template=None,
            separate_git_dir=None,
            shared=None,
            user=None,
            password=None,
            output_encoding=None):
    '''
    Ensure that a repository exists in the given directory

    .. warning::
        If the minion has Git 2.5 or later installed, ``name`` points to a
        worktree_, and ``force`` is set to ``True``, then the worktree will be
        deleted. This has been corrected in Salt 2015.8.0.

    name
        Path to the directory

        .. versionchanged:: 2015.8.0
            This path must now be absolute

    force : False
        If ``True``, and if ``name`` points to an existing directory which does
        not contain a git repository, then the contents of that directory will
        be recursively removed and a new repository will be initialized in its
        place.

    bare : True
        If ``True``, and a repository must be initialized, then the repository
        will be a bare repository.

        .. note::
            This differs from the default behavior of :py:func:`git.init
            <salt.modules.git.init>`, make sure to set this value to ``False``
            if a bare repo is not desired.

    template
        If a new repository is initialized, this argument will specify an
        alternate template directory.

        .. versionadded:: 2015.8.0

    separate_git_dir
        If a new repository is initialized, this argument will specify an
        alternate ``$GIT_DIR``

        .. versionadded:: 2015.8.0

    shared
        Set sharing permissions on git repo. See `git-init(1)`_ for more
        details.

        .. versionadded:: 2015.5.0

    user
        User under which to run git commands. By default, commands are run by
        the user under which the minion is running.

        .. versionadded:: 0.17.0

    password
        Windows only. Required when specifying ``user``. This parameter will be
        ignored on non-Windows platforms.

      .. versionadded:: 2016.3.4

    output_encoding
        Use this option to specify which encoding to use to decode the output
        from any git commands which are run. This should not be needed in most
        cases.

        .. note::
            This should only be needed if the files in the repository were
            created with filenames using an encoding other than UTF-8 to handle
            Unicode characters.

        .. versionadded:: 2018.3.1

    .. _`git-init(1)`: http://git-scm.com/docs/git-init
    .. _`worktree`: http://git-scm.com/docs/git-worktree
    '''
    ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}

    # If the named directory is a git repo return True
    if os.path.isdir(name):
        if bare and os.path.isfile(os.path.join(name, 'HEAD')):
            return ret
        elif not bare and \
                (os.path.isdir(os.path.join(name, '.git')) or
                 __salt__['git.is_worktree'](name,
                                             user=user,
                                             password=password,
                                             output_encoding=output_encoding)):
            return ret
        # Directory exists and is not a git repo, if force is set destroy the
        # directory and recreate, otherwise throw an error
        elif force:
            # Directory exists, and the ``force`` option is enabled, so we need
            # to clear out its contents to proceed.
            if __opts__['test']:
                ret['changes']['new'] = name
                ret['changes']['forced init'] = True
                return _neutral_test(
                    ret,
                    'Target directory {0} exists. Since force=True, the '
                    'contents of {0} would be deleted, and a {1}repository '
                    'would be initialized in its place.'
                    .format(name, 'bare ' if bare else '')
                )
            log.debug(
                'Removing contents of %s to initialize %srepository in its '
                'place (force=True set in git.present state)',
                name, 'bare ' if bare else ''
            )
            try:
                if os.path.islink(name):
                    os.unlink(name)
                else:
                    salt.utils.files.rm_rf(name)
            except OSError as exc:
                return _fail(
                    ret,
                    'Unable to remove {0}: {1}'.format(name, exc)
                )
            else:
                ret['changes']['forced init'] = True
        elif os.listdir(name):
            return _fail(
                ret,
                'Target \'{0}\' exists, is non-empty, and is not a git '
                'repository. Set the \'force\' option to True to remove '
                'this directory\'s contents and proceed with initializing a '
                'repository'.format(name)
            )

    # Run test is set
    if __opts__['test']:
        ret['changes']['new'] = name
        return _neutral_test(
            ret,
            'New {0}repository would be created'.format(
                'bare ' if bare else ''
            )
        )

    __salt__['git.init'](cwd=name,
                         bare=bare,
                         template=template,
                         separate_git_dir=separate_git_dir,
                         shared=shared,
                         user=user,
                         password=password,
                         output_encoding=output_encoding)

    actions = [
        'Initialized {0}repository in {1}'.format(
            'bare ' if bare else '',
            name
        )
    ]
    if template:
        actions.append('Template directory set to {0}'.format(template))
    if separate_git_dir:
        actions.append('Gitdir set to {0}'.format(separate_git_dir))
    message = '. '.join(actions)
    if len(actions) > 1:
        message += '.'
    log.info(message)
    ret['changes']['new'] = name
    ret['comment'] = message
    return ret