def package(build, dist, symlink, relocatable, sanity_check, folder): """ Package a project from source checkout """ build = runez.resolved_path(build) root = None target_dist = dist if target_dist.startswith("root/"): # Special case: we're targeting 'root/...' probably for a debian, use target in that case to avoid venv relocation issues target = target_dist[4:] if os.path.isdir(target): root = target_dist[:4] target_dist = target LOG.debug("debian mode: %s -> %s", dist, target) folder = runez.resolved_path(folder) if not os.path.isdir(folder): sys.exit("Folder %s does not exist" % short(folder)) system.SETTINGS.set_base(build) setup_py = os.path.join(folder, "setup.py") if not os.path.exists(setup_py): sys.exit("No setup.py in %s" % short(folder)) with runez.CurrentFolder(folder): # Some setup.py's assume their working folder is the folder where they're in result = system.run_python(setup_py, "--name", fatal=False, dryrun=False) name = result.output if result.failed or not name: sys.exit("Could not determine package name from %s" % short(setup_py)) package_spec = system.PackageSpec(name) runez.Anchored.add(folder) p = PACKAGERS.resolved(package_spec) p.build_folder = build p.dist_folder = runez.resolved_path(target_dist) p.relocatable = relocatable p.source_folder = folder p.package() p.create_symlinks(symlink, root=root) p.sanity_check(sanity_check) if p.executables: overview = "produced: %s" % runez.quoted(p.executables) else: overview = "package has no entry-points" print("Packaged %s successfully, %s" % (short(folder), overview)) runez.Anchored.pop(folder)
def test_custom_settings(temp_base): system.SETTINGS.set_base(sample_path("custom")) stgs = system.SETTINGS assert isinstance(stgs, Settings) system.SETTINGS.load_config() check_specs("bundle:dev", ["tox", "twine"]) check_specs("bundle:dev2", ["tox", "twine", "pipenv"]) check_specs("bundle:dev bundle:dev2", ["tox", "twine", "pipenv"]) check_specs("pipenv bundle:dev bundle:dev2", ["pipenv", "tox", "twine"]) assert str(stgs) == "[4] base: %s" % short(stgs.base.path) assert str(stgs.defaults) == "defaults" assert str(stgs.base) == "base: %s" % short(stgs.base.path) assert stgs.get_definition("") is None assert stgs.resolved_definition("") is None assert stgs.resolved_value("foo") is None p = stgs.base.full_path("foo/bar") assert stgs.base.relative_path(p) == "foo/bar" d = stgs.resolved_definition( "delivery", package_spec=system.PackageSpec("dict_sample")) assert str(d) == ".pickley/config.json:delivery.copy" assert stgs.resolved_value( "delivery", package_spec=system.PackageSpec("tox")) == "venv" assert stgs.resolved_value( "delivery", package_spec=system.PackageSpec("virtualenv")) == "wrap" assert stgs.resolved_value( "packager", package_spec=system.PackageSpec("tox")) == system.VENV_PACKAGER assert stgs.resolved_value( "packager", package_spec=system.PackageSpec("virtualenv")) == "pex" with runez.Anchored(system.SETTINGS.meta.path): old_width = pickley.settings.REPRESENTATION_WIDTH pickley.settings.REPRESENTATION_WIDTH = 40 actual = stgs.represented(include_defaults=False).replace( short(stgs.base.path), "{base}") assert actual == EXPECTED_REPRESENTATION.strip() pickley.settings.REPRESENTATION_WIDTH = old_width stgs.cli.contents["packager"] = "copy" d = stgs.resolved_definition("packager") assert d.value == "copy" assert d.source is stgs.cli d = stgs.get_definition("packager") assert d.value == "copy" assert d.source is stgs.cli assert stgs.install_timeout == 2 assert stgs.version_check_seconds == 60
def main(ctx, debug, base, index, config, python, delivery, packager): """ Package manager for python CLIs """ if any(opt in sys.argv for opt in ctx.help_option_names): # pragma: no cover return runez.log.setup( debug=debug, console_format="%(levelname)s %(message)s" if debug else "%(message)s", console_level=logging.WARNING, console_stream=sys.stderr, locations=None, ) # Disable logging.config, as pip tries to get smart and configure all logging... runez.log.silence("pip") logging.config.dictConfig = lambda x: None if base: base = runez.resolved_path(base) if not os.path.exists(base): sys.exit("Can't use %s as base: folder does not exist" % short(base)) system.SETTINGS.set_base(base) system.SETTINGS.load_config(config=config, delivery=delivery, index=index, packager=packager) system.DESIRED_PYTHON = python
def sanity_check(self, args): """ :param str args: Args to run as sanity-check against all packaged exes, example: "--version" """ if args: for path in self.executables: result = runez.run(path, args) print("Sanity check: %s %s -> %s" % (short(path), args, result.full_output))
def install(self, force=False): """ :param bool force: If True, re-install even if package is already installed """ try: self.internal_install(force=force) except SoftLockException as e: LOG.error("%s is currently being installed by another process" % self.package_spec) runez.abort("If that is incorrect, please delete %s.lock", short(e.folder))
def test_bogus_install(cli): cli.expect_success("settings -d", "base: %s" % short(cli.context)) cli.expect_success("check", "No packages installed") cli.expect_success("list", "No packages installed") cli.expect_failure("-b foo/bar settings", "Can't use foo/bar as base: folder does not exist") cli.expect_failure("--dryrun check -- -bogus", "not a valid pypi package name") cli.expect_failure("--dryrun check this-package-does-not-exist", "can't determine latest version") cli.expect_failure("--dryrun --delivery foo install tox", "invalid choice: foo") cli.expect_failure("--dryrun uninstall --force /dev/null", "is not a valid pypi package name") cli.expect_success( "--dryrun uninstall --force -- this-package-does-not-exist ", "Nothing to uninstall") runez.touch("foo") assert os.path.exists("foo") cli.expect_failure("uninstall foo", "foo was not installed with pickley") cli.expect_success("uninstall foo --force", "Uninstalled foo") assert not os.path.exists("foo") assert runez.ensure_folder("foo", folder=True) == 1 cli.expect_failure("uninstall foo --force", "Can't automatically uninstall") cli.expect_failure("auto-upgrade foo", "not currently installed") cli.expect_failure("package foo/bar", "Folder", "does not exist") cli.expect_failure(["package", cli.context], "No setup.py") runez.touch(os.path.join(cli.context, "setup.py")) cli.expect_failure(["package", cli.context], "Could not determine package name") cli.expect_success("check", "No packages installed") cli.expect_success("list", "No packages installed") cli.expect_success("settings -d", "base: %s" % short(cli.context))
def uninstall_existing(target, fatal=True): """ :param str target: Path to executable to auto-uninstall if needed :param bool|None fatal: Abort execution on failure if True :return int: 1 if successfully uninstalled, 0 if nothing to do, -1 if failed """ handler = find_uninstaller(target) if handler: return handler(target, fatal=fatal) return runez.abort("Can't automatically uninstall %s", short(target), fatal=(fatal, -1))
def settings(diagnostics): """ Show settings """ if diagnostics: prefix = getattr(sys, "prefix", None) base_prefix = getattr(sys, "base_prefix", None) print("python : %s" % short(system.target_python(desired=system.INVOKER, fatal=None), meta=False)) print("sys.executable : %s" % short(sys.executable, meta=False)) print("sys.prefix : %s" % short(prefix, meta=False)) if base_prefix: print("sys.base_prefix: %s" % short(base_prefix, meta=False)) if not system.SETTINGS.meta.path.startswith( system.PICKLEY_PROGRAM_PATH): print("pickley : %s" % short(system.PICKLEY_PROGRAM_PATH, meta=False)) print("") print(system.SETTINGS.represented())
def package(self): """Package given python project""" if not self.desired.version and not self.source_folder: return runez.abort("Need either source_folder or version in order to package", fatal=(True, [])) if not self.desired.version: setup_py = os.path.join(self.source_folder, "setup.py") if not os.path.isfile(setup_py): return runez.abort("No setup.py in %s", short(self.source_folder), fatal=(True, [])) self.desired.version = None result = system.run_python(setup_py, "--version", dryrun=False, fatal=False, package_spec=self.package_spec) if result.succeeded: self.desired.version = result.output if not self.desired.version: return runez.abort("Could not determine version from %s", short(setup_py), fatal=(True, [])) self.pip_wheel() self.refresh_entry_points() self.packaged = [] template = "{name}" if self.source_folder else "{name}-{version}" self.effective_package(template)
def test_package(cli): result = system.run_python(os.path.join(PROJECT, "setup.py"), "--version") assert result.succeeded and result.output expected_version = result.output # Package pickley as venv cli.expect_success(["package", "-d", "dist", PROJECT], "Packaged %s successfully" % short(PROJECT)) # Verify that it packaged OK, and is relocatable pickley = os.path.abspath("dist/pickley/bin/pickley") assert runez.is_executable(pickley) assert run_program(pickley, "--version") == runez.program.RunResult( expected_version, "", 0)
def 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)
def move(source, destination): """ Copy file or folder, relocate venvs accordingly (if any) """ move_venv(source, destination) print("Moved %s -> %s" % (short(source), short(destination)))
def copy(source, destination): """ Copy file or folder, relocate venvs accordingly (if any) """ copy_venv(source, destination) print("Copied %s -> %s" % (short(source), short(destination)))