Skip to content
Merged
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
31 changes: 31 additions & 0 deletions src/enapter/cli/http/api/blueprint_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import argparse

from enapter import cli

from .blueprint_download_command import BlueprintDownloadCommand
from .blueprint_upload_command import BlueprintUploadCommand


class BlueprintCommand(cli.Command):

@staticmethod
def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"blueprint", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
subparsers = parser.add_subparsers(dest="blueprint_command", required=True)
for command in [
BlueprintDownloadCommand,
BlueprintUploadCommand,
]:
command.register(subparsers)

@staticmethod
async def run(args: argparse.Namespace) -> None:
match args.blueprint_command:
case "download":
await BlueprintDownloadCommand.run(args)
case "upload":
await BlueprintUploadCommand.run(args)
case _:
raise NotImplementedError(args.command_command)
36 changes: 36 additions & 0 deletions src/enapter/cli/http/api/blueprint_download_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import argparse
import logging
import pathlib

from enapter import cli, http

LOGGER = logging.getLogger(__name__)


class BlueprintDownloadCommand(cli.Command):

@staticmethod
def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"download", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("id", help="ID of the blueprint to download")
parser.add_argument(
"-o", "--output", type=pathlib.Path, help="Output file path", required=True
)
parser.add_argument(
"-v",
"--view",
choices=["original", "compiled"],
default="original",
help="Blueprint view type",
)

@staticmethod
async def run(args: argparse.Namespace) -> None:
async with http.api.Client(http.api.Config.from_env()) as client:
content = await client.blueprints.download(
args.id, view=http.api.blueprints.BlueprintView(args.view.upper())
)
with open(args.output, "wb") as f:
f.write(content)
29 changes: 29 additions & 0 deletions src/enapter/cli/http/api/blueprint_upload_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import argparse
import json
import logging
import pathlib

from enapter import cli, http

LOGGER = logging.getLogger(__name__)


class BlueprintUploadCommand(cli.Command):

@staticmethod
def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"upload", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"path", type=pathlib.Path, help="Path to a directory or a zip file"
)

@staticmethod
async def run(args: argparse.Namespace) -> None:
async with http.api.Client(http.api.Config.from_env()) as client:
if args.path.is_dir():
blueprint = await client.blueprints.upload_directory(args.path)
else:
blueprint = await client.blueprints.upload_file(args.path)
print(json.dumps(blueprint.to_dto()))
12 changes: 10 additions & 2 deletions src/enapter/cli/http/api/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from enapter import cli

from .blueprint_command import BlueprintCommand
from .command_command import CommandCommand
from .device_command import DeviceCommand
from .site_command import SiteCommand

Expand All @@ -13,16 +15,22 @@ def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"api", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
subparsers = parser.add_subparsers(dest="http_api_command", required=True)
subparsers = parser.add_subparsers(dest="api_command", required=True)
for command in [
BlueprintCommand,
CommandCommand,
DeviceCommand,
SiteCommand,
]:
command.register(subparsers)

@staticmethod
async def run(args: argparse.Namespace) -> None:
match args.http_api_command:
match args.api_command:
case "blueprint":
await BlueprintCommand.run(args)
case "command":
await CommandCommand.run(args)
case "device":
await DeviceCommand.run(args)
case "site":
Expand Down
11 changes: 11 additions & 0 deletions src/enapter/cli/http/api/command_arguments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import argparse
import json


def parse_command_arguments(arguments_string: str | None) -> dict:
if arguments_string is None:
return {}
try:
return json.loads(arguments_string)
except json.JSONDecodeError as e:
raise argparse.ArgumentTypeError(f"Decode JSON: {e.msg}")
39 changes: 39 additions & 0 deletions src/enapter/cli/http/api/command_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import argparse

from enapter import cli

from .command_create_execution_command import CommandCreateExecutionCommand
from .command_execute_command import CommandExecuteCommand
from .command_get_execution_command import CommandGetExecutionCommand
from .command_list_executions_command import CommandListExecutionsCommand


class CommandCommand(cli.Command):

@staticmethod
def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"command", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
subparsers = parser.add_subparsers(dest="command_command", required=True)
for command in [
CommandCreateExecutionCommand,
CommandExecuteCommand,
CommandGetExecutionCommand,
CommandListExecutionsCommand,
]:
command.register(subparsers)

@staticmethod
async def run(args: argparse.Namespace) -> None:
match args.command_command:
case "create-execution":
await CommandCreateExecutionCommand.run(args)
case "execute":
await CommandExecuteCommand.run(args)
case "get-execution":
await CommandGetExecutionCommand.run(args)
case "list-executions":
await CommandListExecutionsCommand.run(args)
case _:
raise NotImplementedError(args.command_command)
39 changes: 39 additions & 0 deletions src/enapter/cli/http/api/command_create_execution_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import argparse
import json
import logging

from enapter import cli, http

from .command_arguments import parse_command_arguments

LOGGER = logging.getLogger(__name__)


class CommandCreateExecutionCommand(cli.Command):

@staticmethod
def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"create-execution", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"-d",
"--device-id",
required=True,
help="ID or slug of the device to execute the command on",
)
parser.add_argument(
"-a",
"--arguments",
type=parse_command_arguments,
help="JSON string of arguments to pass to the command",
)
parser.add_argument("name", help="Name of the command to execute")

@staticmethod
async def run(args: argparse.Namespace) -> None:
async with http.api.Client(http.api.Config.from_env()) as client:
execution = await client.commands.create_execution(
device_id=args.device_id, name=args.name, arguments=args.arguments
)
print(json.dumps(execution.to_dto()))
48 changes: 48 additions & 0 deletions src/enapter/cli/http/api/command_execute_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import argparse
import json
import logging

from enapter import cli, http

from .command_arguments import parse_command_arguments

LOGGER = logging.getLogger(__name__)


class CommandExecuteCommand(cli.Command):

@staticmethod
def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"execute", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"-d",
"--device-id",
required=True,
help="ID or slug of the device to execute the command on",
)
parser.add_argument(
"-a",
"--arguments",
type=parse_command_arguments,
help="JSON string of arguments to pass to the command",
)
parser.add_argument(
"-l",
"--log",
action="store_true",
help="Expand command execution log in the output",
)
parser.add_argument("name", help="Name of the command to execute")

@staticmethod
async def run(args: argparse.Namespace) -> None:
async with http.api.Client(http.api.Config.from_env()) as client:
execution = await client.commands.execute(
device_id=args.device_id,
name=args.name,
arguments=args.arguments,
expand_log=args.log,
)
print(json.dumps(execution.to_dto()))
41 changes: 41 additions & 0 deletions src/enapter/cli/http/api/command_get_execution_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import argparse
import json
import logging

from enapter import cli, http

LOGGER = logging.getLogger(__name__)


class CommandGetExecutionCommand(cli.Command):

@staticmethod
def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"get-execution", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"-d",
"--device-id",
required=True,
help="ID or slug of the device to get the command execution of",
)
parser.add_argument(
"-l",
"--log",
action="store_true",
help="Expand command execution log in the output",
)
parser.add_argument(
"execution_id", help="ID of the command execution to retrieve"
)

@staticmethod
async def run(args: argparse.Namespace) -> None:
async with http.api.Client(http.api.Config.from_env()) as client:
execution = await client.commands.get_execution(
device_id=args.device_id,
execution_id=args.execution_id,
expand_log=args.log,
)
print(json.dumps(execution.to_dto()))
49 changes: 49 additions & 0 deletions src/enapter/cli/http/api/command_list_executions_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import argparse
import json

from enapter import cli, http


class CommandListExecutionsCommand(cli.Command):

@staticmethod
def register(parent: cli.Subparsers) -> None:
parser = parent.add_parser(
"list-executions", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"-l",
"--limit",
type=int,
help="Maximum number of command executions to list",
default=-1,
)
parser.add_argument(
"-o",
"--order",
choices=["created_at_asc", "created_at_desc"],
help="Order of the listed command executions",
default="created_at_asc",
)
parser.add_argument(
"-d",
"--device-id",
help="ID or slug of the device to list command executions for",
required=True,
)

@staticmethod
async def run(args: argparse.Namespace) -> None:
if args.limit == 0:
return
async with http.api.Client(http.api.Config.from_env()) as client:
async with client.commands.list_executions(
device_id=args.device_id,
order=http.api.commands.ListExecutionsOrder(args.order.upper()),
) as stream:
count = 0
async for device in stream:
print(json.dumps(device.to_dto()))
count += 1
if args.limit > 0 and count == args.limit:
break
Loading