Пример #1
0
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"
Пример #2
0
    def create_symlinks(self, symlink, root=None, fatal=True):
        """
        Use case: preparing a .tox/package/root folder to be packaged as a debian
        With a spec of "root:root/usr/local/bin", all executables produced under ./root will be symlinked to /usr/local/bin

        :param str symlink: A specification of the form "root:root/usr/local/bin"
        :param str root: Optionally, 'root' prefix if used
        :param bool fatal: Abort execution on failure if True
        :return int: 1 if effectively done, 0 if no-op, -1 on failure
        """
        if not symlink or not self.executables:
            return 0

        base, _, target = symlink.partition(":")
        if not target:
            return runez.abort("Invalid symlink specification '%s'", symlink, fatal=(fatal, -1))

        base = runez.resolved_path(base)
        target = runez.resolved_path(target)
        for path in self.executables:
            if path and root:
                path = runez.resolved_path(root + path)

            if not path.startswith(base) or len(path) <= len(base):
                return runez.abort("Symlink base '%s' does not cover '%s'", base, path, fatal=(fatal, -1))

            source = path[len(base):]
            basename = os.path.basename(path)
            destination = os.path.join(target, basename)
            runez.symlink(source, destination, must_exist=False, fatal=fatal, logger=LOG.info)

        return 1 if self.executables else 0
Пример #3
0
def test_edge_cases():
    # Don't crash for no-ops
    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.delete("non-existing") == 0

    assert runez.touch(None) == 0
    assert not runez.file.is_younger("", None)
    assert not runez.file.is_younger("", 1)
    assert not runez.file.is_younger("/dev/null/not-there", 1)
Пример #4
0
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()
Пример #5
0
    def apply(self, exe):
        dest = os.path.join(self.target, os.path.basename(exe))
        if os.path.exists(exe):
            r = runez.symlink(exe, dest, must_exist=False)
            if r > 0:
                inform("Symlinked %s -> %s" %
                       (runez.short(dest), runez.short(exe)))

        else:
            LOG.debug("'%s' does not exist, skipping symlink" % exe)
Пример #6
0
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")
Пример #7
0
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
Пример #8
0
def test_depot(temp_folder, monkeypatch, logged):
    # Create some pyenv-style python installation mocks (using version 8 so it sorts above any real version...)
    mk_python("8.6.1")
    mk_python("8.7.2")
    runez.symlink("8.6.1",
                  ".pyenv/versions/8.6",
                  must_exist=False,
                  logger=None)

    # Verify that if invoker is one of the pyenv-installations, it is properly detected
    depot = mocked_invoker(pyenv=".pyenv",
                           base_prefix=".pyenv/versions/8.6.1",
                           version_info=(8, 6, 1))
    p8 = depot.find_python("8")
    p86 = depot.find_python("8.6")
    assert str(
        p8
    ) == ".pyenv/versions/8.7.2 [cpython:8.7.2]"  # Latest version 8 (invoker doesn't take precedence)
    assert p8.folder == runez.to_path(".pyenv/versions/8.7.2/bin").absolute()
    assert p86 is depot.invoker
    assert str(depot) == "2 scanned"
    assert depot.scanned == [p8, p86]
    assert depot.from_path == []
    assert not logged

    mk_python("8.8.3", executable=False)
    mk_python("8.9.0")
    mk_python("miniconda3-4.7.12")

    # Create some PATH-style python installation mocks (using version 9 so it sorts higher than pyenv ones)
    mk_python("python", folder="path1", version="9.5.1")
    mk_python("python3", folder="path1", content=[
        "foo"
    ])  # Invalid: mocked _pv.py does not return the right number of lines
    mk_python("python", folder="path2",
              content=["foo; bar"])  # --version fails
    mk_python("some-other-python-exe-name", folder="path3", version="8.5.0")
    mk_python("python3", folder="path3")  # Invalid version
    with runez.CurrentFolder("path3/bin"):
        runez.symlink("some-other-python-exe-name", "python", logger=None)

    monkeypatch.setenv("PATH", "bar:path1/bin:path2/bin:path3/bin")
    scanner = PythonInstallationScanner(".pyenv")
    assert str(scanner) == "portable python [.pyenv]"
    depot = PythonDepot(scanner=scanner, use_path=True)
    assert str(depot) == "4 scanned, 2 from PATH"
    r = depot.representation()
    assert "Installed portable python:" in r
    assert "Available pythons from PATH:" in r

    depot.find_preferred_python("8.7.2,8.9.0", "8.7", "8.10")
    assert depot.preferred_python.version == "8.7.2"

    depot.find_preferred_python("8.7.2,8.9.0", "8.7", "8.8")
    assert depot.preferred_python.version == "8.9.0"
    assert depot.find_python(None) is depot.preferred_python
    assert depot.find_python("8") is depot.preferred_python

    depot.find_preferred_python("8.7.2,8.9.0", "10.7", "10.8")
    assert depot.preferred_python is None

    depot.find_preferred_python("")
    assert depot.preferred_python is None

    assert len(depot.from_path) == 2
    assert len(depot.scanned) == 4
    assert depot.scan_path_env_var(
    ) is None  # Already scanned to try and find invoker
    p95 = depot.find_python("9.5.1")
    assert str(p95) == "path1/bin/python [cpython:9.5.1]"

    check_find_python(depot, "9", "path1/bin/python [cpython:9.5.1]")
    check_find_python(depot, "42.4", "42.4 [not available]")
    check_find_python(depot, "foo", "foo [not available]")
    check_find_python(depot, "python:43.0.0", "python:43.0.0 [not available]")

    with pytest.raises(runez.system.AbortException):
        depot.find_python("/bar", fatal=True)

    pbar = depot.find_python("/bar")
    assert str(pbar) == "/bar [not an executable]"
    assert pbar.problem
    assert not pbar.satisfies(depot.spec_from_text("python"))

    p8 = depot.find_python("8")
    p8a = depot.find_python(PythonSpec("8"))
    assert p8a is p8
    p86 = depot.find_python("8.6")
    p87 = depot.find_python("8.7")
    p88 = depot.find_python("8.8")
    p89 = depot.find_python("8.9")
    c = depot.find_python("conda")
    c47 = depot.find_python("conda:4.7")
    assert c47 is c
    assert depot.find_python(PythonSpec("conda47")) is c47
    assert depot.scanned == [p89, p87, p86, c47]

    assert p8.major == 8
    assert p88.major == 8
    assert str(p8) == ".pyenv/versions/8.9.0 [cpython:8.9.0]"
    assert str(p88) == "8.8 [not available]"
    assert str(c47) == ".pyenv/versions/miniconda3-4.7.12 [conda:4.7.12]"
    assert p8 is p89
    assert p8 == p89
    assert p8 != p88
    assert p8 != pbar
    assert p8.satisfies(PythonSpec("python"))
    assert p8.satisfies(PythonSpec("python8"))
    assert p8.satisfies(PythonSpec("py8.9.0"))
    assert not p8.satisfies(PythonSpec("py8.9.1"))
    assert c47.satisfies(PythonSpec("conda47"))
    assert len({p8, p89}) == 1
    assert len({p8, p89, p88}) == 2
Пример #9
0
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")