diff --git a/CHANGELOG.md b/CHANGELOG.md index 81f89ddd..96359ff9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The client here will eventually be released as "spython" (and eventually to singularity on pypi), and the versions here will coincide with these releases. ## [master](https://github.com/singularityhub/singularity-cli/tree/master) + - client should support shell (0.0.67) - adding test for entrypoint + cmd and fixing testing requirements (0.0.66) - fixing bug that inspect does not honor quiet (0.0.65) - refactor recipe parsers, writers, and base (0.0.64) diff --git a/spython/main/__init__.py b/spython/main/__init__.py index 9aa197fb..ea98c221 100644 --- a/spython/main/__init__.py +++ b/spython/main/__init__.py @@ -26,7 +26,7 @@ def get_client(quiet=False, debug=False): # Do imports here, can be customized from .apps import apps from .build import build - from .execute import execute + from .execute import (execute, shell) from .help import helpcmd from .inspect import inspect from .instances import (list_instances, stopall) # global instance commands @@ -44,6 +44,7 @@ def get_client(quiet=False, debug=False): client.inspect = inspect client.instances = list_instances client.run = run + client.shell = shell client.pull = pull # Command Groups, Images diff --git a/spython/main/build.py b/spython/main/build.py index 15d29272..b47587f6 100644 --- a/spython/main/build.py +++ b/spython/main/build.py @@ -18,7 +18,7 @@ def build(self, recipe=None, writable=False, build_folder=None, robot_name=False, - ext='simg', + ext='sif', sudo=True, stream=False, force=False): diff --git a/spython/main/execute.py b/spython/main/execute.py index a58b347b..2e29bf62 100644 --- a/spython/main/execute.py +++ b/spython/main/execute.py @@ -7,8 +7,12 @@ from spython.logger import bot -from spython.utils import stream_command +from spython.utils import ( + stream_command, + which +) +import os def execute(self, image=None, @@ -19,7 +23,9 @@ def execute(self, bind=None, stream=False, nv=False, - return_result=False): + return_result=False, + sudo=False, + quiet=True): ''' execute: send a command to a container Parameters @@ -75,7 +81,6 @@ def execute(self, if app is not None: cmd = cmd + ['--app', app] - sudo = False if writable: sudo = True @@ -87,7 +92,60 @@ def execute(self, if not stream: return self._run_command(cmd, sudo=sudo, - return_result=return_result) + return_result=return_result, + quiet=quiet) return stream_command(cmd, sudo=sudo) bot.error('Please include a command (list) to execute.') + + +def shell(self, + image, + app=None, + writable=False, + contain=False, + bind=None, + nv=False, + sudo=False): + ''' shell into a container. A user is advised to use singularity to do + this directly, however this function is useful for supporting tools. + + Parameters + ========== + + image: full path to singularity image + app: if not None, execute a shell in context of an app + writable: This option makes the file system accessible as read/write + contain: This option disables the automatic sharing of writable + filesystems on your host + bind: list or single string of bind paths. + This option allows you to map directories on your host system to + directories within your container using bind mounts + nv: if True, load Nvidia Drivers in runtime (default False) + ''' + from spython.utils import check_install + check_install() + + cmd = self._init_command('shell') + + # nv option leverages any GPU cards + if nv: + cmd += ['--nv'] + + # Does the user want to use bind paths option? + if bind is not None: + cmd += self._generate_bind_list(bind) + + # Does the user want to run an app? + if app is not None: + cmd = cmd + ['--app', app] + + # Finally, add the image or uri + cmd.append(image) + singularity = which('singularity') + + if writable or sudo: + os.execvp("sudo", ["sudo"] + cmd) + + else: + os.execvp(singularity, cmd) diff --git a/spython/main/instances.py b/spython/main/instances.py index d78babc9..e7b54df3 100644 --- a/spython/main/instances.py +++ b/spython/main/instances.py @@ -9,7 +9,7 @@ from spython.logger import bot from spython.utils import run_command -def list_instances(self, name=None, return_json=False, quiet=False): +def list_instances(self, name=None, return_json=False, quiet=False, sudo=False): '''list instances. For Singularity, this is provided as a command sub group. @@ -44,7 +44,7 @@ def list_instances(self, name=None, return_json=False, quiet=False): if name is not None: cmd.append(name) - output = run_command(cmd, quiet=True) + output = run_command(cmd, quiet=True, sudo=sudo) instances = [] # Success, we have instances diff --git a/spython/utils/__init__.py b/spython/utils/__init__.py index d510b57d..19868898 100644 --- a/spython/utils/__init__.py +++ b/spython/utils/__init__.py @@ -10,12 +10,13 @@ from .terminal import ( check_install, + format_container_name, get_installdir, get_singularity_version, get_singularity_version_info, - stream_command, + remove_uri, run_command, - format_container_name, + stream_command, split_uri, - remove_uri + which ) diff --git a/spython/utils/terminal.py b/spython/utils/terminal.py index 1c2c6a5f..40a4b19f 100644 --- a/spython/utils/terminal.py +++ b/spython/utils/terminal.py @@ -46,6 +46,14 @@ def check_install(software='singularity', quiet=True): return found +def which(software='singularity'): + '''which returns the full path to where software is installed. + ''' + cmd = ['which', software] + result = run_command(cmd, quiet=True)['message'][0] + return result.strip('\n') + + def get_singularity_version(): '''get the full singularity client version as reported by singularity --version [...]. For Singularity 3.x, this means: @@ -173,8 +181,6 @@ def run_command(cmd, ################################################################################ - - def format_container_name(name, special_characters=None): '''format_container_name will take a name supplied by the user, remove all special characters (except for those defined by "special-characters" diff --git a/spython/version.py b/spython/version.py index 6c707108..d4de8709 100644 --- a/spython/version.py +++ b/spython/version.py @@ -6,7 +6,7 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -__version__ = "0.0.66" +__version__ = "0.0.67" AUTHOR = 'Vanessa Sochat' AUTHOR_EMAIL = 'vsochat@stanford.edu' NAME = 'spython' @@ -21,6 +21,4 @@ TESTS_REQUIRES = ( ('pytest', {'min_version': '4.6.2'}), - ('pytest-cov', {'min_version': '2.5.1'}), - ('pytest-fixtures', {'min_version': '0.1.0'}), )