Skip to content
Merged
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
17 changes: 14 additions & 3 deletions easybuild/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
from easybuild.tools.config import find_last_log, get_repository, get_repositorypath, build_option
from easybuild.tools.containers.common import containerize
from easybuild.tools.docs import list_software
from easybuild.tools.filetools import adjust_permissions, cleanup, read_file, write_file
from easybuild.tools.filetools import adjust_permissions, cleanup, copy_file, copy_files, read_file, write_file
from easybuild.tools.github import check_github, close_pr, new_branch_github, find_easybuild_easyconfig
from easybuild.tools.github import install_github_token, list_prs, new_pr, new_pr_from_branch, merge_pr
from easybuild.tools.github import sync_branch_with_develop, sync_pr_with_develop, update_branch, update_pr
Expand Down Expand Up @@ -291,6 +291,9 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
eb_file = find_easybuild_easyconfig()
orig_paths.append(eb_file)

# last path is target when --copy-ec is used, so remove that from the list
target_path = orig_paths.pop() if options.copy_ec else None

categorized_paths = categorize_files_by_type(orig_paths)

# command line options that do not require any easyconfigs to be specified
Expand All @@ -302,9 +305,17 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
# determine paths to easyconfigs
determined_paths = det_easyconfig_paths(categorized_paths['easyconfigs'])

if options.fix_deprecated_easyconfigs or options.show_ec:
if options.fix_deprecated_easyconfigs:
if options.copy_ec or options.fix_deprecated_easyconfigs or options.show_ec:

if options.copy_ec:
if len(determined_paths) == 1:
copy_file(determined_paths[0], target_path)
else:
copy_files(determined_paths, target_path)

elif options.fix_deprecated_easyconfigs:
fix_deprecated_easyconfigs(determined_paths)

elif options.show_ec:
for path in determined_paths:
print_msg("Contents of %s:" % path)
Expand Down
24 changes: 23 additions & 1 deletion easybuild/tools/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1744,7 +1744,7 @@ def copy_file(path, target_path, force_in_dry_run=False):

:param path: the original filepath
:param target_path: path to copy the file to
:param force_in_dry_run: force running the command during dry run
:param force_in_dry_run: force copying of file during dry run
"""
if not force_in_dry_run and build_option('extended_dry_run'):
dry_run_msg("copied file %s to %s" % (path, target_path))
Expand All @@ -1767,6 +1767,28 @@ def copy_file(path, target_path, force_in_dry_run=False):
raise EasyBuildError("Failed to copy file %s to %s: %s", path, target_path, err)


def copy_files(paths, target_dir, force_in_dry_run=False):
"""
Copy list of files to specified target directory (which is created if it doesn't exist yet).

:param filepaths: list of files to copy
:param target_dir: target directory to copy files into
:param force_in_dry_run: force copying of files during dry run
"""
if not force_in_dry_run and build_option('extended_dry_run'):
dry_run_msg("copied files %s to %s" % (paths, target_dir))
else:
if os.path.exists(target_dir):
if os.path.isdir(target_dir):
_log.info("Copying easyconfigs into existing directory %s...", target_dir)
else:
raise EasyBuildError("%s exists but is not a directory", target_dir)
else:
mkdir(target_dir, parents=True)
for path in paths:
copy_file(path, target_dir)


def copy_dir(path, target_path, force_in_dry_run=False, **kwargs):
"""
Copy a directory from specified location to specified location
Expand Down
1 change: 1 addition & 0 deletions easybuild/tools/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ def override_options(self):
{'metavar': 'WHEN'}),
'consider-archived-easyconfigs': ("Also consider archived easyconfigs", None, 'store_true', False),
'containerize': ("Generate container recipe/image", None, 'store_true', False, 'C'),
'copy-ec': ("Copy specified easyconfig(s) to specified location", None, 'store_true', False),
'debug-lmod': ("Run Lmod modules tool commands in debug module", None, 'store_true', False),
'default-opt-level': ("Specify default optimisation level", 'choice', 'store', DEFAULT_OPT_LEVEL,
Compiler.COMPILER_OPT_FLAGS),
Expand Down
40 changes: 38 additions & 2 deletions test/framework/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1324,7 +1324,7 @@ def test_apply_patch(self):
self.assertErrorRegex(EasyBuildError, "Couldn't apply patch file", ft.apply_patch, toy_patch, path)

def test_copy_file(self):
""" Test copy_file """
"""Test copy_file function."""
testdir = os.path.dirname(os.path.abspath(__file__))
to_copy = os.path.join(testdir, 'easyconfigs', 'test_ecs', 't', 'toy', 'toy-0.0.eb')
target_path = os.path.join(self.test_prefix, 'toy.eb')
Expand Down Expand Up @@ -1385,8 +1385,44 @@ def test_copy_file(self):
self.assertTrue(ft.read_file(to_copy) == ft.read_file(target_path))
self.assertEqual(txt, '')

def test_copy_files(self):
"""Test copy_files function."""
test_ecs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs', 'test_ecs')
toy_ec = os.path.join(test_ecs, 't', 'toy', 'toy-0.0.eb')
toy_ec_txt = ft.read_file(toy_ec)
bzip2_ec = os.path.join(test_ecs, 'b', 'bzip2', 'bzip2-1.0.6-GCC-4.9.2.eb')
bzip2_ec_txt = ft.read_file(bzip2_ec)

# copying a single file to a non-existing directory
target_dir = os.path.join(self.test_prefix, 'target_dir1')
ft.copy_files([toy_ec], target_dir)
copied_toy_ec = os.path.join(target_dir, 'toy-0.0.eb')
self.assertTrue(os.path.exists(copied_toy_ec))
self.assertEqual(ft.read_file(copied_toy_ec), toy_ec_txt)

# copying a single file to an existing directory
ft.copy_files([bzip2_ec], target_dir)
copied_bzip2_ec = os.path.join(target_dir, 'bzip2-1.0.6-GCC-4.9.2.eb')
self.assertTrue(os.path.exists(copied_bzip2_ec))
self.assertEqual(ft.read_file(copied_bzip2_ec), bzip2_ec_txt)

# copying multiple files to a non-existing directory
target_dir = os.path.join(self.test_prefix, 'target_dir_multiple')
ft.copy_files([toy_ec, bzip2_ec], target_dir)
copied_toy_ec = os.path.join(target_dir, 'toy-0.0.eb')
self.assertTrue(os.path.exists(copied_toy_ec))
self.assertEqual(ft.read_file(copied_toy_ec), toy_ec_txt)
copied_bzip2_ec = os.path.join(target_dir, 'bzip2-1.0.6-GCC-4.9.2.eb')
self.assertTrue(os.path.exists(copied_bzip2_ec))
self.assertEqual(ft.read_file(copied_bzip2_ec), bzip2_ec_txt)

# copying files to an existing target that is not a directory results in an error
self.assertTrue(os.path.isfile(copied_toy_ec))
error_pattern = "/toy-0.0.eb exists but is not a directory"
self.assertErrorRegex(EasyBuildError, error_pattern, ft.copy_files, [bzip2_ec], copied_toy_ec)

def test_copy_dir(self):
"""Test copy_file"""
"""Test copy_dir function."""
testdir = os.path.dirname(os.path.abspath(__file__))
to_copy = os.path.join(testdir, 'easyconfigs', 'test_ecs', 'g', 'GCC')

Expand Down
83 changes: 81 additions & 2 deletions test/framework/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
from easybuild.tools.config import DEFAULT_MODULECLASSES
from easybuild.tools.config import find_last_log, get_build_log_path, get_module_syntax, module_classes
from easybuild.tools.environment import modify_env
from easybuild.tools.filetools import copy_dir, copy_file, download_file, mkdir, read_file, remove_file
from easybuild.tools.filetools import which, write_file
from easybuild.tools.filetools import change_dir, copy_dir, copy_file, download_file, mkdir, read_file
from easybuild.tools.filetools import remove_dir, remove_file, which, write_file
from easybuild.tools.github import GITHUB_RAW, GITHUB_EB_MAIN, GITHUB_EASYCONFIGS_REPO
from easybuild.tools.github import URL_SEPARATOR, fetch_github_token
from easybuild.tools.modules import Lmod
Expand Down Expand Up @@ -828,6 +828,85 @@ def test_show_ec(self):
regex = re.compile(pattern, re.M)
self.assertTrue(regex.search(stdout), "Pattern '%s' found in: %s" % (regex.pattern, stdout))

def test_copy_ec(self):
"""Test --copy-ec."""

topdir = os.path.dirname(os.path.abspath(__file__))
test_easyconfigs_dir = os.path.join(topdir, 'easyconfigs', 'test_ecs')

toy_ec_txt = read_file(os.path.join(test_easyconfigs_dir, 't', 'toy', 'toy-0.0.eb'))
bzip2_ec_txt = read_file(os.path.join(test_easyconfigs_dir, 'b', 'bzip2', 'bzip2-1.0.6-GCC-4.9.2.eb'))

# basic test: copying one easyconfig file to a non-existing absolute path
test_ec = os.path.join(self.test_prefix, 'test.eb')
args = ['--copy-ec', 'toy-0.0.eb', test_ec]
self.eb_main(args)

self.assertTrue(os.path.exists(test_ec))
self.assertEqual(toy_ec_txt, read_file(test_ec))

remove_file(test_ec)

# basic test: copying one easyconfig file to a non-existing relative path
cwd = change_dir(self.test_prefix)
target_fn = 'test.eb'
self.assertFalse(os.path.exists(target_fn))

args = ['--copy-ec', 'toy-0.0.eb', target_fn]
self.eb_main(args)

change_dir(cwd)

self.assertTrue(os.path.exists(test_ec))
self.assertEqual(toy_ec_txt, read_file(test_ec))

# copying one easyconfig into an existing directory
test_target_dir = os.path.join(self.test_prefix, 'test_target_dir')
mkdir(test_target_dir)
args = ['--copy-ec', 'toy-0.0.eb', test_target_dir]
self.eb_main(args)

copied_toy_ec = os.path.join(test_target_dir, 'toy-0.0.eb')
self.assertTrue(os.path.exists(copied_toy_ec))
self.assertEqual(toy_ec_txt, read_file(copied_toy_ec))

remove_dir(test_target_dir)

def check_copied_files():
"""Helper function to check result of copying multiple easyconfigs."""
self.assertTrue(os.path.exists(test_target_dir))
self.assertEqual(sorted(os.listdir(test_target_dir)), ['bzip2-1.0.6-GCC-4.9.2.eb', 'toy-0.0.eb'])
copied_toy_ec = os.path.join(test_target_dir, 'toy-0.0.eb')
self.assertTrue(os.path.exists(copied_toy_ec))
self.assertEqual(toy_ec_txt, read_file(copied_toy_ec))
copied_bzip2_ec = os.path.join(test_target_dir, 'bzip2-1.0.6-GCC-4.9.2.eb')
self.assertTrue(os.path.exists(copied_bzip2_ec))
self.assertEqual(bzip2_ec_txt, read_file(copied_bzip2_ec))

# copying multiple easyconfig files to a non-existing target directory (which is created automatically)
args = ['--copy-ec', 'toy-0.0.eb', 'bzip2-1.0.6-GCC-4.9.2.eb', test_target_dir]
self.eb_main(args)

check_copied_files()

remove_dir(test_target_dir)

# same but with relative path for target dir
change_dir(self.test_prefix)
args[-1] = os.path.basename(test_target_dir)
self.assertFalse(os.path.exists(args[-1]))

self.eb_main(args)

check_copied_files()

# copying multiple easyconfig to an existing target file resuts in an error
target = os.path.join(self.test_prefix, 'test.eb')
self.assertTrue(os.path.isfile(target))
args = ['--copy-ec', 'toy-0.0.eb', 'bzip2-1.0.6-GCC-4.9.2.eb', target]
error_pattern = ".*/test.eb exists but is not a directory"
self.assertErrorRegex(EasyBuildError, error_pattern, self.eb_main, args, raise_error=True)

def test_dry_run(self):
"""Test dry run (long format)."""
fd, dummylogfn = tempfile.mkstemp(prefix='easybuild-dummy', suffix='.log')
Expand Down