class SimulatedInstallation: 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 check_wrap(self, wrap_method): impl = DeliveryMethod.delivery_method_by_name(wrap_method) impl.install(self.pspec, self.venv, self.entry_points) exe = runez.resolved_path(self.name) r = runez.run(exe, "--version", fatal=False) assert r.succeeded assert r.output == self.version def check_alternating(self, logged): self.check_wrap("wrap") assert "Wrapped %s -> " % self.name in logged.pop() self.check_wrap("symlink") assert "Symlinked %s -> " % self.name in logged.pop() self.check_wrap("wrap") assert "Wrapped %s -> " % self.name in logged.pop()
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 test_bogus_config(temp_folder, logged): cfg = grab_sample("bogus-config") assert cfg.pyenv() == "/dev/null" # from custom.json assert cfg.resolved_bundle("") == [] assert cfg.resolved_bundle("foo") == ["foo"] assert cfg.resolved_bundle("bundle:dev") == ["tox", "mgit"] assert cfg.resolved_bundle("bundle:dev2") == ["tox", "mgit", "pipenv"] actual = cfg.represented().strip() expected = SAMPLE_CONFIG.strip().format( base=runez.short(cfg.base), meta=runez.short(cfg.meta), DEFAULT_PYTHONS=DEFAULT_PYTHONS, ) assert actual == expected p = cfg.find_python(pspec=None, fatal=False) assert p.executable == "/dev/null/foo" assert p.problem == "not an executable" assert "skipped: not an executable" in logged.pop() assert not logged with pytest.raises(SystemExit): # Fails to resolve due to desired python configured to be /dev/null PackageSpec(cfg, "mgit") assert "No suitable python" in logged.pop()
def resolve(self): if not os.path.isdir(self.folder): abort("Folder %s does not exist" % runez.red(runez.short(self.folder))) req = self.requirements if not req: default_req = runez.resolved_path("requirements.txt", base=self.folder) if os.path.exists(default_req): req = [default_req] if req: req = [("-r", runez.resolved_path(r, base=self.folder)) for r in req] req = runez.flattened(req, shellify=True) req.append(self.folder) self.requirements = req self.pspec = PackageSpec(CFG, self.folder) LOG.info("Using python: %s" % self.pspec.python) if self.dist.startswith("root/"): # Special case: we're targeting 'root/...' probably for a debian, use target in that case to avoid venv relocation issues target = self.dist[4:] if os.path.isdir(target): LOG.debug("debian mode: %s -> %s", self.dist, target) self.dist = target parts = self.dist.split("/") if len(parts) <= 2: # Auto-add package name to targets of the form root/subfolder (most typical case) self.dist = os.path.join(self.dist, self.pspec.dashed)
def base(what): """Show pickley base folder""" path = CFG.base.path if what == "bootstrap-own-wrapper": # Internal: called by bootstrap script from pickley.delivery import DeliveryMethodWrap pspec = PackageSpec(CFG, PICKLEY, version=__version__) venv = PythonVenv(pspec, create=False) wrap = DeliveryMethodWrap() wrap.install(pspec, venv, {PICKLEY: PICKLEY}) return if what: paths = { "audit": CFG.meta.full_path("audit.log"), "cache": CFG.cache.path, "config": CFG.meta.full_path("config.json"), "meta": CFG.meta.path, } paths["audit.log"] = paths["audit"] paths["config.json"] = paths["config"] path = paths.get(what) if not path: options = [runez.green(s) for s in sorted(paths)] abort("Unknown base folder reference '%s', try one of: %s" % (runez.red(what), ", ".join(options))) print(path)
def auto_upgrade(force, package): """Background auto-upgrade command (called by wrapper)""" pspec = PackageSpec(CFG, package) ping = pspec.ping_path if not force and runez.file.is_younger( ping, 5): # 5 seconds cool down on version check to avoid bursts LOG.debug("Skipping auto-upgrade, checked recently") sys.exit(0) runez.touch(ping) lock_path = pspec.get_lock_path() if runez.file.is_younger(lock_path, CFG.install_timeout(pspec)): LOG.debug("Lock file present, another installation is in progress") sys.exit(0) perform_install(pspec, is_upgrade=True, force=False, quiet=True)
def test_install_pypi(cli): cli.expect_failure("--color install six", "it is not a CLI") assert not os.path.exists(dot_meta("six")) cli.expect_failure("install mgit+foo", "not a valid pypi package name") runez.touch( dot_meta("mgit/.foo")) # Should stay because name starts with '.' runez.touch(dot_meta("mgit/mgit-foo")) # Bogus installation runez.touch(dot_meta("mgit/mgit-0.0.1/foo")) # Oldest should be deleted # Simulate the presence of an old entry point manifest_path = dot_meta("mgit/.manifest.json") runez.save_json(dict(entrypoints=["mgit", "old-mgit-entrypoint"]), manifest_path) runez.touch("old-mgit-entrypoint") assert os.path.exists("old-mgit-entrypoint") time.sleep(0.01) # Ensure 0.0.1 is older than 0.0.2 runez.touch( dot_meta("mgit/mgit-0.0.2/foo")) # Youngest should remain for an hour check_install_from_pypi(cli, "symlink", "mgit") assert not os.path.exists("old-mgit-entrypoint") assert os.path.islink("mgit") assert os.path.exists(dot_meta("mgit/.manifest.json")) assert os.path.exists(dot_meta("mgit/.foo")) assert os.path.exists(dot_meta("mgit/mgit-0.0.2")) assert not os.path.exists(dot_meta("mgit/mgit-foo")) assert not os.path.exists(dot_meta("mgit/mgit-0.0.1")) cfg = PickleyConfig() cfg.set_base(".") pspec = PackageSpec(cfg, "mgit") pspec.groom_installation(keep_for=0) assert not os.path.exists(dot_meta("mgit/mgit-0.0.2")) cli.expect_success("uninstall mgit", "Uninstalled mgit") assert not runez.is_executable("mgit") assert not os.path.exists(dot_meta("mgit")) assert os.path.exists(dot_meta("audit.log")) check_install_from_pypi(cli, "wrap", "mgit", simulate_version="0.0.0") check_is_wrapper("mgit", True)
def 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_edge_cases(temp_cfg, monkeypatch, logged): monkeypatch.setattr(PickleyConfig, "_pickley_dev_path", None) pspec = PackageSpec(temp_cfg, PICKLEY) assert pspec._pickley_dev_mode == runez.DEV.project_folder assert pspec.install_path.endswith("%s-dev" % PICKLEY) assert pspec.find_wheel(".", fatal=False) is None assert "Expecting 1 wheel" in logged.pop() runez.touch("%s-1.0.0.whl" % PICKLEY) w = pspec.find_wheel(".", fatal=False) assert w == "./%s-1.0.0.whl" % PICKLEY with pytest.raises(NotImplementedError): Packager.package(None, None, None, None, False) runez.touch("share/python-wheels/some-wheel.whl") runez.touch("__pycache__/some_module.py") runez.touch("some_module.pyc") logged.pop() clean_compiled_artifacts(".") assert "Deleted 3 compiled artifacts" in logged.pop() assert not os.path.exists("share/python-wheels") assert os.path.isdir("share")
def test_edge_cases(temp_folder, logged): venv = MagicMock(bin_path=lambda x: os.path.join("some-package/bin", x)) entry_points = {"some-source": ""} cfg = PickleyConfig() cfg.set_base(".") pspec = PackageSpec(cfg, "mgit", "1.0.0") d = DeliveryMethod() with pytest.raises(SystemExit): d.install(pspec, venv, entry_points) assert "Can't deliver some-source -> some-package/bin/some-source: source does not exist" in logged.pop( ) runez.touch("some-package/bin/some-source") with pytest.raises(SystemExit): d.install(pspec, venv, entry_points) assert "Failed to deliver" in logged.pop()
def test_pip_fail(temp_cfg, logged): pspec = PackageSpec(temp_cfg, "bogus") venv = PythonVenv(pspec, folder="") assert str(venv) == "" with patch("pickley.package.PythonVenv.run_pip", return_value=runez.program.RunResult("", "some\nerror", code=1)): with pytest.raises(SystemExit): venv.pip_install("foo") assert "some\nerror" == logged.stdout.pop() r = runez.program.RunResult( "", "foo\nNo matching distribution for ...\nYou should consider upgrading pip", code=1) with patch("pickley.package.PythonVenv.run_pip", return_value=r): with pytest.raises(SystemExit): venv.pip_install("foo") assert "No matching distribution for ..." in logged assert "You should consider" not in logged
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_good_config(temp_folder, logged): cfg = grab_sample("good-config") assert cfg.resolved_bundle("bundle:dev") == [ "tox", "mgit", "poetry", "pipenv" ] mgit = PackageSpec(cfg, "mgit", "1.0.0") pickley = PackageSpec(cfg, "pickley") assert mgit < pickley # Ordering based on package name, then version assert str(mgit) == "mgit==1.0.0" assert str(pickley) == "pickley" assert mgit.index == "https://pypi-mirror.mycompany.net/pypi" logged.clear() d = pickley.get_desired_version_info() assert d.source == "current" assert d.version == __version__ d = mgit.get_desired_version_info() assert d.source == "explicit" assert d.version == "1.0.0" # Verify latest when no pins configured p = PackageSpec(cfg, "foo") d = p.get_desired_version_info() assert d.version == "0.1.2" assert d.source == "latest" # Verify pinned versions in samples/.../config.json are respected p = PackageSpec(cfg, "mgit") d = p.get_desired_version_info() assert d.version == "1.2.1" assert d.source == "pinned"