Source code for buildtest.utils.shell

import shutil

from buildtest.exceptions import BuildTestError


[docs]class Shell: valid_shells = [ "bash", "sh", "zsh", "csh", "tcsh", "/bin/bash", "/bin/csh", "/bin/sh", "/bin/tcsh", "/bin/zsh", "python", ] def __init__(self, shell="bash"): """The Shell initializer takes an input shell and shell options and split string by shell name and options. Args: shell (str): Specify shell program and any options passed to shell. Defaults to ``bash`` """ # enforce input argument 'shell' to be a string if not isinstance(shell, str): raise BuildTestError( f"Invalid type for input: {shell} must be of type 'str'" ) self.name = shell.split()[0] # if input shell is not in list of valid shells we raise error. if self.name not in self.valid_shells: raise BuildTestError( f"Invalid shell: {self.name} select from one of the following shells: {self.valid_shells}" ) self._opts = " ".join(shell.split()[1:]) self.path = self.name @property def opts(self): """retrieve the shell opts that are set on init, and updated with setter""" return self._opts @opts.setter def opts(self, shell_opts): """Override the shell options in class attribute, this would be useful when shell options need to change due to change in shell program. """ self._opts = shell_opts return self._opts @property def path(self): """This method returns the full path to shell program using ``shutil.which()`` If shell program is not found we raise an exception. The shebang is is updated assuming path is valid which is just adding character '#!' in front of path. The return is full path to shell program. This method automatically updates the shell path when there is a change in attribute self.name >>> shell = Shell("bash") >>> shell.path '/usr/bin/bash' >>> shell.name="sh" >>> shell.path '/usr/bin/sh' """ return self._path # Identity functions
[docs] def __str__(self): return "[buildtest.shell][%s]" % self.name
[docs] def __repr__(self): return self.__str__()
@path.setter def path(self, name): """If the user provides a new path with a name, do same checks to ensure that it's found. """ path = shutil.which(name) # raise an exception if shell program is not found if not path: raise BuildTestError(f"Can't find program: {name}") # Update the name not that we are sure path is found self.name = name # if input shell is not in list of valid shells we raise error. if self.name not in self.valid_shells: raise BuildTestError( f"Please select one of the following shells: {self.valid_shells}" ) self._path = path # shebang is formed by adding the char '#!' with path to program self.shebang = f"#!{path}"
[docs] def get(self): """Return shell attributes as a dictionary""" return { "name": self.name, "opts": self._opts, "path": self._path, "shebang": self.shebang, }