Example #1
0
    def effective_package(self, template):
        """
        :param str template: Template describing how to name delivered files, example: {meta}/{name}-{version}
        """
        folder = os.path.join(
            self.dist_folder,
            template.format(name=self.name, version=self.version))
        runez.delete(folder, logger=None)
        runez.ensure_folder(folder, folder=True, logger=None)
        vrun(self.name, "virtualenv", folder)

        bin_folder = os.path.join(folder, "bin")
        pip = os.path.join(bin_folder, "pip")
        spec = self.source_folder if self.source_folder else "%s==%s" % (
            self.name, self.version)
        runez.run(pip, "install", "-i", system.SETTINGS.index, "-f",
                  self.build_folder, spec)

        if self.relocatable:
            python = system.target_python(package_name=self.name).executable
            vrun(self.name, "virtualenv", "--relocatable",
                 "--python=%s" % python, folder)

        self.packaged.append(folder)
        self.executables = [
            os.path.join(bin_folder, name) for name in self.entry_points
        ]
Example #2
0
    def pex_build(self, name, destination):
        """
        Run pex build

        :param str name: Name of entry point
        :param str destination: Path to file where to produce pex
        :return str: None if successful, error message otherwise
        """
        runez.ensure_folder(self.build_folder, folder=True)
        runez.delete(destination)

        args = ["--cache-dir", self.build_folder, "--repo", self.build_folder]
        args.extend([
            "-c%s" % name,
            "-o%s" % destination,
            "%s==%s" % (self.name, self.version)
        ])

        python = system.target_python(package_name=self.name)
        shebang = python.shebang(
            universal=system.is_universal(self.build_folder))
        if shebang:
            args.append("--python-shebang")
            args.append(shebang)

        vrun(self.name,
             self.specced_command(),
             *args,
             path_env=C_COMPILATION_HELP)
Example #3
0
 def __exit__(self, *_):
     """
     Release lock
     """
     if not self._should_keep():
         runez.delete(self.folder, logger=LOG.debug if self.keep else None)
     runez.delete(self.lock, logger=None)
Example #4
0
    def package(pspec, build_folder, dist_folder, requirements, run_compile_all):
        runez.ensure_folder(build_folder, clean=True)
        if pspec.python.major < 3:  # pragma: no cover
            abort("Packaging with pex is not supported any more with python2")

        pex_root = os.path.join(build_folder, "pex-root")
        tmp = os.path.join(build_folder, "pex-tmp")
        wheels = os.path.join(build_folder, "wheels")
        runez.ensure_folder(tmp, logger=False)
        runez.ensure_folder(wheels, logger=False)
        pex_venv = PythonVenv(pspec, folder=os.path.join(build_folder, "pex-venv"))
        pex_venv.pip_install("pex==2.1.75", *requirements)
        pex_venv.pip_wheel("--cache-dir", wheels, "--wheel-dir", wheels, *requirements)
        contents = PackageContents(pex_venv, pspec)
        if contents.entry_points:
            wheel_path = pspec.find_wheel(wheels)
            result = []
            for name in contents.entry_points:
                target = os.path.join(dist_folder, name)
                runez.delete(target)
                pex_venv.run_python(
                    "-mpex", "-o%s" % target, "--pex-root", pex_root, "--tmpdir", tmp,
                    "--no-index", "--find-links", wheels,  # resolver options
                    None if run_compile_all else "--no-compile",  # output options
                    "-c%s" % name,  # entry point options
                    "--python-shebang", "/usr/bin/env python%s" % pspec.python.major,
                    wheel_path,
                )
                result.append(target)

            return result
Example #5
0
    def __init__(self, lock, venv_python):
        """
        :param SoftLock lock: Acquired lock
        """
        self.venv_python = venv_python
        self.lock = lock
        self.folder = lock.folder
        self.bin = os.path.join(self.folder, "bin")
        self.python = os.path.join(self.bin, "python")
        self._frozen = None
        if runez.file.is_younger(self.python, self.lock.keep):
            return
        runez.delete(self.folder)

        is_py2 = runez.PY2
        if venv_python:
            is_py2 = runez.to_int(venv_python.major, default=2) < 3

        if is_py2:
            venv = virtualenv_path()
            if not venv:
                runez.abort("Can't determine path to virtualenv.py")
            runez.run(self.venv_python.executable, venv, self.folder)

        else:
            runez.run(self.venv_python.executable, "-mvenv", self.folder)
            runez.run(self.python, "-mpip", "install", "wheel")
Example #6
0
    def clean_samples(cls, verbose=False):
        cleanable = []
        for root, dirs, files in os.walk(cls.SAMPLE_FOLDER):
            if not dirs and not files:
                cleanable.append(root)

            if os.path.basename(root).startswith("_xpct-"):
                for fname in files:
                    ypath = os.path.dirname(root)
                    ypath = os.path.join(ypath,
                                         "%s.yml" % runez.basename(fname))
                    if not os.path.isfile(ypath):
                        # Delete _xpct-* files that correspond to moved samples
                        cleanable.append(os.path.join(root, fname))

        if not cleanable:
            if verbose:
                print("No cleanable _xpct- files found")

            return

        for path in cleanable:
            runez.delete(path, logger=logging.info)

        for root, dirs, files in os.walk(cls.SAMPLE_FOLDER):
            if not dirs and not files:
                cleanable.append(root)
                runez.delete(root, logger=logging.info)

        print("%s cleaned" % runez.plural(cleanable, "file"))
Example #7
0
def clean_folder(folder):
    """Clean contents of 'folder', if any"""
    if os.path.isdir(folder):
        for fname in os.listdir(folder):
            runez.delete(os.path.join(folder, fname))

    else:
        runez.ensure_folder(folder, folder=True)
Example #8
0
    def _install(self, pspec, target, source):
        runez.delete(target, logger=False)
        if os.path.isabs(source) and os.path.isabs(target):
            parent = runez.parent_folder(target)
            if runez.parent_folder(source).startswith(parent):
                # Use relative path if source is under target
                source = os.path.relpath(source, parent)

        os.symlink(source, target)
Example #9
0
    def cleanup(self):
        """Cleanup older installs"""
        cutoff = time.time() - system.SETTINGS.install_timeout * 60
        folder = system.SETTINGS.meta.full_path(self.name)

        removed_entry_points = runez.read_json(self.removed_entry_points_path,
                                               default=[],
                                               fatal=False)

        prefixes = {None: [], self.name: []}
        for name in self.entry_points:
            prefixes[name] = []
        for name in removed_entry_points:
            prefixes[name] = []

        if os.path.isdir(folder):
            for name in os.listdir(folder):
                if name.startswith("."):
                    continue
                target = find_prefix(prefixes, name)
                if target in prefixes:
                    fpath = os.path.join(folder, name)
                    prefixes[target].append((os.path.getmtime(fpath), fpath))

        # Sort each by last modified timestamp
        for target, cleanable in prefixes.items():
            prefixes[target] = sorted(cleanable, reverse=True)

        rem_cleaned = 0
        for target, cleanable in prefixes.items():
            if not cleanable:
                if target in removed_entry_points:
                    # No cleanable found for a removed entry-point -> count as cleaned
                    rem_cleaned += 1
                continue

            if target not in removed_entry_points:
                if cleanable[0][0] <= cutoff:
                    # Latest is old enough now, cleanup all except latest
                    cleanable = cleanable[1:]
                else:
                    # Latest is too young, keep the last 2
                    cleanable = cleanable[2:]
            elif cleanable[0][0] <= cutoff:
                # Delete all removed entry points when old enough
                rem_cleaned += 1
            else:
                # Removed entry point still too young, keep latest
                cleanable = cleanable[1:]

            for _, path in cleanable:
                runez.delete(path)

        if rem_cleaned >= len(removed_entry_points):
            runez.delete(self.removed_entry_points_path)
Example #10
0
 def required_entry_points(self):
     """
     :return list: Entry points, abort execution if there aren't any
     """
     ep = self.entry_points
     if not ep:
         runez.delete(system.SETTINGS.meta.full_path(self.name))
         runez.abort(
             "'%s' is not a CLI, it has no console_scripts entry points",
             self.name)
     return ep
Example #11
0
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")
Example #12
0
    def __exit__(self, *_):
        """Release lock"""
        if runez.DRYRUN:
            print("Would release %s" % runez.short(self.lock_path))

        else:
            runez.log.trace("Released %s" % runez.short(self.lock_path))

        if CFG.base:
            runez.Anchored.pop(CFG.base.path)

        runez.delete(self.lock_path, logger=False)
Example #13
0
def uninstall(all, packages):
    """Uninstall packages"""
    if packages and all:
        abort("Either specify packages to uninstall, or --all (but not both)")

    if not packages and not all:
        abort("Specify packages to uninstall, or --all")

    if packages and PICKLEY in packages:
        abort(
            "Run 'uninstall --all' if you wish to uninstall pickley itself (and everything it installed)"
        )

    setup_audit_log()
    for pspec in CFG.package_specs(packages):
        manifest = pspec.get_manifest()
        if not manifest or not manifest.version:
            abort("%s was not installed with pickley" %
                  runez.bold(pspec.dashed))

        if manifest.entrypoints:
            for ep in manifest.entrypoints:
                runez.delete(pspec.exe_path(ep))

        runez.delete(pspec.meta_path)
        action = "Would uninstall" if runez.DRYRUN else "Uninstalled"
        inform("%s %s" % (action, pspec.dashed))

    if all:
        runez.delete(CFG.base.full_path(PICKLEY))
        runez.delete(CFG.meta.path)
        inform("pickley is now %s" % runez.red("uninstalled"))
Example #14
0
def test_lock(temp_base):
    folder = os.path.join(temp_base, "foo")
    with SoftLock(folder, timeout=10) as lock:
        assert lock._locked()
        with pytest.raises(SoftLockException):
            with SoftLock(folder, timeout=0.01):
                pass
        assert str(lock) == folder + ".lock"
        runez.delete(str(lock))
        assert not lock._locked()

        with patch("pickley.system.virtualenv_path", return_value=None):
            assert "Can't determine path to virtualenv.py" in verify_abort(
                SharedVenv, lock, None)
Example #15
0
    def internal_install(self, force=False, verbose=True):
        """
        :param bool force: If True, re-install even if package is already installed
        :param bool verbose: If True, show more extensive info
        """
        with SoftLock(self.dist_folder,
                      timeout=system.SETTINGS.install_timeout):
            self.refresh_desired(force=force)
            self.version = self.desired.version
            if not self.desired.valid:
                return runez.abort("Can't install %s: %s", self.name,
                                   self.desired.problem)

            if not force and self.current.equivalent(self.desired):
                system.inform(
                    self.desired.representation(verbose=verbose,
                                                note="is already installed"))
                self.cleanup()
                return

            prev_entry_points = self.entry_points
            self.effective_install()

            new_entry_points = self.entry_points
            removed = set(prev_entry_points).difference(new_entry_points)
            if removed:
                old_removed = runez.read_json(self.removed_entry_points_path,
                                              default=[],
                                              fatal=False)
                removed = sorted(removed.union(old_removed))
                runez.save_json(removed,
                                self.removed_entry_points_path,
                                fatal=False)

            # Delete wrapper/symlinks of removed entry points immediately
            for name in removed:
                runez.delete(system.SETTINGS.base.full_path(name))

            self.cleanup()

            self.current.set_from(self.desired)
            self.current.save(fatal=False)

            msg = "Would install" if runez.DRYRUN else "Installed"
            system.inform("%s %s" %
                          (msg, self.desired.representation(verbose=verbose)))
Example #16
0
    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
Example #17
0
    def install(self, pspec, venv, entry_points):
        """
        Args:
            pspec (pickley.PackageSpec): Package spec this installation is for
            venv (pickley.package.PythonVenv): Virtual env where executables reside (DOT_META/<package>/...)
            entry_points (dict | list): Full path of executable to deliver (<base>/<entry_point>)
        """
        if not pspec.is_clear_for_installation():
            auto_uninstall(pspec.exe_path(pspec.dashed))

        try:
            prev_manifest = pspec.get_manifest()
            for name in entry_points:
                src = venv.bin_path(name)
                dest = pspec.exe_path(name)
                if runez.DRYRUN:
                    print("Would %s %s -> %s" %
                          (self.short_name, short(dest), short(src)))
                    continue

                if not os.path.exists(src):
                    abort(
                        "Can't %s %s -> %s: source does not exist" %
                        (self.short_name, short(dest), runez.red(short(src))))

                LOG.debug("%s %s -> %s" %
                          (self.action, short(dest), short(src)))
                self._install(pspec, dest, src)

            manifest = pspec.save_manifest(entry_points)
            if not runez.DRYRUN and prev_manifest and prev_manifest.entrypoints:
                for old_ep in prev_manifest.entrypoints:
                    if old_ep and old_ep not in entry_points:
                        # Remove old entry points that are not in new manifest any more
                        runez.delete(pspec.exe_path(old_ep))

            if self.ping:
                # Touch the .ping file since this is a fresh install (no need to check for upgrades right away)
                runez.touch(pspec.ping_path)

            return manifest

        except Exception as e:
            abort("Failed to %s %s: %s" %
                  (self.short_name, short(pspec), runez.red(e)))
Example #18
0
    def install(pspec, ping=True):
        delivery = DeliveryMethod.delivery_method_by_name(pspec.settings.delivery)
        delivery.ping = ping
        args = [pspec.specced]
        if pspec.folder:
            args = [pspec.folder]

        elif pspec._pickley_dev_mode:
            args = ["-e", pspec._pickley_dev_mode]  # pragma: no cover, convenience case for running pickley from .venv/

        venv = PythonVenv(pspec)
        venv.pip_install(*args)
        contents = PackageContents(venv, pspec)
        if not contents.entry_points:
            runez.delete(pspec.meta_path)
            abort("Can't install '%s', it is %s" % (runez.bold(pspec.dashed), runez.red("not a CLI")))

        return delivery.install(pspec, venv, contents.entry_points)
Example #19
0
    def __init__(self, lock, venv_python):
        """
        :param SoftLock lock: Acquired lock
        """
        self.venv_python = venv_python
        self.lock = lock
        self.folder = lock.folder
        self.bin = os.path.join(self.folder, "bin")
        self.python = os.path.join(self.bin, "python")
        self.pip = os.path.join(self.bin, "pip")
        self._frozen = None
        if runez.is_younger(self.python, self.lock.keep):
            return
        runez.delete(self.folder)
        venv = system.virtualenv_path()
        if not venv:
            runez.abort("Can't determine path to virtualenv.py")

        runez.run(self.venv_python.executable, venv, self.folder)
Example #20
0
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)
Example #21
0
    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)
Example #22
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)
Example #23
0
    def install(self, target, source):
        """
        :param str target: Full path of executable to deliver (<base>/<entry_point>)
        :param str source: Path to original executable being delivered (.pickley/<package>/...)
        """
        runez.delete(target)
        if runez.DRYRUN:
            LOG.debug("Would %s %s (source: %s)", self.implementation_name,
                      short(target), short(source))
            return

        if not os.path.exists(source):
            runez.abort("Can't %s, source %s does not exist",
                        self.implementation_name, short(source))

        try:
            LOG.debug("Delivering %s %s -> %s", self.implementation_name,
                      short(target), short(source))
            self._install(target, source)

        except Exception as e:
            runez.abort("Failed %s %s: %s", self.implementation_name,
                        short(target), e)
Example #24
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()
Example #25
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()
Example #26
0
    def groom_installation(self, keep_for=60):
        """
        Args:
            keep_for (int): Minimum time in minutes for how long to keep the previous latest version
        """
        if self.cfg.cache.contains(self.folder):
            runez.delete(self.folder, logger=False)

        current = self.get_manifest()
        meta_path = self.meta_path
        current_age = None
        if current and os.path.isdir(meta_path):
            now = time.time()
            candidates = []
            for fname in os.listdir(meta_path):
                if fname.startswith("."):  # Pickley meta files start with '.'
                    continue

                fpath = os.path.join(meta_path, fname)
                vpart = fname[len(self.dashed) + 1:]
                age = now - os.path.getmtime(fpath)
                if vpart == current.version:
                    current_age = age

                else:
                    version = Version(vpart)
                    if not version.is_valid:
                        # Not a proper installation
                        runez.delete(fpath, fatal=False)
                        continue

                    # Different version, previously installed
                    candidates.append((age, version, fpath))

            if not candidates:
                return

            candidates = sorted(candidates)
            youngest = candidates[0]
            for candidate in candidates[1:]:
                runez.delete(candidate[2], fatal=False)

            if current_age:
                current_age = min(current_age, youngest[0])
                if current_age > (keep_for * runez.date.SECONDS_IN_ONE_MINUTE):
                    runez.delete(youngest[2], fatal=False)
Example #27
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

    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
Example #28
0
def uninstall(force, packages):
    """
    Uninstall packages
    """
    packages = system.SETTINGS.resolved_packages(packages)
    errors = 0
    for name in packages:
        p = PACKAGERS.resolved(name)
        if not force and not p.current.file_exists:
            errors += 1
            LOG.error("%s was not installed with pickley", name)
            continue

        eps = p.entry_points
        ep_uninstalled = 0
        ep_missed = 0
        meta_deleted = runez.delete(system.SETTINGS.meta.full_path(name),
                                    fatal=False)
        if not eps and force:
            eps = {name: ""}
        if eps and meta_deleted >= 0:
            for entry_point in eps:
                path = system.SETTINGS.base.full_path(entry_point)
                handler = runez.delete if meta_deleted > 0 else uninstall_existing
                r = handler(path, fatal=False)
                if r < 0:
                    ep_missed += 1
                elif r > 0:
                    ep_uninstalled += 1

        if ep_missed or meta_deleted < 0:
            # Error was already reported
            errors += 1
            continue

        if ep_uninstalled + meta_deleted == 0:
            system.inform("Nothing to uninstall for %s" % name)
            continue

        message = "Would uninstall" if runez.DRYRUN else "Uninstalled"
        message = "%s %s" % (message, name)
        if ep_uninstalled > 1:
            message += " (%s entry points)" % ep_uninstalled
        system.inform(message)

    if errors:
        sys.exit(1)
Example #29
0
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()
Example #30
0
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")