Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
)
from jumpstarter_kubernetes import (
V1Alpha1Client,
V1Alpha1ClientList,
V1Alpha1Exporter,
V1Alpha1ExporterList,
V1Alpha1Lease,
V1Alpha1List,
V1Alpha1LeaseList,
)

CLIENT_COLUMNS = ["NAME", "ENDPOINT", "AGE"]
Expand All @@ -34,7 +36,7 @@ def print_client(client: V1Alpha1Client, output: OutputType):
click.echo(make_table(CLIENT_COLUMNS, [make_client_row(client)]))


def print_clients(clients: V1Alpha1List[V1Alpha1Client], namespace: str, output: OutputType):
def print_clients(clients: V1Alpha1ClientList, namespace: str, output: OutputType):
if output == OutputMode.JSON:
click.echo(clients.dump_json())
elif output == OutputMode.YAML:
Expand Down Expand Up @@ -98,7 +100,7 @@ def print_exporter(exporter: V1Alpha1Exporter, devices: bool, output: OutputType
click.echo(make_table(EXPORTER_COLUMNS, [make_exporter_row(exporter)]))


def print_exporters(exporters: V1Alpha1List[V1Alpha1Exporter], namespace: str, devices: bool, output: OutputType):
def print_exporters(exporters: V1Alpha1ExporterList, namespace: str, devices: bool, output: OutputType):
if output == OutputMode.JSON:
click.echo(exporters.dump_json())
elif output == OutputMode.YAML:
Expand Down Expand Up @@ -164,7 +166,7 @@ def print_lease(lease: V1Alpha1Lease, output: OutputType):
click.echo(make_table(LEASE_COLUMNS, [make_lease_row(lease)]))


def print_leases(leases: V1Alpha1List[V1Alpha1Lease], namespace: str, output: OutputType):
def print_leases(leases: V1Alpha1LeaseList, namespace: str, output: OutputType):
if output == OutputMode.JSON:
click.echo(leases.dump_json())
elif output == OutputMode.YAML:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ class OutputMode(str):
YAML = "yaml"
NAME = "name"
PATH = "path"
WIDE = "wide"


OutputType = Optional[OutputMode]

opt_output_all = click.option(
"-o",
"--output",
type=click.Choice([OutputMode.JSON, OutputMode.YAML, OutputMode.NAME]),
type=click.Choice([OutputMode.JSON, OutputMode.YAML, OutputMode.NAME, OutputMode.WIDE]),
default=None,
help='Output mode. Use "-o name" for shorter output (resource/name).',
)
Expand Down
1 change: 0 additions & 1 deletion packages/jumpstarter-cli-driver/README.md

This file was deleted.

24 changes: 0 additions & 24 deletions packages/jumpstarter-cli-driver/jumpstarter_cli_driver/__init__.py

This file was deleted.

13 changes: 0 additions & 13 deletions packages/jumpstarter-cli-driver/jumpstarter_cli_driver/driver.py

This file was deleted.

This file was deleted.

1 change: 1 addition & 0 deletions packages/jumpstarter-cli-pkg/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Jumpstarter Package Management CLI
17 changes: 17 additions & 0 deletions packages/jumpstarter-cli-pkg/jumpstarter_cli_pkg/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import asyncclick as click
from jumpstarter_cli_common import AliasedGroup

from .commands.list import list
from .commands.show import show


@click.group(cls=AliasedGroup)
def pkg():
"""Jumpstarter package management CLI tool"""


pkg.add_command(list)
pkg.add_command(show)

if __name__ == "__main__":
pkg()
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Allow running Jumpstarter through `python -m jumpstarter_cli_driver`."""
"""Allow running Jumpstarter through `python -m jumpstarter_cli_pkg`."""

from . import driver
from . import pkg

if __name__ == "__main__":
driver(prog_name="jmp-driver")
pkg(prog_name="jmp-pkg")
178 changes: 178 additions & 0 deletions packages/jumpstarter-cli-pkg/jumpstarter_cli_pkg/commands/list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import re
from typing import Optional

import asyncclick as click
from jumpstarter_cli_common import opt_output_all
from jumpstarter_cli_common.exceptions import handle_exceptions
from jumpstarter_cli_common.opt import OutputMode, OutputType
from jumpstarter_cli_common.table import make_table

from ..opt import opt_adapters, opt_driver_clients, opt_drivers, opt_inspect
from ..repository import (
LocalDriverRepository,
V1Alpha1AdapterEntryPointList,
V1Alpha1DriverClientEntryPointList,
V1Alpha1DriverEntryPointList,
V1Alpha1DriverPackageList,
)

MAX_SUMMARY_LENGTH = 100


def clean_truncate_summary(summary: Optional[str]):
if summary is None:
return ""
# Get only the first line
first_line = summary.split("\n")[0].strip()
# Strip markdown formatting
cleaned_summary = re.sub(r"[#*_~`\[\]\(\)\{}]", "", first_line) # Remove markdown characters
# Truncate if necessary
truncated_summary = cleaned_summary[:MAX_SUMMARY_LENGTH] + (
"..." if len(cleaned_summary) > MAX_SUMMARY_LENGTH else ""
)
return truncated_summary


def print_packages(packages: V1Alpha1DriverPackageList, output: OutputType):
match output:
case OutputMode.JSON:
click.echo(packages.dump_json())
case OutputMode.YAML:
click.echo(packages.dump_yaml())
case OutputMode.NAME:
for package in packages.items:
click.echo(f"package.jumpstarter.dev/{package.name}")
case _:
if output == OutputMode.WIDE:
columns = ["NAME", "VERSION", "INSTALLED", "CATEGORIES", "LICENSE", "SUMMARY"]
else:
columns = ["NAME", "VERSION", "INSTALLED", "CATEGORIES"]
driver_rows = []
for package in packages.items:
driver_rows.append(
{
"INSTALLED": "Yes" if package.installed else "No",
"NAME": package.name,
"VERSION": package.version,
"CATEGORIES": ",".join(package.categories),
"LICENSE": package.license if package.license else "Unspecified",
"SUMMARY": clean_truncate_summary(package.summary),
}
)
click.echo(make_table(columns, driver_rows))


def print_drivers(packages: V1Alpha1DriverPackageList, output: OutputType, inspect: bool):
drivers = V1Alpha1DriverEntryPointList()
for package in packages.items:
for driver in package.drivers.items:
drivers.items.append(driver)
match output:
case OutputMode.JSON:
click.echo(drivers.dump_json())
case OutputMode.YAML:
click.echo(drivers.dump_yaml())
case OutputMode.NAME:
for driver in drivers.items:
click.echo(f"driver.jumpstarter.dev/{driver.package}/{driver.name}")
case _:
if output == OutputMode.WIDE and inspect:
columns = ["NAME", "PACKAGE", "TYPE", "CLIENT", "SUMMARY"]
else:
columns = ["NAME", "PACKAGE", "TYPE"]
driver_rows = []
for driver in drivers.items:
driver_rows.append(
{
"NAME": driver.name,
"PACKAGE": driver.package,
"TYPE": driver.type,
"CLIENT": driver.client_type if driver.client_type else "",
"SUMMARY": clean_truncate_summary(driver.summary),
}
)
click.echo(make_table(columns, driver_rows))


def print_driver_clients(packages: V1Alpha1DriverPackageList, output: OutputType):
driver_clients = V1Alpha1DriverClientEntryPointList()
for package in packages.items:
for client in package.driver_clients.items:
driver_clients.items.append(client)
match output:
case OutputMode.JSON:
click.echo(driver_clients.dump_json())
case OutputMode.YAML:
click.echo(driver_clients.dump_yaml())
case OutputMode.NAME:
for client in driver_clients.items:
click.echo(f"client.jumpstarter.dev/{client.package}/{client.name}")
case _:
if output == OutputMode.WIDE:
columns = ["NAME", "PACKAGE", "TYPE", "SUMMARY"]
else:
columns = ["NAME", "PACKAGE", "TYPE"]
driver_client_rows = []
for client in driver_clients.items:
driver_client_rows.append(
{
"NAME": client.name,
"PACKAGE": client.package,
"TYPE": client.type,
"SUMMARY": clean_truncate_summary(client.summary),
}
)
click.echo(make_table(columns, driver_client_rows))


def print_adapters(packages: V1Alpha1DriverPackageList, output: OutputType):
adapters = V1Alpha1AdapterEntryPointList()
for package in packages.items:
for adapter in package.adapters.items:
adapters.items.append(adapter)
match output:
case OutputMode.JSON:
click.echo(adapters.dump_json())
case OutputMode.YAML:
click.echo(adapters.dump_yaml())
case OutputMode.NAME:
for adapter in adapters.items:
click.echo(f"adapter.jumpstarter.dev/{adapter.package}/{adapter.name}")
case _:
if output == OutputMode.WIDE:
columns = ["NAME", "PACKAGE", "TYPE"]
else:
columns = ["NAME", "PACKAGE", "TYPE"]
adapter_rows = []
for adapter in adapters.items:
adapter_rows.append({"NAME": adapter.name, "PACKAGE": adapter.package, "TYPE": adapter.type})
click.echo(make_table(columns, adapter_rows))


@click.command("list")
@opt_drivers
@opt_driver_clients
@opt_adapters
@opt_inspect
@opt_output_all
@handle_exceptions
def list(output: OutputType, drivers: bool, driver_clients: bool, adapters: bool, inspect: bool):
"""List available Jumpstarter packages."""
# Add validation to ensure only one flag is set
if sum([drivers, driver_clients, adapters]) > 1:
raise click.UsageError("Only one of --drivers, --driver-clients, or --adapters can be specified.")
# Print loading message for text outputs
if output is None or output == OutputMode.WIDE:
click.echo("Fetching local packages for current Python environment")
# Load the packages from the local environment
local_repo = LocalDriverRepository.from_venv()
local_packages = local_repo.list_packages(inspect)
# Print specified output
if drivers:
print_drivers(local_packages, output, inspect)
elif driver_clients:
print_driver_clients(local_packages, output)
elif adapters:
print_adapters(local_packages, output)
else:
print_packages(local_packages, output)
Loading
Loading