Esempio n. 1
0
def perform_isolated_build(build_info, package_venv, dist_dir, setup_dir):
    with package_venv.new_action(
            "perform-isolated-build",
            package_venv.envconfig.envdir,
    ) as action:
        # need to start with an empty (but existing) source distribution folder
        if dist_dir.exists():
            dist_dir.remove(rec=1, ignore_errors=True)
        dist_dir.ensure_dir()

        result = package_venv._pcall(
            [
                package_venv.envconfig.envpython,
                BUILD_ISOLATED,
                str(dist_dir),
                build_info.backend_module,
                build_info.backend_object,
                os.path.pathsep.join(str(p) for p in build_info.backend_paths),
            ],
            returnout=True,
            action=action,
            cwd=setup_dir,
        )
        reporter.verbosity2(result)
        return dist_dir.join(result.split("\n")[-2])
Esempio n. 2
0
def tox_cleanup(session):
    # This hook can be called multiple times especially when using parallel mode
    if not is_running_on_actions():
        return
    verbosity2("disabling problem matcher")
    for owner in get_problem_matcher_owners():
        print("::remove-matcher owner={}::".format(owner))
Esempio n. 3
0
    def _pcall(
        self,
        args,
        cwd,
        venv=True,
        is_test_command=False,
        action=None,
        redirect=True,
        ignore_ret=False,
        returnout=False,
    ):
        # construct environment variables
        os.environ.pop("VIRTUALENV_PYTHON", None)
        env = self._get_os_environ(is_test_command=is_test_command)
        bin_dir = str(self.envconfig.envbindir)
        env["PATH"] = os.pathsep.join([bin_dir, os.environ["PATH"]])
        reporter.verbosity2("setting PATH={}".format(env["PATH"]))

        # get command
        args[0] = self.getcommandpath(args[0], venv, cwd)
        if sys.platform != "win32" and "TOX_LIMITED_SHEBANG" in os.environ:
            args = prepend_shebang_interpreter(args)

        cwd.ensure(dir=1)  # ensure the cwd exists
        return action.popen(args,
                            cwd=cwd,
                            env=env,
                            redirect=redirect,
                            ignore_ret=ignore_ret,
                            returnout=returnout)
Esempio n. 4
0
def tox_cleanup(session):
    for tox_env in session.venv_dict.values():
        if hasattr(tox_env, "package") and isinstance(tox_env.package, py.path.local):
            package = tox_env.package
            if package.exists():
                verbosity2("cleanup {}".format(package))
                package.remove()
                py.path.local(package.dirname).remove(ignore_errors=True)
Esempio n. 5
0
def make_sdist(config, session):
    setup = config.setupdir.join("setup.py")
    pyproject = config.setupdir.join("pyproject.toml")
    setup_check = setup.check()
    if not setup_check and not pyproject.check():
        reporter.error(
            "No pyproject.toml or setup.py file found. The expected locations are:\n"
            "  {pyproject} or {setup}\n"
            "You can\n"
            "  1. Create one:\n"
            "     https://tox.readthedocs.io/en/latest/example/package.html\n"
            "  2. Configure tox to avoid running sdist:\n"
            "     https://tox.readthedocs.io/en/latest/example/general.html\n"
            "  3. Configure tox to use an isolated_build".format(
                pyproject=pyproject, setup=setup), )
        raise SystemExit(1)
    if not setup_check:
        reporter.error(
            "pyproject.toml file found.\n"
            "To use a PEP 517 build-backend you are required to "
            "configure tox to use an isolated_build:\n"
            "https://tox.readthedocs.io/en/latest/example/package.html\n", )
        raise SystemExit(1)
    with session.newaction("GLOB", "packaging") as action:
        action.setactivity("sdist-make", setup)
        ensure_empty_dir(config.distdir)
        build_log = action.popen(
            [
                sys.executable,
                setup,
                "sdist",
                "--formats=zip",
                "--dist-dir",
                config.distdir,
            ],
            cwd=config.setupdir,
            returnout=True,
        )
        reporter.verbosity2(build_log)
        try:
            return config.distdir.listdir()[0]
        except py.error.ENOENT:
            # check if empty or comment only
            data = []
            with open(str(setup)) as fp:
                for line in fp:
                    if line and line[0] == "#":
                        continue
                    data.append(line)
            if not "".join(data).strip():
                reporter.error("setup.py is empty")
                raise SystemExit(1)
            reporter.error(
                "No dist directory found. Please check setup.py, e.g with:\n"
                "     python setup.py sdist", )
            raise SystemExit(1)
Esempio n. 6
0
 def get_executable(self, envconfig):
     """return path object to the executable for the given
     name (e.g. python2.7, python3.6, python etc.)
     if name is already an existing path, return name.
     If an interpreter cannot be found, return None.
     """
     try:
         return self.name2executable[envconfig.envname]
     except KeyError:
         exe = self.hook.tox_get_python_executable(envconfig=envconfig)
         reporter.verbosity2("{} uses {}".format(envconfig.envname, exe))
         self.name2executable[envconfig.envname] = exe
         return exe
Esempio n. 7
0
def check_with_path(candidates, spec):
    for path in candidates:
        base = path
        if not os.path.isabs(path):
            path = py.path.local.sysfind(path)
            reporter.verbosity2(("path found", path))
        if path is not None:
            if os.path.exists(str(path)):
                cur_spec = exe_spec(path, base)
                if cur_spec is not None and cur_spec.satisfies(spec):
                    return cur_spec.path
            else:
                reporter.verbosity2("no such file {}".format(path))
Esempio n. 8
0
    def _pcall(
        self,
        args,
        cwd,
        venv=True,
        is_test_command=False,
        action=None,
        redirect=True,
        ignore_ret=False,
        returnout=False,
        env=None,
        capture_err=True,
    ):
        if env is None:
            env = self._get_os_environ(is_test_command=is_test_command)

        # construct environment variables
        env.pop("VIRTUALENV_PYTHON", None)
        bin_dir = str(self.envconfig.envbindir)
        path = self.envconfig.setenv.get("PATH") or os.environ["PATH"]
        env["PATH"] = os.pathsep.join([bin_dir, path])
        reporter.verbosity2("setting PATH={}".format(env["PATH"]))

        # get command
        try:
            args[0] = self.getcommandpath(args[0], venv, cwd)
        except tox.exception.InvocationError:
            if ignore_ret:
                self.status = getattr(self, "status", 0)
                msg = "command not found but explicitly ignored"
                reporter.warning("{}\ncmd: {}".format(msg, args[0]))
                return ""  # in case it's returnout
            else:
                raise

        if sys.platform != "win32" and "TOX_LIMITED_SHEBANG" in os.environ:
            args = prepend_shebang_interpreter(args)

        cwd.ensure(dir=1)  # ensure the cwd exists
        return action.popen(
            args,
            cwd=cwd,
            env=env,
            redirect=redirect,
            ignore_ret=ignore_ret,
            returnout=returnout,
            report_fail=not is_test_command,
            capture_err=capture_err,
        )
Esempio n. 9
0
def get_factors(gh_actions_config, versions):
    # type: (Dict[str, Dict[str, Any]], Iterable[str]) -> List[str]
    """Get a list of factors"""
    factors = []  # type: List[List[str]]
    for version in versions:
        if version in gh_actions_config["python"]:
            verbosity2("got factors for Python version: {}".format(version))
            factors.append(gh_actions_config["python"][version])
            break  # Shoudn't check remaining versions
    for env, env_config in gh_actions_config.get("env", {}).items():
        if env in os.environ:
            env_value = os.environ[env]
            if env_value in env_config:
                factors.append(env_config[env_value])
    return [x for x in map(lambda f: "-".join(f), product(*factors)) if x]
Esempio n. 10
0
def exe_spec(python_exe, base):
    if not isinstance(python_exe, str):
        python_exe = str(python_exe)
    with _SPECK_LOCK[python_exe]:
        if python_exe not in _SPECS:
            info = get_python_info(python_exe)
            if info is not None:
                found = PythonSpec(
                    "pypy" if info["implementation"] == "PyPy" else "python",
                    info["version_info"][0],
                    info["version_info"][1],
                    64 if info["is_64"] else 32,
                    info["executable"],
                )
                reporter.verbosity2("{} ({}) is {}".format(base, python_exe, info))
            else:
                found = None
            _SPECS[python_exe] = found
    return _SPECS[python_exe]
Esempio n. 11
0
def make_sdist(config, session):
    setup = config.setupdir.join("setup.py")
    if not setup.check():
        reporter.error(
            "No setup.py file found. The expected location is:\n"
            "  {}\n"
            "You can\n"
            "  1. Create one:\n"
            "     https://packaging.python.org/tutorials/distributing-packages/#setup-py\n"
            "  2. Configure tox to avoid running sdist:\n"
            "     https://tox.readthedocs.io/en/latest/example/general.html"
            "#avoiding-expensive-sdist".format(setup)
        )
        raise SystemExit(1)
    with session.newaction("GLOB", "packaging") as action:
        action.setactivity("sdist-make", setup)
        ensure_empty_dir(config.distdir)
        build_log = action.popen(
            [sys.executable, setup, "sdist", "--formats=zip", "--dist-dir", config.distdir],
            cwd=config.setupdir,
            returnout=True,
        )
        reporter.verbosity2(build_log)
        try:
            return config.distdir.listdir()[0]
        except py.error.ENOENT:
            # check if empty or comment only
            data = []
            with open(str(setup)) as fp:
                for line in fp:
                    if line and line[0] == "#":
                        continue
                    data.append(line)
            if not "".join(data).strip():
                reporter.error("setup.py is empty")
                raise SystemExit(1)
            reporter.error(
                "No dist directory found. Please check setup.py, e.g with:\n"
                "     python setup.py sdist"
            )
            raise SystemExit(1)
Esempio n. 12
0
def tox_configure(config):
    # type: (Config) -> None
    # Only run if we're enabled
    toxinidir = str(config.toxinidir)
    cfg = get_config(toxinidir)
    if "wikimedia" not in cfg:
        verbosity2("[wikimedia] tox-wikimedia is not enabled, skipping")
        return

    verbosity2("[wikimedia] tox-wikimedia is enabled")
    for envname, econfig in config.envconfigs.items():
        for factor in econfig.factors:
            # factors are py35, flake8, pytest, etc.
            try:
                fconfig = TOOLS[factor]  # type: dict
            except KeyError:
                continue

            for dep in fconfig["deps"]:
                # Check to make sure the dep is not already
                # specific (e.g. to specify a constraint)
                for cdep in econfig.deps:
                    if dep in cdep.name:
                        break
                else:
                    econfig.deps.append(DepConfig(dep))
                    verbosity2("[wikimedia] {}: Adding dep on {}".format(
                        envname, dep))
            if fconfig.get("requirements"):
                for txtdep in [
                        "requirements.txt",
                        "test-requirements.txt",
                ]:
                    if os.path.exists(os.path.join(toxinidir, txtdep)):
                        verbosity2("[wikimedia] {}: Adding dep on {}".format(
                            envname, txtdep))
                        econfig.deps.append(DepConfig("-r{}".format(txtdep)))
            if econfig.commands:
                verbosity2("[wikimedia] {}: overridden commands: {}".format(
                    envname, repr(econfig.commands)))
            if not econfig.commands:
                # If there's no command, then set one
                cmd = []
                for part in fconfig["commands"]:
                    if "{" in part:
                        # Needs formatting
                        part = part.format(**cfg["wikimedia"])
                    cmd.append(part)
                econfig.commands.append(cmd)
                verbosity2("[wikimedia] {}: Setting command to {}".format(
                    envname, str(cmd)))
            if not econfig.description:
                econfig.description = fconfig["description"]
Esempio n. 13
0
def tox_configure(config):
    # type: (Config) -> None
    verbosity1("running tox-gh-actions")
    if not is_running_on_actions():
        verbosity1(
            "tox-gh-actions won't override envlist "
            "because tox is not running in GitHub Actions"
        )
        return
    elif is_env_specified(config):
        verbosity1(
            "tox-gh-actions won't override envlist because "
            "envlist is explicitly given via TOXENV or -e option"
        )
        return

    verbosity2("original envconfigs: {}".format(list(config.envconfigs.keys())))
    verbosity2("original envlist_default: {}".format(config.envlist_default))
    verbosity2("original envlist: {}".format(config.envlist))

    versions = get_python_version_keys()
    verbosity2("Python versions: {}".format(versions))

    gh_actions_config = parse_config(config._cfg.sections)
    verbosity2("tox-gh-actions config: {}".format(gh_actions_config))

    factors = get_factors(gh_actions_config, versions)
    verbosity2("using the following factors to decide envlist: {}".format(factors))

    envlist = get_envlist_from_factors(config.envlist, factors)
    config.envlist_default = config.envlist = envlist
    verbosity1("overriding envlist with: {}".format(envlist))

    if is_running_on_container():
        verbosity2(
            "not enabling problem matcher as tox seems to be running on a container"
        )
        # Trying to add a problem matcher from a container without proper host mount can
        # cause an error like the following:
        # Unable to process command '::add-matcher::/.../matcher.json' successfully.
    else:
        verbosity2("enabling problem matcher")
        print("::add-matcher::" + get_problem_matcher_file_path())

    if not is_log_grouping_enabled(config):
        verbosity2(
            "disabling log line grouping on GitHub Actions based on the configuration"
        )
Esempio n. 14
0
def tox_configure(config):
    # type: (Config) -> None
    verbosity1("running tox-gh-actions")
    if not is_running_on_actions():
        verbosity1(
            "tox-gh-actions won't override envlist "
            "because tox is not running in GitHub Actions"
        )
        return
    elif is_env_specified(config):
        verbosity1(
            "tox-gh-actions won't override envlist because "
            "envlist is explicitly given via TOXENV or -e option"
        )
        return

    verbosity2("original envconfigs: {}".format(list(config.envconfigs.keys())))
    verbosity2("original envlist_default: {}".format(config.envlist_default))
    verbosity2("original envlist: {}".format(config.envlist))

    version = get_python_version()
    verbosity2("Python version: {}".format(version))

    gh_actions_config = parse_config(config._cfg.sections)
    verbosity2("tox-gh-actions config: {}".format(gh_actions_config))

    factors = get_factors(gh_actions_config, version)
    verbosity2("using the following factors to decide envlist: {}".format(factors))

    envlist = get_envlist_from_factors(config.envlist, factors)
    config.envlist_default = config.envlist = envlist
    verbosity1("overriding envlist with: {}".format(envlist))