Skip to content
Open
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
65 changes: 37 additions & 28 deletions cotainr/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,34 +223,43 @@ def execute(self):
with container.SingularitySandbox(
base_image=self.base_image, log_settings=self.log_settings
) as sandbox:
if self.conda_env is not None:
# Install supplied conda env
logger.info("Installing Conda environment: %s", self.conda_env)
conda_env_name = "conda_container_env"
conda_env_file = sandbox.sandbox_dir / self.conda_env.name
shutil.copyfile(self.conda_env, conda_env_file)
conda_install = pack.CondaInstall(
sandbox=sandbox,
license_accepted=self.accept_licenses,
log_settings=self.log_settings,
)
conda_install.add_environment(
path=conda_env_file, name=conda_env_name
)

sandbox.add_to_env(shell_script=f"conda activate {conda_env_name}")

# Clean-up unused files
logger.info("Cleaning up unused Conda files")
conda_install.cleanup_unused_files()
logger.info(
"Finished installing conda environment: %s", self.conda_env
)

logger.info("Adding metadata to container")
sandbox.add_metadata()
logger.info("Building container image")
sandbox.build_image(path=self.image_path)
try:
if self.conda_env is not None:
# Install supplied conda env
logger.info("Installing Conda environment: %s", self.conda_env)
conda_env_name = "conda_container_env"
conda_env_file = sandbox.sandbox_dir / self.conda_env.name
shutil.copyfile(self.conda_env, conda_env_file)
conda_install = pack.CondaInstall(
sandbox=sandbox,
license_accepted=self.accept_licenses,
log_settings=self.log_settings,
)
conda_install.add_environment(
path=conda_env_file, name=conda_env_name
)

sandbox.add_to_env(
shell_script=f"conda activate {conda_env_name}"
)

# Clean-up unused files
logger.info("Cleaning up unused Conda files")
conda_install.cleanup_unused_files()
logger.info(
"Finished installing conda environment: %s", self.conda_env
)

logger.info("Adding metadata to container")
sandbox.add_metadata()
logger.info("Building container image")
sandbox.build_image(path=self.image_path)
except subprocess.CalledProcessError:
if self.log_settings.verbosity < 5:
logger.error(
"Tip: Attempt the cotainer build with increased verbosity using -v(vvvv) for more information"
)
sys.exit(0)

t_end_build = time.time()
logger.info(
Expand Down
19 changes: 12 additions & 7 deletions cotainr/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,14 +262,19 @@ def run_command_in_container(self, *, cmd, custom_log_dispatcher=None):
]
),
)
except subprocess.CalledProcessError as e:
singularity_fatal_error = "\n".join(
[line for line in e.stderr.split("\n") if line.startswith("FATAL")]
except subprocess.CalledProcessError:
if custom_log_dispatcher is None:
error_logger = self.log_dispatcher.logger_stderr

else:
error_logger = custom_log_dispatcher.logger_stderr

name = error_logger.name.split(".")[0]
logger.error(
f"An error occurred in the {name} subprocess when running cmd:"
)
raise ValueError(
f"Invalid command {cmd=} passed to Singularity "
f"resulted in the FATAL error: {singularity_fatal_error}"
) from e
logger.error(cmd)
raise

return process

Expand Down
14 changes: 9 additions & 5 deletions cotainr/tests/container/test_singularity_sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,17 @@ def test_correct_umask(self, data_cached_alpine_sif, context_set_umask):
test_file_permissions = test_file_mode & 0o777
assert oct(test_file_permissions) == "0o644"

def test_error_handling(self, data_cached_alpine_sif):
def test_error_handling(self, data_cached_alpine_sif, capsys):
from subprocess import CalledProcessError

cmd = "some6021 non-meaningful command"
with SingularitySandbox(base_image=data_cached_alpine_sif) as sandbox:
with pytest.raises(
ValueError, match=f"^Invalid command {cmd=} passed to Singularity"
):
with SingularitySandbox(
base_image=data_cached_alpine_sif, log_settings=LogSettings()
) as sandbox:
with pytest.raises(CalledProcessError):
sandbox.run_command_in_container(cmd=cmd)
stderr = capsys.readouterr().err
assert '"some6021": executable file not found in $PATH\n' in stderr

def test_no_home(self, data_cached_alpine_sif):
with SingularitySandbox(base_image=data_cached_alpine_sif) as sandbox:
Expand Down