diff --git a/src/kiwi/runner.py b/src/kiwi/runner.py index 1561c30..a783382 100644 --- a/src/kiwi/runner.py +++ b/src/kiwi/runner.py @@ -13,7 +13,9 @@ from .subcommands import * SUBCOMMANDS = [ InitCommand, ShowCommand, - LogsCommand + LogsCommand, + CmdCommand, + ShellCommand ] diff --git a/src/kiwi/subcommands/__init__.py b/src/kiwi/subcommands/__init__.py index 63c7d4c..9b026d7 100644 --- a/src/kiwi/subcommands/__init__.py +++ b/src/kiwi/subcommands/__init__.py @@ -2,9 +2,13 @@ from .init import InitCommand from .logs import LogsCommand from .show import ShowCommand +from .cmd import CmdCommand +from .shell import ShellCommand __all__ = [ 'InitCommand', 'LogsCommand', - 'ShowCommand' + 'ShowCommand', + 'CmdCommand', + 'ShellCommand' ] diff --git a/src/kiwi/subcommands/_subcommand.py b/src/kiwi/subcommands/_subcommand.py index cd84a26..653c9fe 100644 --- a/src/kiwi/subcommands/_subcommand.py +++ b/src/kiwi/subcommands/_subcommand.py @@ -43,13 +43,13 @@ class ProjectCommand(SubCommand): class ServiceCommand(ProjectCommand): """this command concerns services in a project""" - def __init__(self, name, **kwargs): + def __init__(self, name, nargs='*', **kwargs): super().__init__( name, **kwargs ) self._sub_parser.add_argument( - 'services', metavar='service', nargs='*', type=str, + 'services', metavar='service', nargs=nargs, type=str, help="select service(s) in a project" ) diff --git a/src/kiwi/subcommands/cmd.py b/src/kiwi/subcommands/cmd.py new file mode 100644 index 0000000..52cb6ff --- /dev/null +++ b/src/kiwi/subcommands/cmd.py @@ -0,0 +1,29 @@ +# system +import logging + +# local +from ._subcommand import ProjectCommand +from .utils.dockercommand import DockerCommand + + +class CmdCommand(ProjectCommand): + def __init__(self): + super().__init__( + 'cmd', + description="Run raw docker-compose command in a project" + ) + + # arguments for docker-compose command + self._sub_parser.add_argument( + 'compose_cmd', metavar='cmd', type=str, + help="runs `docker-compose " + ) + + def run(self, config, args): + try: + import shlex + DockerCommand('docker-compose').run(config, args, shlex.split(args.compose_cmd)) + + except KeyboardInterrupt: + logging.debug("Subprocess aborted.") + print() diff --git a/src/kiwi/subcommands/shell.py b/src/kiwi/subcommands/shell.py new file mode 100644 index 0000000..8622c89 --- /dev/null +++ b/src/kiwi/subcommands/shell.py @@ -0,0 +1,57 @@ +# system +import logging +import subprocess + +# local +from ._subcommand import ServiceCommand +from .utils.dockercommand import DockerCommand + + +def _service_has_shell(config, args, exec_service, try_shell): + try: + # test if desired shell exists + DockerCommand('docker-compose').run( + config, args, [*exec_service, '/bin/sh', '-c', f"which {try_shell}"], + check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL + ) + return True + + except subprocess.CalledProcessError: + # fallback + logging.info(f"Shell '{try_shell}' not found in container") + return False + + +class ShellCommand(ServiceCommand): + def __init__(self): + super().__init__( + 'sh', 1, + description="Spawn shell inside project's service" + ) + + # -s switch: Select shell + self._sub_parser.add_argument( + '-s', '--shell', type=str, default="/bin/bash", + help="shell to spawn" + ) + + def run(self, config, args): + try: + exec_service = ['exec', args.services[0]] + exec_shell = args.shell + + if not _service_has_shell(config, args, exec_service, exec_shell): + # fallback + exec_shell = '/bin/bash' + + if not _service_has_shell(config, args, exec_service, exec_shell): + exec_shell = '/bin/sh' + + # spawn shell + DockerCommand('docker-compose').run( + config, args, [*exec_service, exec_shell] + ) + + except KeyboardInterrupt: + logging.debug("Subprocess aborted.") + print()