def test_pathlib(temp_folder): subfolder = Path("subfolder") assert runez.to_path(subfolder) is subfolder assert not subfolder.is_dir() runez.ensure_folder(subfolder) assert subfolder.is_dir() with pytest.raises(Exception): runez.to_path("foo bar", no_spaces=Exception) with runez.CurrentFolder(subfolder, anchor=True): path = Path("foo") assert runez.short(path) == "foo" assert runez.short(path.absolute()) == "foo" assert runez.resolved_path(path) assert runez.parent_folder(path) == os.path.join(temp_folder, "subfolder") assert runez.touch(path) == 1 assert runez.copy(path, Path("bar")) == 1 assert runez.copy(Path("bar"), Path("baz")) == 1 foo_json = Path("foo.json") runez.write(path, '{"a": "b"}') runez.symlink(path, foo_json) assert runez.read_json(foo_json) == {"a": "b"} assert list(runez.readlines(foo_json)) == ['{"a": "b"}'] assert runez.basename(foo_json.absolute()) == "foo"
def __enter__(self): """Acquire lock""" if CFG.base: runez.Anchored.add(CFG.base.path) cutoff = time.time() + self.give_up holder_args = self._locked_by() while holder_args: if time.time() >= cutoff: lock = runez.bold(runez.short(self.lock_path)) holder_args = runez.bold(holder_args) raise SoftLockException( "Can't grab lock %s, giving up\nIt is being held by: pickley %s" % (lock, holder_args)) time.sleep(1) holder_args = self._locked_by() # We got the soft lock if runez.DRYRUN: print("Would acquire %s" % runez.short(self.lock_path)) else: runez.log.trace("Acquired %s" % runez.short(self.lock_path)) runez.write(self.lock_path, "%s\n%s\n" % (os.getpid(), runez.quoted(sys.argv[1:])), logger=False) self.pspec.resolve() return self
def mk_python(basename, prefix=None, base_prefix=None, executable=True, content=None, folder=None, version=None): if version is None: m = RE_VERSION.match(basename) if m: if not folder: folder = os.path.join(".pyenv/versions", basename) version = m.group(2) basename = "python" if not folder: folder = ".pyenv/versions" path = runez.resolved_path(folder) if not prefix: prefix = path if not base_prefix: base_prefix = prefix path = os.path.join(path, "bin", basename) if not content: content = [version, prefix, base_prefix] content = "#!/bin/bash\n%s\n" % "\n".join("echo %s" % s for s in content) runez.write(path, content, logger=None) if executable: runez.make_executable(path, logger=None)
def mock_git_clone(pspec): basename = runez.basename(pspec.original) pspec.folder = pspec.cfg.cache.full_path("checkout", basename) setup_py = os.path.join(pspec.folder, "setup.py") runez.write( setup_py, "from setuptools import setup\nsetup(name='%s', version='1.0')\n" % basename, dryrun=False)
def test_default_index(temp_folder, logged): assert get_default_index() == (None, None) # Verify that we try 'a' (no such file), then find a configured index in 'b' runez.write("b", "[global]\nindex-url = https://example.com/pypi", logger=False) assert get_default_index("a", "b") == ("b", "https://example.com/pypi") # Not logging, since default is pypi, and which index is used can be configured and seen via diagnostics command assert not logged
def __init__(self, cfg, name, version): self.cfg = cfg self.name = name self.version = version self.entry_points = {name: name} self.pspec = PackageSpec(cfg, name, version=version) self.pspec.save_manifest(self.entry_points) self.venv = PythonVenv(self.pspec, create=False) self.venv_exe = os.path.join(self.pspec.install_path, "bin", name) runez.write(self.venv_exe, "#!/bin/bash\necho %s" % version) runez.make_executable(self.venv_exe)
def _install(self, target, source): wrapper = PICKLEY_WRAPPER if self.package_name == system.PICKLEY else GENERIC_WRAPPER contents = wrapper.lstrip().format( hook=self.hook, bg=self.bg, name=runez.quoted(self.package_name), pickley=runez.quoted(system.SETTINGS.base.full_path( system.PICKLEY)), source=runez.quoted(source), ) runez.write(target, contents) runez.make_executable(target)
def test_file_operations(temp_folder): runez.symlink("foo", "dangling-symlink", must_exist=False) runez.move("dangling-symlink", "dangling-symlink2") assert os.path.islink("dangling-symlink2") runez.write("README.md", "hello") runez.copy("README.md", "sample1/README.md") runez.copy("sample1", "sample2") runez.move("sample1/README.md", "sample1/foo") # overwrite=None "merges" dir contents runez.copy("sample1", "sample2", overwrite=None) assert dir_contents("sample2") == {"README.md": ["hello"], "foo": ["hello"]} # overwrite=True replaces dir runez.copy("sample1", "sample2", overwrite=True) assert dir_contents("sample2") == {"foo": ["hello"]} # overwrite=None, source is a dir, existing destination file gets replaced by source directory runez.copy("sample1", "sample2/foo", overwrite=None) assert dir_contents("sample2") == {"foo": {"foo": ["hello"]}} with runez.CaptureOutput(dryrun=True) as logged: assert runez.ensure_folder("some-folder", fatal=False) == 1 assert "Would create" in logged.pop() assert runez.touch("some-file", logger=logging.debug) == 1 assert "Would touch some-file" in logged.pop() assert runez.copy("some-file", "bar") == 1 assert "Would copy some-file -> bar" in logged.pop() assert runez.move("some-file", "bar") == 1 assert "Would move some-file -> bar" in logged.pop() assert runez.symlink("some-file", "bar") == 1 assert "Would symlink some-file <- bar" in logged.pop() assert runez.delete(temp_folder) == 1 assert "Would delete" in logged.pop() assert runez.copy("some-folder/bar", "some-folder", fatal=False) == -1 assert "source contained in destination" in logged.pop() assert runez.move("some-folder/bar/baz", "some-folder", fatal=False) == -1 assert "source contained in destination" in logged.pop() assert runez.symlink("some-folder/bar/baz", "some-folder", fatal=False) == -1 assert "source contained in destination" in logged.pop()
def __enter__(self): """ Acquire lock """ cutoff = time.time() + self.timeout while self._locked(): if time.time() >= cutoff: raise SoftLockException(self.folder) time.sleep(1) # We got the soft lock runez.write(self.lock, "%s\n" % os.getpid()) if not self._should_keep(): runez.delete(self.folder, logger=LOG.debug if self.keep else None) return self
def test_wrapper(temp_base): repeater = os.path.join(temp_base, "repeat.sh") target = os.path.join(temp_base, system.PICKLEY) runez.write(repeater, "#!/bin/bash\n\necho :: $*\n") runez.make_executable(repeater) # Actual wrapper d = DeliveryMethodWrap(system.PackageSpec(system.PICKLEY)) d.install(target, repeater) assert runez.run(target, "auto-upgrade", "foo") == RunResult(":: auto-upgrade foo", "", 0) assert runez.run(target, "--debug", "auto-upgrade", "foo") == RunResult(":: --debug auto-upgrade foo", "", 0) assert runez.run(target, "settings", "-d") == RunResult(":: settings -d", "", 0) # Verify that we're triggering background auto-upgrade as expected d.hook = "echo " d.bg = "" d.install(target, repeater) result = runez.run(target, "settings", "-d") assert "nohup" in result.output assert "repeat.sh settings -d" in result.output result = runez.run(target, "auto-upgrade", "foo") assert "nohup" not in result.output assert "repeat.sh auto-upgrade foo" in result.output result = runez.run(target, "--debug", "auto-upgrade", "foo") assert "nohup" not in result.output assert "repeat.sh --debug auto-upgrade foo" in result.output runez.delete(repeater) result = runez.run(target, "foo", fatal=False) assert result.failed assert "Please reinstall with" in result.full_output assert os.path.exists(target) assert uninstall_existing(target, fatal=False) == 1 assert not os.path.exists(target)
def _install(self, pspec, target, source): pickley = pspec.cfg.base.full_path(PICKLEY) if pspec.dashed == PICKLEY: wrapper = PICKLEY_WRAPPER else: wrapper = GENERIC_WRAPPER if runez.DEV.project_folder and not os.path.exists(pickley): # We're running from development venv pickley = pspec.cfg.program_path contents = wrapper.lstrip().format( hook=self.hook, bg=self.bg, name=runez.quoted(pspec.dashed, adapter=None), pickley=runez.quoted(pickley, adapter=None), source=runez.quoted(source, adapter=None), ) runez.delete(target, logger=False) runez.write(target, contents, logger=False) runez.make_executable(target, logger=False)
def test_convenience(temp_log): fmt = "f:%(filename)s mod:%(module)s func:%(funcName)s %(levelname)s %(message)s " fmt += " path:%(pathname)s" runez.log.setup(console_format=fmt, console_level=logging.DEBUG, file_format=None) assert temp_log.logfile is None runez.write("some-file", "some content", logger=logging.info) logging.info("hello") logging.exception("oops") assert "f:system.py mod:system func:hlog INFO Wrote 12 bytes" in temp_log.stderr assert "f:test_logsetup.py mod:test_logsetup func:test_convenience INFO hello" in temp_log.stderr assert "f:test_logsetup.py mod:test_logsetup func:test_convenience ERROR oops" in temp_log.stderr temp_log.stderr.clear() runez.write("some-file", "some content", logger=LOG.info) LOG.info("hello") LOG.exception("oops") assert "f:system.py mod:system func:hlog INFO Wrote 12 bytes" in temp_log.stderr assert "f:test_logsetup.py mod:test_logsetup func:test_convenience INFO hello" in temp_log.stderr assert "f:test_logsetup.py mod:test_logsetup func:test_convenience ERROR oops" in temp_log.stderr
def test_capture(temp_folder, logged): chatter = runez.resolved_path("chatter") assert runez.write(chatter, CHATTER.strip(), fatal=False) == 1 assert runez.make_executable(chatter, fatal=False) == 1 assert runez.run(chatter, fatal=False) == "chatter" r = runez.run(chatter, include_error=True, fatal=False) assert r.startswith("chatter") assert "No such file" in r assert "Running: chatter" in logged
def textual_diff(kind, actual, expected): actual_error = isinstance(actual, dict) and actual.get("_error") or None expected_error = isinstance(expected, dict) and expected.get("_error") or None if actual_error != expected_error: if actual_error: return diff_overview(kind, actual_error, expected_error, "deserialization failed") return diff_overview(kind, actual_error, expected_error, "deserialization did NOT yield expected error") if type(actual) != type(expected): return diff_overview(kind, type(actual), type(expected), "differing types") if kind == TestSamples.K_TOKEN: actual = "%s\n" % "\n".join(actual) expected = "%s\n" % "\n".join(expected) else: actual = runez.represented_json(actual, keep_none=True, none_key="-null-") expected = runez.represented_json(expected, keep_none=True, none_key="-null-") if actual != expected: with runez.TempFolder(dryrun=False): runez.write("actual", actual) runez.write("expected", expected) r = runez.run("diff", "-br", "-U1", "expected", "actual", fatal=None, dryrun=False) return formatted_diff(r.full_output)
def test_entry_points(temp_cfg): venv = PythonVenv(folder="", cfg=temp_cfg) with runez.CaptureOutput(dryrun=True): pspec = PackageSpec(temp_cfg, "mgit") contents = PackageContents(venv, pspec) assert str(contents) == "mgit [None]" assert str(contents.bin) == "bin [1 files]" assert contents.entry_points == {"mgit": "dryrun"} runez.write( "ansible.dist-info/metadata.json", '{"extensions": {"python.commands": {"wrap_console": ["ansible"]}}}') with patch("runez.run", side_effect=simulated_run): pspec = PackageSpec(temp_cfg, "ansible") # Used to trigger ansible edge case contents = PackageContents(venv, pspec) assert str(contents) == "ansible [.]" assert str(contents.bin) == "bin [0 files]" assert str(contents.completers) == "bin [1 files]" assert str(contents.dist_info) == "ansible.dist-info [1 files]" assert contents.entry_points == ["ansible"] assert str(contents.files) == " [1 files]" assert contents.files.files.get("foo/bar.py") assert contents.info == { "Name": "ansible", "Version": "1.0.0", "Location": "." } assert contents.location == "." assert contents.pspec is pspec assert contents.venv is venv contents = PackageContents(venv, PackageSpec(temp_cfg, "no-location")) assert contents.files is None assert contents.entry_points is None contents = PackageContents(venv, PackageSpec(temp_cfg, "no-such-package")) assert contents.files is None assert contents.entry_points is None
def test_debian_mode(temp_folder, logged): runez.write( "foo/setup.py", "import setuptools\nsetuptools.setup(name='foo', version='1.0')") p = dummy_finalizer("root/apps") assert p.dist == "root/apps/foo" assert p.requirements == [runez.resolved_path("foo")] assert "Using python:" in logged.pop() # Symlink not created unless source effectively exists p.symlink.apply("root/foo") assert "skipping symlink" in logged.pop() assert not os.path.isdir("root/usr/local/bin") foo = runez.resolved_path("root/foo") runez.touch(foo) logged.pop() # Simulate symlink p.symlink.apply(foo) assert "Symlinked root/usr/local/bin/foo -> root/foo" in logged.pop() assert os.path.isdir("root/usr/local/bin") assert os.path.islink("root/usr/local/bin/foo") with patch("os.path.isdir", return_value=True): # pretend /apps exists p = dummy_finalizer("root/apps") assert "debian mode" in logged.pop() assert p.dist == "/apps/foo" with patch("runez.run", return_value=runez.program.RunResult("usage: ...")): assert p.validate_sanity_check( "foo", "--version") == "does not respond to --version" with patch("runez.run", return_value=runez.program.RunResult("failed")): with pytest.raises(SystemExit): p.validate_sanity_check("foo", "--version") assert "'foo' failed --version sanity check" in logged.pop()
def relocate_venv(path, source, destination, fatal=True, _seen=None): """ :param str path: Path of file or folder to relocate (change mentions of 'source' to 'destination') :param str source: Where venv used to be :param str destination: Where venv is moved to :param bool fatal: Abort execution on failure if True :return int: Number of relocated files (0 if no-op, -1 on failure) """ original_call = False if _seen is None: original_call = True _seen = set() if not path or path in _seen: return 0 _seen.add(path) if os.path.isdir(path): relocated = 0 if original_call: for bin_folder in find_venvs(path): for name in os.listdir(bin_folder): fpath = os.path.join(bin_folder, name) r = relocate_venv(fpath, source, destination, fatal=fatal, _seen=_seen) if r < 0: return r relocated += r return relocated modified = False lines = [] try: for line in runez.readlines(path): if source in line: line = line.replace(source, destination) modified = True lines.append(line) except Exception: return 0 # If binary file, skip if not modified: return 0 return runez.write(path, "\n".join(lines), fatal=fatal)
def test_failed_read(*_): with runez.CaptureOutput() as logged: assert runez.get_lines("bar", fatal=False) is None assert "Can't read" in logged.pop() assert runez.write("bar", "some content", fatal=False) assert "Can't write" in logged.pop() assert runez.copy("some-file", "bar", fatal=False) == -1 assert "Can't delete" in logged assert "Can't copy" in logged.pop() assert runez.make_executable("some-file", fatal=False) == -1 assert "Can't chmod" in logged.pop()
def test_ini_to_dict(temp_folder, logged): assert runez.file.ini_to_dict(None) == {} assert runez.file.ini_to_dict("foo") == {} assert not logged with pytest.raises(runez.system.AbortException) as exc: runez.file.ini_to_dict("foo", fatal=True) assert "Can't read foo" in str(exc) assert "Can't read foo" in logged.pop() expected = {None: {"root": "some-value"}, "": {"ek": "ev"}, "s1": {"k1": "v1"}, "s2": {"k2": ""}} runez.write("test.ini", SAMPLE_CONF, logger=None) actual = runez.file.ini_to_dict("test.ini", keep_empty=True, logger=None) assert not logged assert actual == expected del expected[None] del expected[""] del expected["s2"] actual = runez.file.ini_to_dict("test.ini", keep_empty=False) assert not logged assert actual == expected
def test_facultative(cli): runez.save_json({"pinned": { "virtualenv": { "facultative": True } }}, dot_meta("config.json")) # Empty file -> proceed with install as if it wasn't there runez.touch("virtualenv") cli.expect_success("-n install virtualenv", "Would state: Installed virtualenv") # Simulate pickley wrapper runez.write("virtualenv", "echo installed by pickley") runez.make_executable("virtualenv") cli.expect_success("-n install virtualenv", "Would state: Installed virtualenv") # Unknown executable -> skip pickley installation (since facultative) runez.write("virtualenv", "echo foo") runez.make_executable("virtualenv") cli.expect_success( "-n install virtualenv", "Skipping installation of virtualenv: not installed by pickley") cli.expect_success("-n check virtualenv", "skipped, not installed by pickley") # --force ignores 'facultative' setting cli.expect_failure("-n install --force virtualenv", "Can't automatically uninstall virtualenv") # Simulate pickley symlink delivery dummy_target = dot_meta("foo") runez.touch(dummy_target) runez.symlink(dummy_target, "virtualenv") cli.expect_success("-n install virtualenv", "Would state: Installed virtualenv")
def test_lock(temp_cfg, logged): pspec = PackageSpec(temp_cfg, "foo") lock_path = dot_meta("foo.lock") with SoftLock(pspec, give_up=600) as lock: assert str(lock) == "lock foo" assert os.path.exists(lock_path) try: # Try to grab same lock a seconds time, give up after 1 second with SoftLock(pspec, give_up=1, invalid=600): assert False, "Should not grab same lock twice!" except SoftLockException as e: assert "giving up" in str(e) assert not os.path.exists(lock_path) # Check that lock was released # Check that lock detects bogus (or dead) PID runez.write(lock_path, "0\nbar\n") with SoftLock(pspec, give_up=600): lines = list(runez.readlines(lock_path)) assert lines[0] == str( os.getpid()) # Lock file replaced with correct stuff assert not os.path.exists(lock_path) # Lock released
def test_relocate_venv_successfully(temp_base): with runez.CaptureOutput() as logged: original = "line 1: source\nline 2\n" runez.write("foo/bar/bin/baz", original, logger=logging.debug) runez.write("foo/bar/bin/empty", "", logger=logging.debug) runez.write("foo/bar/bin/python", "", logger=logging.debug) runez.make_executable("foo/bar/bin/baz") runez.make_executable("foo/bar/bin/empty") runez.make_executable("foo/bar/bin/python") assert "Created" in logged.pop() # Simulate already seen expected = ["line 1: source\n", "line 2\n"] assert system.relocate_venv("foo", "source", "dest", fatal=False, _seen={"foo"}) == 0 assert runez.get_lines("foo/bar/bin/baz") == expected assert not logged # Simulate failure to write with patch("runez.write", return_value=-1): assert system.relocate_venv("foo", "source", "dest", fatal=False) == -1 assert runez.get_lines("foo/bar/bin/baz") == expected assert not logged # Simulate effective relocation, by folder expected = ["line 1: dest\n", "line 2\n"] assert system.relocate_venv("foo", "source", "dest", fatal=False) == 1 assert runez.get_lines("foo/bar/bin/baz") == expected assert "Relocated " in logged # Second relocation is a no-op assert system.relocate_venv("foo", "source", "dest", fatal=False) == 0 # Test relocating a single file runez.write("foo/bar/bin/baz", original, logger=logging.debug) assert system.relocate_venv("foo/bar/bin/baz", "source", "dest", fatal=False) == 1 assert "Relocated " in logged
def test_failure(monkeypatch): monkeypatch.setattr(io, "open", runez.conftest.exception_raiser()) monkeypatch.setattr(os, "unlink", runez.conftest.exception_raiser("bad unlink")) monkeypatch.setattr(shutil, "copy", runez.conftest.exception_raiser()) monkeypatch.setattr(os.path, "exists", lambda _: True) monkeypatch.setattr(os.path, "isfile", lambda _: True) monkeypatch.setattr(os.path, "getsize", lambda _: 10) with runez.CaptureOutput() as logged: with patch("runez.file._do_delete"): with patch("pathlib.Path.exists", return_value=True): assert runez.copy("some-file", "bar", fatal=False) == -1 assert "Can't copy" in logged.pop() assert runez.delete("some-file", fatal=False) == -1 assert "Can't delete" in logged assert "bad unlink" in logged.pop() assert runez.write("bar", "some content", fatal=False) assert "Can't write" in logged.pop() if not runez.SYS_INFO.platform_id.is_windows: assert runez.make_executable("some-file", fatal=False) == -1 assert "Can't chmod" in logged.pop()
def test_bootstrap(cli, monkeypatch): with patch("pickley.bstrap.which", side_effect=mocked_which): with patch("pickley.bstrap.os.path.expanduser", side_effect=mocked_expanduser): runez.write( ".local/bin/pickley", "#!/bin/sh\necho 0.1") # Pretend we have an old pickley runez.make_executable(".local/bin/pickley") with patch("pickley.bstrap.get_python_version", return_value=(3, 6)): # urllib fails monkeypatch.setenv("__PYVENV_LAUNCHER__", "oh apple, why?" ) # macos oddity env var, should be removed cli.run("-n", main=bstrap.main) assert cli.succeeded assert "__PYVENV_LAUNCHER__" not in os.environ assert "Replacing older pickley 0.1" in cli.logged assert "Would run: python virtualenv.pyz" in cli.logged assert "Would run: .local/bin/.pickley/pickley/pickley-" in cli.logged # Simulate multiple base candidates given cli.run("-n", "-b", "~/.local/bin:foo/bar", main=bstrap.main) assert cli.failed assert "not suitable: ~/.local/bin, foo/bar" in cli.logged # Simulate seeding cli.run("0.1", "-b", "~/.local/bin", "-m", "my-mirror", "-c", '{"pyenv":"~/.pyenv"}', main=bstrap.main) assert cli.succeeded assert "Seeding .local/bin/.pickley/config.json with {'pyenv': '~/.pyenv'}" in cli.logged assert "Seeding .config/pip/pip.conf with my-mirror" in cli.logged assert "pickley version 0.1 is already installed" in cli.logged assert list(runez.readlines(".config/pip/pip.conf")) == [ "[global]", "index-url = my-mirror" ] assert list( runez.readlines(".local/bin/.pickley/config.json")) == [ "{", ' "pyenv": "~/.pyenv"', "}" ] monkeypatch.setenv("PATH", "foo/bar:%s" % os.environ["PATH"]) runez.ensure_folder("foo/bar", logger=None) cli.run("-n", "-b", "~/.local/bin:foo/bar", main=bstrap.main) assert cli.succeeded assert "base: foo/bar" in cli.logged with patch("pickley.bstrap.which", return_value=None): with patch("pickley.bstrap.is_executable", return_value=False): # Simulate no python 3 cli.run("-n", main=bstrap.main) assert cli.failed assert "Could not find python3 on this machine" in cli.logged with patch("pickley.bstrap.get_python_version", return_value=(3, 9)): # urllib fails cli.run("-n", main=bstrap.main) assert cli.succeeded assert " -mvenv " in cli.logged
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 relocate_venv(path, source, destination, fatal=True, logger=LOG.debug, _seen=None): """ :param str path: Path of file or folder to relocate (change mentions of 'source' to 'destination') :param str source: Where venv used to be :param str destination: Where venv is moved to :param bool fatal: Abort execution on failure if True :param callable|None logger: Logger to use :return int: Number of relocated files (0 if no-op, -1 on failure) """ original_call = False if _seen is None: original_call = True _seen = set() if not path or path in _seen: return 0 _seen.add(path) if os.path.isdir(path): relocated = 0 if original_call: for bin_folder in find_venvs(path): for name in os.listdir(bin_folder): fpath = os.path.join(bin_folder, name) r = relocate_venv(fpath, source, destination, fatal=fatal, logger=logger, _seen=_seen) if r < 0: return r relocated += r if logger and relocated: logger("Relocated %s files in %s: %s -> %s", relocated, short(path), short(source), short(destination)) return relocated content = runez.get_lines(path, fatal=fatal) if not content: return 0 modified = False lines = [] for line in content: if source in line: line = line.replace(source, destination) modified = True lines.append(line) if not modified: return 0 r = runez.write(path, "".join(lines), fatal=fatal) if r > 0 and logger and original_call: logger("Relocated %s: %s -> %s", short(path), short(source), short(destination)) return r
def test_paths(temp_folder): assert runez.resolved_path(None) is None assert runez.resolved_path("some-file") == os.path.join(temp_folder, "some-file") assert runez.resolved_path("some-file", base="bar") == os.path.join(temp_folder, "bar", "some-file") assert runez.short(None) is None assert runez.short("") == "" assert runez.short(temp_folder) == temp_folder assert runez.short(temp_folder + "/some-file") == "some-file" assert runez.short(temp_folder + "/some-file") == "some-file" assert runez.parent_folder(None) is None assert runez.parent_folder(temp_folder + "/some-file") == temp_folder assert runez.represented_args(["ls", temp_folder + "/some-file bar", "-a"]) == 'ls "some-file bar" -a' # Don't crash for no-ops assert runez.ensure_folder(None) == 0 assert runez.ensure_folder("") == 0 assert runez.copy(None, None) == 0 assert runez.move(None, None) == 0 assert runez.symlink(None, None) == 0 assert runez.copy("some-file", "some-file") == 0 assert runez.move("some-file", "some-file") == 0 assert runez.symlink("some-file", "some-file") == 0 assert runez.ensure_folder("some-folder") == 0 # 'some-folder' would be in temp_folder, which already exists with runez.CaptureOutput(dryrun=True) as logged: assert runez.ensure_folder("some-folder", folder=True, fatal=False) == 1 assert "Would create" in logged.pop() assert runez.touch("some-file", logger=logging.debug) == 1 assert "Would touch some-file" in logged.pop() assert runez.copy("some-file", "bar") == 1 assert "Would copy some-file -> bar" in logged.pop() assert runez.move("some-file", "bar") == 1 assert "Would move some-file -> bar" in logged.pop() assert runez.symlink("some-file", "bar") == 1 assert "Would symlink some-file <- bar" in logged.pop() assert runez.delete(temp_folder) == 1 assert "Would delete" in logged.pop() assert runez.copy("some-folder/bar/baz", "some-folder", fatal=False) == -1 assert "source contained in destination" in logged.pop() assert runez.move("some-folder/bar/baz", "some-folder", fatal=False) == -1 assert "source contained in destination" in logged.pop() assert runez.symlink("some-folder/bar/baz", "some-folder", fatal=False) == -1 assert "source contained in destination" in logged.pop() with runez.CaptureOutput(): assert runez.touch("sample") == 1 assert "Can't create folder" in runez.verify_abort(runez.ensure_folder, "sample", folder=True) custom = runez.verify_abort(runez.ensure_folder, "sample", folder=True, fatal=SystemExit, expected_exception=SystemExit) assert "Can't create folder" in custom with pytest.raises(AssertionError): assert runez.verify_abort(runez.ensure_folder, None) assert runez.delete("sample") == 1 assert runez.ensure_folder("sample", folder=True) == 1 assert os.getcwd() == temp_folder with runez.CurrentFolder("sample", anchor=False): cwd = os.getcwd() sample = os.path.join(temp_folder, "sample") assert cwd == sample assert runez.short(os.path.join(cwd, "some-file")) == "sample/some-file" with runez.CurrentFolder("sample", anchor=True): cwd = os.getcwd() sample = os.path.join(temp_folder, "sample") assert cwd == sample assert runez.short(os.path.join(cwd, "some-file")) == "some-file" assert os.getcwd() == temp_folder assert runez.delete("sample") == 1 with runez.CaptureOutput() as logged: sample = os.path.join(os.path.dirname(__file__), "sample.txt") content = runez.get_lines(sample) assert runez.write("sample", "".join(content), fatal=False, logger=logging.debug) == 1 assert runez.get_lines("sample") == content assert "Writing 13 bytes" in logged.pop() assert runez.first_line("sample") == "Fred" assert runez.is_younger("sample", age=10) assert not runez.is_younger("sample", age=-1) assert runez.copy("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() assert runez.move("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() assert runez.symlink("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() # Creating dangling symlinks is possible assert runez.symlink("bar", "baz", fatal=False, must_exist=False) == 1 assert "Symlink bar <- baz" in logged.pop() assert os.path.islink("baz") assert not os.path.exists("baz") assert runez.copy("sample", "x/y/sample") == 1 assert runez.symlink("sample", "x/y/sample3", fatal=False) == 1 assert os.path.exists("sample") assert runez.move("sample", "x/y/sample2") == 1 assert not os.path.exists("sample") assert runez.copy("x/y", "x/z") == 1 assert os.path.exists("x/z/sample") assert os.path.exists("x/z/sample2") assert os.path.exists("x/z/sample3") assert os.path.islink("x/z/sample3") assert runez.touch(None) == 0 assert not runez.is_younger(None, 1) assert not runez.is_younger("/dev/null/not-there", 1) assert runez.first_line("/dev/null/not-there") is None assert runez.get_lines(None) is None
def test_versions(_, __, temp_base): p = PACKAGERS.get("pex")("foo") p.pip_wheel = lambda *_: None assert p.specced_command() == "pex" p.implementation_version = "1.4.5" assert p.specced_command() == "pex==1.4.5" p.refresh_desired() assert p.desired.representation( verbose=True ) == "foo: can't determine latest version from pypi (channel: latest, source: pypi)" with patch("pickley.package.latest_pypi_version", return_value="error: test failed"): p.refresh_desired() assert p.desired.representation() == "foo: test failed" system.SETTINGS.cli.contents["channel"] = "stable" p.refresh_desired() assert p.desired.representation() == "foo: can't determine stable version" p.version = None assert "can't determine stable version" in verify_abort(p.install) # Without a build folder assert p.get_entry_points() is None # With an empty build fodler runez.ensure_folder(p.build_folder, folder=True) assert p.get_entry_points() is None # With a bogus wheel with runez.CaptureOutput() as logged: p.version = "0.0.0" whl = os.path.join(p.build_folder, "foo-0.0.0-py2.py3-none-any.whl") runez.touch(whl) assert p.get_entry_points() is None assert "Can't read wheel" in logged runez.delete(whl) p.refresh_desired() assert p.desired.channel == "adhoc" assert p.desired.source == "cli" assert p.desired.version == "0.0.0" assert not p.desired.problem p.version = None p.refresh_desired() assert p.desired.problem # Ambiguous package() call assert "Need either source_folder or version in order to package" in verify_abort( p.package) # Package bogus folder without a setup.py p.source_folder = temp_base assert "No setup.py" in verify_abort(p.package) # Package with a bogus setup.py setup_py = os.path.join(temp_base, "setup.py") runez.touch(setup_py) assert "Could not determine version" in verify_abort(p.package) # Provide a minimal setup.py runez.write( setup_py, "from setuptools import setup\nsetup(name='foo', version='0.0.0')\n") # Package project without entry points p.get_entry_points = lambda *_: None assert "is not a CLI" in verify_abort(p.required_entry_points)
def test_file_inspection(temp_folder, logged): assert runez.touch("sample") == 1 assert runez.delete("sample") == 1 assert "Deleted sample" in logged.pop() assert runez.ensure_folder("sample") == 1 assert runez.delete("sample") == 1 assert "Deleted sample" in logged.pop() sample = runez.DEV.tests_path("sample.txt") assert len(list(runez.readlines(sample))) == 4 assert len(list(runez.readlines(sample, first=1))) == 1 assert not logged cc = "%s\n" % "\n".join(runez.readlines(sample)) assert runez.write("sample", cc, fatal=False, logger=logging.debug) == 1 cc2 = "%s\n" % "\n".join(runez.readlines("sample")) assert cc2 == cc assert "bytes to sample" in logged.pop() # Wrote 13 bytes on linux... but 14 on windows... assert list(runez.readlines("sample", first=2)) == ["", "Fred"] assert runez.file.is_younger("sample", age=10) assert not runez.file.is_younger("sample", age=-1) # Verify that readlines() can ignore encoding errors with io.open("not-a-text-file", "wb") as fh: fh.write(b"\x89 hello\nworld") assert list(runez.readlines("not-a-text-file", first=1)) == [" hello"] assert not logged assert runez.copy("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() assert runez.move("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() assert runez.symlink("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() # Creating dangling symlinks is possible assert runez.symlink("s/bar", "s/baz", fatal=False, must_exist=False) == 1 assert "Symlink s/bar <- s/baz" in logged.pop() assert os.path.islink("s/baz") assert not os.path.exists("s/baz") runez.touch("s/bar") assert os.path.exists("s/baz") assert runez.copy("sample", "x/y/sample") == 1 assert runez.symlink("sample", "x/y/sample3", fatal=False) == 1 assert os.path.exists("sample") assert runez.move("sample", "x/y/sample2") == 1 assert not os.path.exists("sample") assert runez.copy("x/y", "x/z1") == 1 assert os.path.exists("x/z1/sample") assert os.path.exists("x/z1/sample2") assert os.path.exists("x/z1/sample3") assert os.path.islink("x/z1/sample3") assert runez.copy("x/y", "x/z2", ignore={"sample2"}) == 1 assert os.path.exists("x/z2/sample") assert not os.path.exists("x/z2/sample2") assert os.path.exists("x/z2/sample3") assert os.path.islink("x/z2/sample3") def should_ignore(src, dest): if src == "x/y" and "sample3" in dest: return {"sample3"} assert runez.copy("x/y", "x/z3", ignore=should_ignore) == 1 assert os.path.exists("x/z3/sample") assert os.path.exists("x/z3/sample2") assert not os.path.exists("x/z3/sample3") assert runez.copy("x/y", "x/z2") == 1 assert os.path.exists("x/z2/sample2") # Copy a folder over an existing file runez.touch("x2") assert not os.path.exists("x2/z2/sample2") assert runez.copy("x", "x2") == 1 assert os.path.exists("x2/z2/sample2")
def test_decompress(temp_folder, logged): runez.write("test/README.md", "hello", logger=None) runez.write("test/a/b", "c", logger=None) expected = dir_contents("test") test_folder = runez.to_path("test/") assert runez.filesize(test_folder) == 6 assert runez.represented_bytesize(test_folder) == "6 B" assert runez.represented_bytesize(runez.to_path("no-such-file")) == "0 B" # Unknown extension assert runez.compress("test", "test.foo", overwrite=False, fatal=False) == -1 assert "Unknown extension 'test.foo'" in logged.pop() assert runez.decompress("test.foo", "somewhere", fatal=False) == -1 assert "Unknown extension 'test.foo'" in logged.pop() assert runez.compress("test", "test.tar.gz", dryrun=True) == 1 assert "Would tar test -> test.tar.gz" in logged.pop() assert runez.compress("test", "test.tar") == 1 assert runez.compress("test", "test.tar.gz") == 1 assert runez.compress("test", "test.tar.xz") == 1 assert runez.compress("test", "test.zip") == 1 assert "Tar test -> test.tar.gz" in logged.pop() size_raw = runez.filesize("test.tar") size_gz = runez.filesize("test.tar.gz") size_xz = runez.filesize("test.tar.xz") size_zip = runez.filesize("test.zip") assert size_raw > size_gz assert size_gz != size_xz if sys.version_info[:2] > (3, 8): # Flakey for some reason on 3.6... not sure why (.gz and .zip sizes are sometimes equal...) assert size_gz != size_zip # Tar on top of existing file assert runez.compress("test", "test.tar.gz", overwrite=False, fatal=False) == -1 assert "test.tar.gz exists, can't tar" in logged.pop() assert runez.decompress("test.tar.gz", "unpacked", dryrun=True) == 1 assert "Would untar test.tar.gz -> unpacked" in logged.pop() assert runez.decompress("test.tar.gz", "unpacked", simplify=True) == 1 assert "Untar test.tar.gz -> unpacked" in logged.pop() assert dir_contents("unpacked") == expected # Second attempt fails without overwrite assert runez.decompress("test.tar.gz", "unpacked", overwrite=False, fatal=False) == -1 assert "unpacked exists, can't untar" in logged.pop() # Second attempt succeeds with overwrite assert runez.decompress("test.tar.gz", "unpacked", simplify=True, logger=None) == 1 assert dir_contents("unpacked") == expected # Check .xz file assert runez.decompress("test.tar.gz", "unpacked", simplify=True, logger=None) == 1 assert dir_contents("unpacked") == expected # Check .zip file assert runez.decompress("test.zip", "unpacked", simplify=True, logger=None) == 1 assert dir_contents("unpacked") == expected assert not logged assert runez.decompress("test.zip", "unpacked2", logger=None) == 1 assert dir_contents("unpacked2") == {"test": expected} # Verify that arcname=None works correctly assert runez.compress("test", "test-flat.tar.gz", arcname=None) == 1 assert runez.compress("test", "test-flat.zip", arcname=None) == 1 assert runez.decompress("test-flat.tar.gz", "unpacked-flat-gz", logger=None) == 1 assert runez.decompress("test-flat.zip", "unpacked-flat-zip", logger=None) == 1 assert dir_contents("unpacked-flat-gz") == expected assert dir_contents("unpacked-flat-zip") == expected