def test_executable(temp_folder): with runez.CaptureOutput(dryrun=True) as logged: assert runez.make_executable("some-file") == 1 assert "Would make some-file executable" in logged assert runez.touch("some-file") == 1 assert runez.make_executable("some-file") == 1 assert runez.is_executable("some-file") assert runez.make_executable("some-file") == 0 assert runez.delete("some-file") == 1 assert not runez.is_executable("some-file") with runez.CaptureOutput() as logged: assert runez.make_executable("/dev/null/some-file", fatal=False) == -1 assert "does not exist, can't make it executable" in logged
def check_install_from_pypi(cli, delivery, package, simulate_version=None): cli.run("--debug", "-d%s" % delivery, "install", package) assert cli.succeeded assert cli.match("Installed %s" % package) assert runez.is_executable(package) m = TrackedManifest.from_file(dot_meta("%s/.manifest.json" % package)) assert str(m) assert m.entrypoints[package] assert m.install_info.args == runez.quoted(cli.args) assert m.install_info.timestamp assert m.install_info.vpickley == __version__ assert m.settings.delivery == delivery assert m.settings.python assert m.version r = runez.run(package, "--version") assert r.succeeded cli.expect_success("--debug auto-upgrade %s" % package, "Skipping auto-upgrade, checked recently") cli.expect_success("install %s" % package, "is already installed") cli.expect_success("check", "is installed") cli.expect_success("list", package) cli.expect_success("upgrade", "is already up-to-date") if simulate_version: m.version = simulate_version runez.save_json(m.to_dict(), dot_meta("%s/.manifest.json" % package)) cli.expect_success( "check", "v%s installed, can be upgraded to" % simulate_version)
def get_program_path(path=None): if path is None: path = runez.resolved_path(sys.argv[0]) if path.endswith(".py") or path.endswith(".pyc"): packaged = runez.SYS_INFO.venv_bin_path(PICKLEY) if runez.is_executable(packaged): path = packaged # Convenience when running from debugger return path
def _set_executable(self, path): path = runez.resolved_path(path) if runez.is_executable(path): self.executable = path if not self.major or not self.minor: result = runez.run(self.executable, "--version", dryrun=False, fatal=False) if result.succeeded: m = RE_PYTHON_LOOSE.match(result.full_output) if m: self.major = m.group(3) self.minor = m.group(4)
def test_package_venv(cli): # Verify that "debian mode" works as expected, with -droot/tmp <-> /tmp runez.delete("/tmp/pickley") cli.run("package", cli.project_folder, "-droot/tmp", "--no-compile", "--sanity-check=--version", "-sroot:root/usr/local/bin") assert cli.succeeded assert "--version" in cli.logged assert runez.is_executable("/tmp/pickley/bin/pickley") r = runez.run("/tmp/pickley/bin/pickley", "--version") assert r.succeeded runez.delete("/tmp/pickley")
def is_venv_exe(self, path): """ Args: path (str): Path to file to examine Returns: (bool): True if 'path' points to a python executable part of this venv """ if runez.is_executable(path): for line in runez.readlines(path, first=1): if line.startswith("#!"): if path.startswith(self.folder): return True
def test_package(cli): pickley = system.SETTINGS.base.full_path("dist", "pickley", "bin", "pickley") expected_version = system.run_python(os.path.join(PROJECT, "setup.py"), "--version") # Package pickley as venv cli.expect_success(["package", "-d", "dist", PROJECT], "Packaged %s successfully" % short(PROJECT)) # Verify that it packaged OK, and is relocatable assert runez.is_executable(pickley) assert run_program(pickley, "--version") == expected_version assert runez.first_line(pickley).startswith("#!/usr/bin/env python")
def test_package(cli): result = system.run_python(os.path.join(PROJECT, "setup.py"), "--version") assert result.succeeded and result.output expected_version = result.output # Package pickley as venv cli.expect_success(["package", "-d", "dist", PROJECT], "Packaged %s successfully" % short(PROJECT)) # Verify that it packaged OK, and is relocatable pickley = os.path.abspath("dist/pickley/bin/pickley") assert runez.is_executable(pickley) assert run_program(pickley, "--version") == runez.program.RunResult( expected_version, "", 0)
def test_executable(temp_folder): with runez.CaptureOutput(dryrun=True) as logged: assert runez.make_executable("some-file") == 1 assert "Would make some-file executable" in logged.pop() assert runez.make_executable("some-file", logger=False) == 1 assert not logged with runez.CaptureOutput() as logged: assert runez.touch("some-file") == 1 assert "Touched some-file" in logged.pop() assert runez.delete("some-file") == 1 assert "Deleted some-file" in logged.pop() assert runez.touch("some-file", logger=logging.debug) == 1 assert "Touched some-file" in logged.pop() assert runez.make_executable("some-file", logger=logging.debug) == 1 assert "Made 'some-file' executable" in logged.pop() assert runez.is_executable("some-file") assert runez.make_executable("some-file") == 0 assert not logged assert runez.touch("some-file", logger=False) == 1 assert runez.delete("some-file", logger=False) == 1 assert not runez.is_executable("some-file") assert not logged assert runez.make_executable("/dev/null/some-file", fatal=False) == -1 assert "does not exist, can't make it executable" in logged.pop() assert runez.make_executable("/dev/null/some-file", fatal=False, logger=None) == -1 # Don't log anything assert not logged assert runez.make_executable("/dev/null/some-file", fatal=False, logger=False) == -1 # Log errors only assert "does not exist, can't make it executable" in logged.pop()
def _set_executable(self, path): path = runez.resolved_path(path) if runez.is_executable(path): self.executable = path if not self.major or not self.minor: output = runez.run(self.executable, "--version", dryrun=False, fatal=None, include_error=True, logger=None) if output: m = RE_PYTHON_LOOSE.match(output) if m: self.major = m.group(3) self.minor = m.group(4)
def _installed_module(self, package_name, version=None): """ :param str package_name: Pypi module to install in venv, if not already installed :param str|None version: Version (default: latest) """ program = os.path.join(self.bin, package_name) current = self.frozen.get(package_name) if not current and runez.is_executable(program): # Edge case for older versions that weren't based on freeze self._refresh_frozen() current = self.frozen.get(package_name) if not current or (version and current != version): spec = package_name if not version else "%s==%s" % (package_name, version) self._run_pip("install", "-i", system.SETTINGS.index, spec) self._refresh_frozen() return program
def _installed_module(self, command_spec): """ :param system.PackageSpec command_spec: Associated package spec """ program = os.path.join(self.bin, command_spec.dashed) current = self.frozen.get(command_spec.dashed) if not current and runez.is_executable(program): # Edge case for older versions that weren't based on freeze self._refresh_frozen() current = self.frozen.get(command_spec.dashed) if not current or (command_spec.version and current != command_spec.version): self._run_builtin_module("pip", "install", "-i", system.SETTINGS.index, command_spec.specced) self._refresh_frozen() return program
def test_install_pypi(cli): cli.expect_failure("--color install six", "it is not a CLI") assert not os.path.exists(dot_meta("six")) cli.expect_failure("install mgit+foo", "not a valid pypi package name") runez.touch( dot_meta("mgit/.foo")) # Should stay because name starts with '.' runez.touch(dot_meta("mgit/mgit-foo")) # Bogus installation runez.touch(dot_meta("mgit/mgit-0.0.1/foo")) # Oldest should be deleted # Simulate the presence of an old entry point manifest_path = dot_meta("mgit/.manifest.json") runez.save_json(dict(entrypoints=["mgit", "old-mgit-entrypoint"]), manifest_path) runez.touch("old-mgit-entrypoint") assert os.path.exists("old-mgit-entrypoint") time.sleep(0.01) # Ensure 0.0.1 is older than 0.0.2 runez.touch( dot_meta("mgit/mgit-0.0.2/foo")) # Youngest should remain for an hour check_install_from_pypi(cli, "symlink", "mgit") assert not os.path.exists("old-mgit-entrypoint") assert os.path.islink("mgit") assert os.path.exists(dot_meta("mgit/.manifest.json")) assert os.path.exists(dot_meta("mgit/.foo")) assert os.path.exists(dot_meta("mgit/mgit-0.0.2")) assert not os.path.exists(dot_meta("mgit/mgit-foo")) assert not os.path.exists(dot_meta("mgit/mgit-0.0.1")) cfg = PickleyConfig() cfg.set_base(".") pspec = PackageSpec(cfg, "mgit") pspec.groom_installation(keep_for=0) assert not os.path.exists(dot_meta("mgit/mgit-0.0.2")) cli.expect_success("uninstall mgit", "Uninstalled mgit") assert not runez.is_executable("mgit") assert not os.path.exists(dot_meta("mgit")) assert os.path.exists(dot_meta("audit.log")) check_install_from_pypi(cli, "wrap", "mgit", simulate_version="0.0.0") check_is_wrapper("mgit", True)
def find_brew_name(target): """ :param str target: Path to executable file :return str, str: Name of brew formula, if target was installed with brew """ if not os.path.islink(target): return None, None path = os.path.realpath(target) folder = runez.parent_folder(target) cellar = os.path.join(runez.parent_folder(folder), "Cellar") if not path.startswith(cellar): return None, None brew = os.path.join(folder, "brew") if not runez.is_executable(brew): return None, None name, _, _ = path[len(cellar) + 1:].partition("/") return brew, name
def test_delivery(temp_base): # Test copy folder tox = system.PackageSpec("tox") deliver = DELIVERERS.get("copy")(tox) target = os.path.join(temp_base, "t1") source = os.path.join(temp_base, "t1-source") source_file = os.path.join(source, "foo") runez.touch(source_file) deliver.install(target, source) assert os.path.isdir(target) assert os.path.isfile(os.path.join(target, "foo")) # Test copy file deliver = DELIVERERS.get("copy")(tox) target = os.path.join(temp_base, "t2") source = os.path.join(temp_base, "t2-source") runez.touch(source) deliver.install(target, source) assert os.path.isfile(target) # Test symlink deliver = DELIVERERS.get("symlink")(tox) target = os.path.join(temp_base, "l2") source = os.path.join(temp_base, "l2-source") runez.touch(source) deliver.install(target, source) assert os.path.islink(target) # Test wrapper p = PACKAGERS.get(system.VENV_PACKAGER)(tox) assert p.create_symlinks(None) == 0 assert p.create_symlinks("foo", fatal=False) == 0 p.executables = ["foo"] assert p.create_symlinks("foo:bar", fatal=False) == -1 assert str(p) == "venv tox" target = os.path.join(temp_base, "tox") source = os.path.join(temp_base, "tox-source") runez.touch(source) deliver = DELIVERERS.get("wrap")(system.PackageSpec("tox")) deliver.install(target, source) assert runez.is_executable(target)
def find_venvs(folder, _seen=None): """ :param str folder: Folder to scan for venvs :param set|None _seen: Allows to not get stuck on circular symlinks """ if folder and os.path.isdir(folder): if _seen is None: folder = os.path.realpath(folder) _seen = set() if folder not in _seen: _seen.add(folder) files = os.listdir(folder) if "bin" in files: bin_folder = os.path.join(folder, "bin") if runez.is_executable(os.path.join(bin_folder, "python")): yield bin_folder return for name in files: fname = os.path.join(folder, name) for path in find_venvs(fname, _seen=_seen): yield path
def is_clear_for_installation(self): """ Returns: (bool): True if we can proceed with installation without needing to uninstall anything """ if self.is_already_installed_by_pickley: return True target = self.exe_path(self.dashed) if not target or not os.path.exists(target): return True path = os.path.realpath(target) if path.startswith(self.cfg.meta.path): return True # Pickley symlink if os.path.isfile(target): if os.path.getsize(target) == 0 or not runez.is_executable(target): return True # Empty file or not executable for line in runez.readlines(target, first=5): if PICKLEY in line: return True # Pickley wrapper
def test_install(cli): cli.expect_success("--dryrun --delivery wrap install tox", "Would wrap", "Would install tox") cli.expect_success("--dryrun --delivery symlink install tox", "Would symlink", "Would install tox") assert not os.path.exists(".pickley/audit.log") cli.expect_failure("check tox", "is not installed") cli.expect_failure("install six", "'six' is not a CLI") # Install tox, but add a few files + a bogus previous entry point to test cleanup runez.write(".pickley/tox/.entry-points.json", '["tox-old1", "tox-old2"]\n') runez.touch("tox-old1") runez.touch(".pickley/tox/tox-0.1/bin") runez.touch(".pickley/tox/tox-0.2/bin") runez.touch(".pickley/tox/tox-0.3/bin") runez.touch(".pickley/tox/tox-old1-0.1") runez.touch(".pickley/tox/tox-old1-0.2") cli.expect_success("--delivery wrap install tox", "Installed tox") # Old entry point removed immediately assert not os.path.exists("tox-old1") # Only 1 cleaned up immediately (latest + 1 kept) assert not os.path.exists(".pickley/tox/tox-0.1") assert not os.path.exists(".pickley/tox/tox-0.2") assert os.path.exists(".pickley/tox/tox-0.3") assert not os.path.exists(".pickley/tox/tox-old1-0.1") assert os.path.exists(".pickley/tox/tox-old1-0.2") assert runez.is_executable("tox") result = run_program("tox", "--version") assert "tox" in result.output cli.expect_success("auto-upgrade tox", "Skipping auto-upgrade") runez.delete(system.SETTINGS.meta.full_path("tox", ".ping")) cli.expect_success("auto-upgrade tox", "already installed") cli.expect_success("copy .pickley/tox tox-copy", "Copied") cli.expect_success("move tox-copy tox-relocated", "Moved") runez.delete("tox-relocated") # Verify that older versions and removed entry-points do get cleaned up runez.save_json({"install_timeout": 0}, "custom-timeout.json") cli.expect_success("-ccustom-timeout.json install tox", "already installed") # All cleaned up when enough time went by assert not os.path.exists(".pickley/tox/tox-0.3") assert not os.path.exists(".pickley/tox/tox-old1-0.2") cli.expect_success("check", "tox", "is installed") cli.expect_success( "check --verbose", "tox", "is installed (as %s wrap, channel: " % system.VENV_PACKAGER) # Simulate new version available latest = runez.read_json(".pickley/tox/.latest.json") latest["version"] = "10000.0" runez.save_json(latest, ".pickley/tox/.latest.json") cli.expect_failure("check", "tox", "can be upgraded to 10000.0") # Latest twine 2.0 requires py3 cli.expect_success("-ppex install twine==1.14.0", "Installed twine") cli.expect_success("list", "tox", "twine") cli.expect_success("list --verbose", "tox", "twine") assert find_uninstaller("tox") assert find_uninstaller("twine") cli.expect_success("uninstall twine", "Uninstalled twine") runez.write(".pickley/tox/.current.json", "") cli.expect_failure("check", "tox", "Couldn't read", "is not installed") cli.expect_success("uninstall --all", "Uninstalled tox", "entry points") assert not os.path.exists("tox") assert not os.path.exists(".pickley")
def _first_executable(self, *paths): for path in paths: if runez.is_executable(path): return path return None
def parent_python(): prefix = getattr(sys, "real_prefix", None) if prefix: path = os.path.join(prefix, "bin", "python") if runez.is_executable(path): return path
def test_install(cli): tox = system.SETTINGS.base.full_path("tox") p = PACKAGERS.resolved("tox") p.refresh_desired() tox_version = p.desired.version assert not os.path.exists(tox) assert runez.first_line(tox) is None cli.expect_success("--dryrun -b{base} --delivery wrap install tox", "Would wrap", "Would install tox", base=cli.context) cli.expect_success("--dryrun -b{base} --delivery symlink install tox", "Would symlink", "Would install tox", base=cli.context) cli.expect_failure("--dryrun -b{base} --delivery foo install tox", "invalid choice: foo", base=cli.context) cli.expect_success("--dryrun uninstall /dev/null --force", "Nothing to uninstall") runez.touch("foo") assert os.path.exists("foo") cli.expect_failure("uninstall foo", "foo was not installed with pickley") cli.expect_success("uninstall foo --force", "Uninstalled foo") assert not os.path.exists("foo") assert runez.ensure_folder("foo", folder=True) == 1 cli.expect_failure("uninstall foo --force", "Can't automatically uninstall") cli.expect_failure("-b{base} check tox foo/bar", "is not installed", "can't determine latest version", base=cli.context) cli.expect_failure("-b{base} install six", "'six' is not a CLI", base=cli.context) # Install tox, but add a few files + a bogus previous entry point to test cleanup wep1 = system.SETTINGS.base.full_path("tox-old-entrypoint1") tep10 = system.SETTINGS.meta.full_path("tox", "tox-old-entrypoint1-1.0") tep11 = system.SETTINGS.meta.full_path("tox", "tox-old-entrypoint1-1.1") t00 = system.SETTINGS.meta.full_path("tox", "tox-0.0.0") tfoo = system.SETTINGS.meta.full_path("tox", "tox-foo") runez.touch(wep1) runez.touch(tep10) runez.touch(tep11) runez.touch(t00) runez.touch(tfoo) eppath = system.SETTINGS.meta.full_path("tox", ".entry-points.json") runez.write(eppath, '["tox-old-entrypoint1", "tox-old-entrypoint2"]\n') cli.expect_success("-b{base} --delivery wrap install tox", "Installed tox", base=cli.context) # Old entry point removed immediately assert not os.path.exists(wep1) # Only 1 cleaned up immediately (latest + 1 kept) assert not os.path.exists(tep10) assert os.path.exists(tep11) assert not os.path.exists(t00) assert os.path.exists(tfoo) assert runez.is_executable(tox) output = run_program(tox, "--version") assert "tox" in output assert tox_version in output cli.expect_success("-b{base} auto-upgrade tox", "Skipping auto-upgrade", base=cli.context) runez.delete(system.SETTINGS.meta.full_path("tox", ".ping")) cli.expect_success("-b{base} auto-upgrade tox", "already installed", base=cli.context) version = output.partition(" ")[0] cli.expect_success("copy .pickley/tox/tox-%s tox-copy" % version, "Copied") cli.expect_success("move tox-copy tox-relocated", "Moved") # Verify that older versions and removed entry-points do get cleaned up runez.save_json({"install_timeout": 0}, "custom-timeout.json") cli.expect_success("-b{base} -ccustom-timeout.json install tox", "already installed", base=cli.context) # All cleaned up when enough time went by assert not os.path.exists(tep10) assert not os.path.exists(tep11) assert not os.path.exists(t00) assert not os.path.exists(tfoo) cli.expect_success("-b{base} check", "tox", "is installed", base=cli.context) cli.expect_success( "-b{base} check --verbose", "tox", "is installed (as %s wrap, channel: " % system.VENV_PACKAGER, base=cli.context, ) p = PACKAGERS.get(system.VENV_PACKAGER)("tox") p.refresh_latest() p.latest.version = "10000.0" p.latest.save() cli.expect_failure("-b{base} check", "tox", "can be upgraded to 10000.0", base=cli.context) cli.expect_success("-b{base} -ppex install twine", "Installed twine", base=cli.context) cli.expect_success("-b{base} list", "tox", "twine", base=cli.context) cli.expect_success("-b{base} list --verbose", "tox", "twine", base=cli.context) tmp = os.path.realpath(cli.context) assert find_uninstaller(os.path.join(tmp, "tox")) assert find_uninstaller(os.path.join(tmp, "twine")) cli.expect_success("-b{base} uninstall twine", "Uninstalled twine", base=cli.context) runez.delete(p.current._path) runez.touch(p.current._path) cli.expect_failure("-b{base} check", "tox", "Couldn't read", "is not installed", base=cli.context) cli.expect_success("-b{base} uninstall tox", "Uninstalled tox", "entry points", base=cli.context)