import os
import subprocess as sp
import sys

import pytest

PACKAGE_DIR = os.path.dirname(__file__)


def run_cmd(cmd, args, path=None, raise_error=True):
    """
    Runs a shell command with the given argument list.  Changes directory to
    ``path`` if given, otherwise runs the command in the current directory.

    Returns a 3-tuple of (stdout, stderr, exit code)

    If ``raise_error=True`` raise an exception on non-zero exit codes.
    """

    if path is not None:
        # Transparently support py.path objects
        path = str(path)

    p = sp.Popen([cmd] + list(args), stdout=sp.PIPE, stderr=sp.PIPE,
                 cwd=path)
    streams = tuple(s.decode('latin1').strip() for s in p.communicate())
    return_code = p.returncode

    if raise_error and return_code != 0:
        raise RuntimeError(
            "The command `{0}` with args {1!r} exited with code {2}.\n"
            "Stdout:\n\n{3}\n\nStderr:\n\n{4}".format(
                cmd, list(args), return_code, streams[0], streams[1]))

    return streams + (return_code,)


@pytest.fixture(scope='function', autouse=True)
def reset_setup_helpers(request):
    """
    Saves and restores the global state of the astropy_helpers.setup_helpers
    module between tests.
    """

    mod = __import__('astropy_helpers.setup_helpers', fromlist=[''])

    old_state = mod._module_state.copy()

    def finalizer(old_state=old_state):
        mod = sys.modules.get('astropy_helpers.setup_helpers')
        if mod is not None:
            mod._module_state.update(old_state)

    request.addfinalizer(finalizer)


@pytest.fixture(scope='function', autouse=True)
def reset_distutils_log():
    """
    This is a setup/teardown fixture that ensures the log-level of the
    distutils log is always set to a default of WARN, since different
    settings could affect tests that check the contents of stdout.
    """

    from distutils import log
    log.set_threshold(log.WARN)


TEST_PACKAGE_SETUP_PY = """\
#!/usr/bin/env python

from setuptools import setup

NAME = 'astropy-helpers-test'
VERSION = {version!r}

setup(name=NAME, version=VERSION,
      packages=['_astropy_helpers_test_'],
      zip_safe=False)
"""


@pytest.fixture
def testpackage(tmpdir, version='0.1'):
    """
    This fixture creates a simplified package called _astropy_helpers_test_
    used primarily for testing ah_boostrap, but without using the
    astropy_helpers package directly and getting it confused with the
    astropy_helpers package already under test.
    """

    source = tmpdir.mkdir('testpkg')

    with source.as_cwd():
        source.mkdir('_astropy_helpers_test_')
        init = source.join('_astropy_helpers_test_', '__init__.py')
        init.write('__version__ = {0!r}'.format(version))
        setup_py = TEST_PACKAGE_SETUP_PY.format(version=version)
        source.join('setup.py').write(setup_py)

        # Make the new test package into a git repo
        run_cmd('git', ['init'])
        run_cmd('git', ['add', '--all'])
        run_cmd('git', ['commit', '-m', 'test package'])

    return source


def cleanup_import(package_name):
    """Remove all references to package_name from sys.modules"""

    for k in list(sys.modules):
        if not isinstance(k, str):
            # Some things will actually do this =_=
            continue
        elif k.startswith('astropy_helpers.tests'):
            # Don't delete imported test modules or else the tests will break,
            # badly
            continue
        if k == package_name or k.startswith(package_name + '.'):
            del sys.modules[k]

@@ -39,16 +39,48 @@
 rt sys%0A%0A
+from setuptools import sandbox%0A%0A
 import p
@@ -1979,16 +1979,689 @@
 WARN)%0A%0A%0A
+@pytest.fixture(scope='module', autouse=True)%0Adef fix_hide_setuptools():%0A    %22%22%22%0A    Workaround for https://github.com/astropy/astropy-helpers/issues/124%0A%0A    In setuptools 10.0 run_setup was changed in such a way that it sweeps%0A    away the existing setuptools import before running the setup script.  In%0A    principle this is nice, but in the practice of testing astropy_helpers%0A    this is problematic since we're trying to test code that has already been%0A    imported during the testing process, and which relies on the setuptools%0A    module that was already in use.%0A    %22%22%22%0A%0A    if hasattr(sandbox, 'hide_setuptools'):%0A        sandbox.hide_setuptools = lambda: None%0A%0A%0A
 TEST_PAC

Work around the new 'hide_setuptools' feature used by 'run_setup' by simply monkey-patching it to not do anything. For now this completely solves the problem. I think this is fine since it doesn't break any particular expectations, it just disables something which itself is a workaround for a feature setuptools needs for itself, but that isn't relevant outside the context of setuptools self-upgrading (it's not an entirely bad feature for testing either since it resets any of setuptools' global variables, but it breaks the specific tests for astropy_helpers)