Bug Report
---------------

**SUMMARY**

When a file in a role has a tilde (~) in the name, the ansible-galaxy pull fails.

**COMPONENT NAME**

lib/ansible/cli/galaxy.py

**ANSIBLE VERSION**

~~~
ansible-galaxy 2.11.0.dev0
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/ansible/lib/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/ansible/bin/ansible-galaxy
  python version = 3.6.9 (default, Nov 11 2019, 11:24:16) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
~~~

**STEPS TO REPRODUCE**

When filename does not contain a tilde (~):

```
[root@0b37f81e0ac0 galaxy]# ansible-galaxy install -r requirements.yml -vvv
ansible-galaxy 2.9.7
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible-galaxy
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
Using /etc/ansible/ansible.cfg as config file
Reading requirement file at 'requirements.yml'
found role {'scm': 'git', 'src': 'http://git.example.com/ansible/tester.git', 'version': '', 'name': 'tester'} in yaml file
Processing role tester 
archiving ['/usr/bin/git', 'archive', '--prefix=tester/', u'--output=/root/.ansible/tmp/ansible-local-8920yXDh66/tmp7Myv3l.tar', 'HEAD']
- extracting tester to /root/.ansible/roles/tester
- tester was installed successfully
[WARNING]: Meta file /root/.ansible/roles/tester is empty. Skipping dependencies.
```

When filename contains a tilde (~):

```
ansible-galaxy 2.9.7
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible-galaxy
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
Using /etc/ansible/ansible.cfg as config file
Reading requirement file at 'requirements.yml'
found role {'scm': 'git', 'src': 'http://git.example.com/ansible/tester.git', 'version': '', 'name': 'tester'} in yaml file
Processing role tester 
archiving ['/usr/bin/git', 'archive', '--prefix=tester/', u'--output=/root/.ansible/tmp/ansible-local-8984bfuVM3/tmp_wXxbO.tar', 'HEAD']
- extracting tester to /root/.ansible/roles/tester
ERROR! Unexpected Exception, this is probably a bug: [Errno 21] Is a directory: u'/root/.ansible/roles/tester/files'
the full traceback was:

Traceback (most recent call last):
  File "/usr/bin/ansible-galaxy", line 123, in <module>
    exit_code = cli.run()
  File "/usr/lib/python2.7/site-packages/ansible/cli/galaxy.py", line 375, in run
    context.CLIARGS['func']()
  File "/usr/lib/python2.7/site-packages/ansible/cli/galaxy.py", line 891, in execute_install
    installed = role.install()
  File "/usr/lib/python2.7/site-packages/ansible/galaxy/role.py", line 330, in install
    role_tar_file.extract(member, self.path)
  File "/usr/lib64/python2.7/tarfile.py", line 2084, in extract
    self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
  File "/usr/lib64/python2.7/tarfile.py", line 2160, in _extract_member
    self.makefile(tarinfo, targetpath)
  File "/usr/lib64/python2.7/tarfile.py", line 2200, in makefile
    with bltn_open(targetpath, "wb") as target:
IOError: [Errno 21] Is a directory: u'/root/.ansible/roles/tester/files'
```

**EXPECTED RESULTS**

I would think roles should be able to accommodate tildes in the filenames.

See: ansible/galaxy#704
See: https://github.com/ansible/ansible/issues/71624

Here's the structure of a local Git clone which causes the problem:
~~~
(galaxy) machine@machine1:~/Downloads/galaxy/arole$ tree 
.
├── files
│   ├── XXX-account.sh
│   └── group-XXXXXX~XXX-XXXXX-XX
├── meta
│   └── main.yml
└── README.md

2 directories, 4 files
~~~

Here's the ansible-galaxy output when a ~ is present in a dependency filename:

~~~
[WARNING]: You are running the development version of Ansible. You should only run Ansible from "devel" if you are modifying the Ansible engine, or trying out features under development. This is a rapidly
changing source of code and can become unstable at any point.
ansible-galaxy 2.11.0.dev0
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/ansible/lib/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/ansible/bin/ansible-galaxy
  python version = 3.6.9 (default, Nov 11 2019, 11:24:16) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
Using /etc/ansible/ansible.cfg as config file
Initial connection to galaxy_server: https://galaxy.ansible.com
Opened /root/.ansible/galaxy_token
Calling Galaxy at https://galaxy.ansible.com/api/
Found API version 'v1, v2' with Galaxy server default (https://galaxy.ansible.com/api/)
Starting galaxy role install process
Processing role arole 
archiving ['/usr/bin/git', 'archive', '--prefix=arole/', '--output=/root/.ansible/tmp/ansible-local-912do8enx7f/tmpp4ii2gwc.tar', 'HEAD']
- extracting arole to /root/.ansible/roles/arole
[WARNING]: - arole was NOT installed successfully: Could not update files in /root/.ansible/roles/arole: [Errno 21] Is a directory: '/root/.ansible/roles/arole/files'
ERROR! - you can use --ignore-errors to skip failed roles and finish processing the list.
~~~

Here's the ansible-galaxy output when a ~ is not in a dependency filename:

~~~
[WARNING]: You are running the development version of Ansible. You should only run Ansible from "devel" if you are modifying the Ansible engine, or trying out features under development. This is a rapidly
changing source of code and can become unstable at any point.
ansible-galaxy 2.11.0.dev0
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/ansible/lib/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/ansible/bin/ansible-galaxy
  python version = 3.6.9 (default, Nov 11 2019, 11:24:16) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
Using /etc/ansible/ansible.cfg as config file
Initial connection to galaxy_server: https://galaxy.ansible.com
Opened /root/.ansible/galaxy_token
Calling Galaxy at https://galaxy.ansible.com/api/
Found API version 'v1, v2' with Galaxy server default (https://galaxy.ansible.com/api/)
Starting galaxy role install process
Processing role arole 
archiving ['/usr/bin/git', 'archive', '--prefix=arole/', '--output=/root/.ansible/tmp/ansible-local-927j9gf3cer/tmpsrn81ct7.tar', 'HEAD']
- extracting arole to /root/.ansible/roles/arole
- arole was installed successfully
[WARNING]: Meta file /root/.ansible/roles/arole is empty. Skipping dependencies.
~~~
#
#
#
#
#
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import errno
import datetime
import os
import tarfile
import tempfile
import yaml
from distutils.version import LooseVersion
from shutil import rmtree
from ansible import context
from ansible.errors import AnsibleError
from ansible.galaxy.user_agent import user_agent
from ansible.module_utils._text import to_native, to_text
from ansible.module_utils.urls import open_url
from ansible.playbook.role.requirement import RoleRequirement
from ansible.utils.display import Display
display = Display()
class GalaxyRole(object):