Skip to content
Merged
13 changes: 9 additions & 4 deletions easybuild/tools/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2271,7 +2271,11 @@ def copy_file(path, target_path, force_in_dry_run=False):
:param force_in_dry_run: force copying of file during dry run
"""
if not force_in_dry_run and build_option('extended_dry_run'):
# If in dry run mode, do not copy any files, just lie about it
dry_run_msg("copied file %s to %s" % (path, target_path))
elif not os.path.exists(path) and not os.path.islink(path):
# NOTE: 'exists' will return False if 'path' is a broken symlink
raise EasyBuildError("Could not copy '%s' it does not exist!", path)
else:
try:
target_exists = os.path.exists(target_path)
Expand All @@ -2285,13 +2289,14 @@ def copy_file(path, target_path, force_in_dry_run=False):
_log.info("Copied contents of file %s to %s", path, target_path)
else:
mkdir(os.path.dirname(target_path), parents=True)
if os.path.exists(path):
shutil.copy2(path, target_path)
elif os.path.islink(path):
if os.path.islink(path):
# special care for copying broken symlinks
link_target = os.readlink(path)
symlink(link_target, target_path)
_log.info("%s copied to %s", path, target_path)
_log.info("created symlink from %s to %s", path, target_path)
else:
shutil.copy2(path, target_path)
_log.info("%s copied to %s", path, target_path)
except (IOError, OSError, shutil.Error) as err:
raise EasyBuildError("Failed to copy file %s to %s: %s", path, target_path, err)

Expand Down
16 changes: 15 additions & 1 deletion test/framework/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
from easybuild.tools import run
import easybuild.tools.filetools as ft
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.config import IGNORE, ERROR
from easybuild.tools.config import IGNORE, ERROR, update_build_option
from easybuild.tools.multidiff import multidiff
from easybuild.tools.py2vs3 import std_urllib

Expand Down Expand Up @@ -1663,6 +1663,20 @@ def test_copy_file(self):
self.assertTrue(ft.read_file(to_copy) == ft.read_file(target_path))
self.assertEqual(txt, '')

# Test that a non-existing file raises an exception
update_build_option('extended_dry_run', False)
src, target = os.path.join(self.test_prefix, 'this_file_does_not_exist'), os.path.join(self.test_prefix, 'toy')
self.assertErrorRegex(EasyBuildError, "Could not copy *", ft.copy_file, src, target)
# Test that copying a non-existing file in 'dry_run' mode does noting
update_build_option('extended_dry_run', True)
self.mock_stdout(True)
ft.copy_file(src, target, force_in_dry_run=False)
txt = self.get_stdout()
self.mock_stdout(False)
self.assertTrue(re.search("^copied file %s to %s" % (src, target), txt))
# However, if we add 'force_in_dry_run=True' it should throw an exception
self.assertErrorRegex(EasyBuildError, "Could not copy *", ft.copy_file, src, target, force_in_dry_run=True)

def test_copy_files(self):
"""Test copy_files function."""
test_ecs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs', 'test_ecs')
Expand Down