Fix ansible-test handling of egg-info.
Resolves https://github.com/ansible/ansible/issues/67990
This commit is contained in:
parent
133a29acb4
commit
d092356fc5
3 changed files with 56 additions and 51 deletions
11
changelogs/fragments/ansible-test-egg-info-handling.yml
Normal file
11
changelogs/fragments/ansible-test-egg-info-handling.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
bugfixes:
|
||||||
|
- ansible-test - Running tests using an installed version of ``ansible-test`` against one Python version from another no longer fails
|
||||||
|
due to a missing ``egg-info`` directory.
|
||||||
|
This could occur when testing plugins which import ``pkg_resources``.
|
||||||
|
- ansible-test - Running tests using an installed version of ``ansible-test`` no longer generates an error attempting to create an ``egg-info`` directory
|
||||||
|
when an existing one is not found in the expected location.
|
||||||
|
This could occur if the existing ``egg-info`` directory included a Python version specifier in the name.
|
||||||
|
minor_changes:
|
||||||
|
- ansible-test - Generation of an ``egg-info`` directory, if needed, is now done after installing test dependencies and before running tests.
|
||||||
|
When running from an installed version of ``ansible-test`` a temporary directory is used to avoid permissions issues.
|
||||||
|
Previously it was done before installing test dependencies and adjacent to the installed directory.
|
|
@ -11,6 +11,10 @@ from .constants import (
|
||||||
SOFT_RLIMIT_NOFILE,
|
SOFT_RLIMIT_NOFILE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from .io import (
|
||||||
|
write_text_file,
|
||||||
|
)
|
||||||
|
|
||||||
from .util import (
|
from .util import (
|
||||||
common_environment,
|
common_environment,
|
||||||
display,
|
display,
|
||||||
|
@ -20,6 +24,7 @@ from .util import (
|
||||||
ANSIBLE_TEST_DATA_ROOT,
|
ANSIBLE_TEST_DATA_ROOT,
|
||||||
ANSIBLE_BIN_PATH,
|
ANSIBLE_BIN_PATH,
|
||||||
ANSIBLE_SOURCE_ROOT,
|
ANSIBLE_SOURCE_ROOT,
|
||||||
|
get_ansible_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .util_common import (
|
from .util_common import (
|
||||||
|
@ -75,7 +80,7 @@ def ansible_environment(args, color=True, ansible_config=None):
|
||||||
ANSIBLE_LIBRARY='/dev/null',
|
ANSIBLE_LIBRARY='/dev/null',
|
||||||
ANSIBLE_DEVEL_WARNING='false', # Don't show warnings that CI is running devel
|
ANSIBLE_DEVEL_WARNING='false', # Don't show warnings that CI is running devel
|
||||||
ANSIBLE_CONTROLLER_PYTHON_WARNING='false', # Don't show warnings in CI for old controller Python
|
ANSIBLE_CONTROLLER_PYTHON_WARNING='false', # Don't show warnings in CI for old controller Python
|
||||||
PYTHONPATH=get_ansible_python_path(),
|
PYTHONPATH=get_ansible_python_path(args),
|
||||||
PAGER='/bin/cat',
|
PAGER='/bin/cat',
|
||||||
PATH=path,
|
PATH=path,
|
||||||
# give TQM worker processes time to report code coverage results
|
# give TQM worker processes time to report code coverage results
|
||||||
|
@ -171,28 +176,59 @@ def configure_plugin_paths(args): # type: (CommonConfig) -> t.Dict[str, str]
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
|
||||||
def get_ansible_python_path(): # type: () -> str
|
def get_ansible_python_path(args): # type: (CommonConfig) -> str
|
||||||
"""
|
"""
|
||||||
Return a directory usable for PYTHONPATH, containing only the ansible package.
|
Return a directory usable for PYTHONPATH, containing only the ansible package.
|
||||||
If a temporary directory is required, it will be cached for the lifetime of the process and cleaned up at exit.
|
If a temporary directory is required, it will be cached for the lifetime of the process and cleaned up at exit.
|
||||||
"""
|
"""
|
||||||
if ANSIBLE_SOURCE_ROOT:
|
|
||||||
# when running from source there is no need for a temporary directory to isolate the ansible package
|
|
||||||
return os.path.dirname(ANSIBLE_LIB_ROOT)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return get_ansible_python_path.python_path
|
return get_ansible_python_path.python_path
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
python_path = create_temp_dir(prefix='ansible-test-')
|
if ANSIBLE_SOURCE_ROOT:
|
||||||
|
# when running from source there is no need for a temporary directory to isolate the ansible package
|
||||||
|
python_path = os.path.dirname(ANSIBLE_LIB_ROOT)
|
||||||
|
else:
|
||||||
|
# when not running from source the installed directory is unsafe to add to PYTHONPATH
|
||||||
|
# doing so would expose many unwanted packages on sys.path
|
||||||
|
# instead a temporary directory is created which contains only ansible using a symlink
|
||||||
|
python_path = create_temp_dir(prefix='ansible-test-')
|
||||||
|
|
||||||
|
os.symlink(ANSIBLE_LIB_ROOT, os.path.join(python_path, 'ansible'))
|
||||||
|
|
||||||
|
if not args.explain:
|
||||||
|
generate_egg_info(python_path)
|
||||||
|
|
||||||
get_ansible_python_path.python_path = python_path
|
get_ansible_python_path.python_path = python_path
|
||||||
|
|
||||||
os.symlink(ANSIBLE_LIB_ROOT, os.path.join(python_path, 'ansible'))
|
|
||||||
|
|
||||||
return python_path
|
return python_path
|
||||||
|
|
||||||
|
|
||||||
|
def generate_egg_info(path): # type: (str) -> None
|
||||||
|
"""Generate an egg-info in the specified base directory."""
|
||||||
|
# minimal PKG-INFO stub following the format defined in PEP 241
|
||||||
|
# required for older setuptools versions to avoid a traceback when importing pkg_resources from packages like cryptography
|
||||||
|
# newer setuptools versions are happy with an empty directory
|
||||||
|
# including a stub here means we don't need to locate the existing file or have setup.py generate it when running from source
|
||||||
|
pkg_info = '''
|
||||||
|
Metadata-Version: 1.0
|
||||||
|
Name: ansible
|
||||||
|
Version: %s
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Summary: Radically simple IT automation
|
||||||
|
Author-email: info@ansible.com
|
||||||
|
License: GPLv3+
|
||||||
|
''' % get_ansible_version()
|
||||||
|
|
||||||
|
pkg_info_path = os.path.join(path, 'ansible_core.egg-info', 'PKG-INFO')
|
||||||
|
|
||||||
|
if os.path.exists(pkg_info_path):
|
||||||
|
return
|
||||||
|
|
||||||
|
write_text_file(pkg_info_path, pkg_info.lstrip(), create_directories=True)
|
||||||
|
|
||||||
|
|
||||||
def check_pyyaml(args, version, required=True, quiet=False):
|
def check_pyyaml(args, version, required=True, quiet=False):
|
||||||
"""
|
"""
|
||||||
:type args: EnvironmentConfig
|
:type args: EnvironmentConfig
|
||||||
|
|
|
@ -298,8 +298,6 @@ def install_command_requirements(args, python_version=None, context=None, enable
|
||||||
if args.raw:
|
if args.raw:
|
||||||
return
|
return
|
||||||
|
|
||||||
generate_egg_info(args)
|
|
||||||
|
|
||||||
if not args.requirements:
|
if not args.requirements:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -434,46 +432,6 @@ def pip_list(args, pip):
|
||||||
return stdout
|
return stdout
|
||||||
|
|
||||||
|
|
||||||
def generate_egg_info(args):
|
|
||||||
"""
|
|
||||||
:type args: EnvironmentConfig
|
|
||||||
"""
|
|
||||||
if args.explain:
|
|
||||||
return
|
|
||||||
|
|
||||||
ansible_version = get_ansible_version()
|
|
||||||
|
|
||||||
# inclusion of the version number in the path is optional
|
|
||||||
# see: https://setuptools.readthedocs.io/en/latest/formats.html#filename-embedded-metadata
|
|
||||||
egg_info_path = ANSIBLE_LIB_ROOT + '_core-%s.egg-info' % ansible_version
|
|
||||||
|
|
||||||
if os.path.exists(egg_info_path):
|
|
||||||
return
|
|
||||||
|
|
||||||
egg_info_path = ANSIBLE_LIB_ROOT + '_core.egg-info'
|
|
||||||
|
|
||||||
if os.path.exists(egg_info_path):
|
|
||||||
return
|
|
||||||
|
|
||||||
# minimal PKG-INFO stub following the format defined in PEP 241
|
|
||||||
# required for older setuptools versions to avoid a traceback when importing pkg_resources from packages like cryptography
|
|
||||||
# newer setuptools versions are happy with an empty directory
|
|
||||||
# including a stub here means we don't need to locate the existing file or have setup.py generate it when running from source
|
|
||||||
pkg_info = '''
|
|
||||||
Metadata-Version: 1.0
|
|
||||||
Name: ansible
|
|
||||||
Version: %s
|
|
||||||
Platform: UNKNOWN
|
|
||||||
Summary: Radically simple IT automation
|
|
||||||
Author-email: info@ansible.com
|
|
||||||
License: GPLv3+
|
|
||||||
''' % get_ansible_version()
|
|
||||||
|
|
||||||
pkg_info_path = os.path.join(egg_info_path, 'PKG-INFO')
|
|
||||||
|
|
||||||
write_text_file(pkg_info_path, pkg_info.lstrip(), create_directories=True)
|
|
||||||
|
|
||||||
|
|
||||||
def generate_pip_install(pip, command, packages=None, constraints=None, use_constraints=True, context=None):
|
def generate_pip_install(pip, command, packages=None, constraints=None, use_constraints=True, context=None):
|
||||||
"""
|
"""
|
||||||
:type pip: list[str]
|
:type pip: list[str]
|
||||||
|
|
Loading…
Reference in a new issue