diff --git a/.gitea/workflows/package.yaml b/.gitea/workflows/package.yaml index f4a6d0ce..8db3a1eb 100644 --- a/.gitea/workflows/package.yaml +++ b/.gitea/workflows/package.yaml @@ -36,6 +36,12 @@ jobs: echo "Set version to $(cat /workspace/sh-edraft.de/cpl/version.txt)" cat pyproject.toml + - name: Set package version + run: | + sed -i -E "s/^__version__ = \".*\"/__version__ = \"$(cat /workspace/sh-edraft.de/cpl/version.txt)\"/" cpl/*/__init__.py + echo "Set version to $(cat /workspace/sh-edraft.de/cpl/version.txt)" + cat cpl/*/__init__.py + - name: Set pip conf run: | cat > .pip.conf <<'EOF' diff --git a/src/cpl-cli/cpl/cli/__init__.py b/src/cpl-cli/cpl/cli/__init__.py index e69de29b..5becc17c 100644 --- a/src/cpl-cli/cpl/cli/__init__.py +++ b/src/cpl-cli/cpl/cli/__init__.py @@ -0,0 +1 @@ +__version__ = "1.0.0" diff --git a/src/cpl-cli/cpl/cli/command/version.py b/src/cpl-cli/cpl/cli/command/version.py new file mode 100644 index 00000000..5709f43a --- /dev/null +++ b/src/cpl-cli/cpl/cli/command/version.py @@ -0,0 +1,27 @@ +import platform + +import cpl +from cpl.cli.cli import cli +from cpl.cli.utils.pip import Pip +from cpl.core.console import Console, ForegroundColorEnum + + +@cli.command("version", aliases=["v"]) +def version(): + Console.set_foreground_color(ForegroundColorEnum.yellow) + Console.banner("CPL CLI") + Console.set_foreground_color(ForegroundColorEnum.default) + + Console.write_line() + Console.write_line(f"CPL CLI: {getattr(cpl.cli, '__version__', "1.0")}") + Console.write_line(f"Python: {platform.python_version()}") + Console.write_line(f"PIP: {Pip.get_pip_version()}") + Console.write_line(f"OS: {platform.system()} {platform.release()}") + + Console.write_line("\nCPL Packages:\n") + cpl_packages = {n: v for n, v in Pip.get_packages().items() if n.startswith("cpl-")} + if len(cpl_packages) == 0: + Console.write_line("No CPL packages installed") + return + + Console.table(["Package", "Version"], [[n, v] for n, v in cpl_packages.items()]) diff --git a/src/cpl-cli/cpl/cli/main.py b/src/cpl-cli/cpl/cli/main.py index 5f7357de..69a1e0c8 100644 --- a/src/cpl-cli/cpl/cli/main.py +++ b/src/cpl-cli/cpl/cli/main.py @@ -6,6 +6,7 @@ from cpl.cli.command.init import init from cpl.cli.command.install import install from cpl.cli.command.uninstall import uninstall from cpl.cli.command.update import update +from cpl.cli.command.version import version from cpl.cli.model.workspace import Workspace from cpl.cli.utils.custom_command import script_command from cpl.core.configuration import Configuration @@ -42,10 +43,23 @@ def prepare(): def configure(): + # cli + cli.add_command(version) + + # structure cli.add_command(init) + # cli.add_command(new) + + # packaging cli.add_command(install) cli.add_command(uninstall) cli.add_command(update) + # cli.add_command(add) + # cli.add_command(remove) + + # run + # cli.add_command(run) + # cli.add_command(start) def main(): diff --git a/src/cpl-cli/cpl/cli/utils/pip.py b/src/cpl-cli/cpl/cli/utils/pip.py index aa3da223..5c00eb92 100644 --- a/src/cpl-cli/cpl/cli/utils/pip.py +++ b/src/cpl-cli/cpl/cli/utils/pip.py @@ -29,7 +29,7 @@ class Pip: for prefix, pip_op in table.items(): if raw.startswith(prefix): op = pip_op - raw = raw[len(prefix):] + raw = raw[len(prefix) :] break return f"{name}{op}{raw}" @@ -48,7 +48,7 @@ class Pip: return f"~{installed}" op = m.group(1) - rest = s[m.end():].strip() + rest = s[m.end() :].strip() if "," in rest: rest = rest.split(",", 1)[0].strip() if " " in rest: @@ -59,7 +59,7 @@ class Pip: installed_parts = [p for p in installed.split(".") if p != ""] if orig_version: orig_parts = [p for p in orig_version.split(".") if p != ""] - trimmed_installed = ".".join(installed_parts[:len(orig_parts)]) or installed + trimmed_installed = ".".join(installed_parts[: len(orig_parts)]) or installed else: trimmed_installed = installed @@ -96,8 +96,8 @@ class Pip: return spec.replace(package_name, "").strip() or None @staticmethod - def command(command: str, *args,verbose:bool=False, path: str=None): - venv_path = ensure_venv(Path(path or './')) + def command(command: str, *args, verbose: bool = False, path: str = None): + venv_path = ensure_venv(Path(path or "./")) pip = get_venv_pip(venv_path) if verbose: @@ -113,8 +113,8 @@ class Pip: ) @staticmethod - def get_package_version(package: str, path: str=None) -> str | None: - venv_path = ensure_venv(Path(path or './')) + def get_package_version(package: str, path: str = None) -> str | None: + venv_path = ensure_venv(Path(path or "./")) pip = get_venv_pip(venv_path) try: @@ -132,4 +132,45 @@ class Pip: except subprocess.CalledProcessError: return None - return None \ No newline at end of file + return None + + @staticmethod + def get_packages(path: str = None): + venv_path = ensure_venv(Path(path or "./")) + pip = get_venv_pip(venv_path) + try: + result = subprocess.run( + f"{pip} list --format=freeze", + shell=True, + check=True, + capture_output=True, + text=True, + stdin=subprocess.DEVNULL, + ) + packages = {} + for line in result.stdout.splitlines(): + if "==" in line: + name, version = line.split("==", 1) + packages[name] = version + return packages + except subprocess.CalledProcessError: + return {} + + @staticmethod + def get_pip_version(path: str = None) -> str | None: + venv_path = ensure_venv(Path(path or "./")) + pip = get_venv_pip(venv_path) + + try: + result = subprocess.run( + f"{pip} --version", + shell=True, + check=True, + capture_output=True, + text=True, + stdin=subprocess.DEVNULL, + ) + version = result.stdout.split()[1] + return version + except subprocess.CalledProcessError: + return None diff --git a/src/cpl-core/cpl/core/__init__.py b/src/cpl-core/cpl/core/__init__.py index e69de29b..5becc17c 100644 --- a/src/cpl-core/cpl/core/__init__.py +++ b/src/cpl-core/cpl/core/__init__.py @@ -0,0 +1 @@ +__version__ = "1.0.0" diff --git a/src/cpl-core/cpl/core/console/_spinner.py b/src/cpl-core/cpl/core/console/_spinner.py index 74fab96a..a9f28ab2 100644 --- a/src/cpl-core/cpl/core/console/_spinner.py +++ b/src/cpl-core/cpl/core/console/_spinner.py @@ -1,4 +1,5 @@ import os +import shutil import sys import multiprocessing import time @@ -56,9 +57,8 @@ class Spinner(Process): if sys.platform == "win32": columns = os.get_terminal_size().columns else: - values = os.popen("stty size", "r").read().split() - term_rows, term_columns = values if len(values) == 2 else (0, 0) - columns = int(term_columns) + size = shutil.get_terminal_size(fallback=(80, 24)) + columns = max(1, size.columns) end_msg = "done" diff --git a/src/cpl-core/cpl/core/console/console.py b/src/cpl-core/cpl/core/console/console.py index ce764832..86e6fa9c 100644 --- a/src/cpl-core/cpl/core/console/console.py +++ b/src/cpl-core/cpl/core/console/console.py @@ -1,4 +1,5 @@ import os +import shutil import sys import time from collections.abc import Callable @@ -251,6 +252,25 @@ class Console: Console.read() sys.exit() + @classmethod + def divider(cls, char: str = "-"): + r"""Prints a divider line + + Parameter: + char: :class:`str` + Character to use for the divider + """ + if cls._disabled: + return + + if cls._hold_back: + cls._hold_back_calls.append(ConsoleCall(cls.divider, char)) + return + + size = shutil.get_terminal_size(fallback=(80, 24)) + columns = max(1, size.columns) + cls.write_line(char * columns) + @classmethod def disable(cls): r"""Disables console interaction"""