Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ab933f1
Allow use of --copy-ec with --from-pr
Oct 19, 2020
9accd5d
Appease the hound
Oct 19, 2020
e2f270a
Fix broken tests
Oct 19, 2020
64e95f2
Fix broken tests
Oct 19, 2020
4e6980f
Fix broken tests (2nd attempt)
Oct 19, 2020
fceea89
Reinstate the copy of the easyconfigs from the PR
Oct 19, 2020
51f0b06
Add test for --from-pr and --copy-ec
Oct 19, 2020
d633ece
Fix linting and add additional tests
Oct 19, 2020
f8db57d
Address most comments in the review
Oct 19, 2020
b3615f4
Fix linting
Oct 19, 2020
2408626
Fix linting
Oct 19, 2020
34cd4a5
Rework the approach and add additional tests
Oct 20, 2020
f821af1
Rework the approach and add additional tests
Oct 20, 2020
33d8570
Fix comment
Oct 20, 2020
3980dc9
Be a little more careful with patches
Oct 20, 2020
f7aa646
Retain old behaviour when using try-*
Oct 20, 2020
11f5a48
Tidy up the new tests
Oct 20, 2020
0141243
Keep our patch list unique
Oct 20, 2020
e61e72d
Fix copy_ecs_to_target for case where I want to copy a single file to…
Oct 20, 2020
30145e4
Fix broken test
Oct 20, 2020
49b4f47
Fix broken test
Oct 20, 2020
1a8eecf
Fix broken test
Oct 20, 2020
380387b
Fix broken test
Oct 20, 2020
eedbfd1
Fix broken test
Oct 20, 2020
ae9e0ea
Only grab the current working directory once at the beginning.
Oct 20, 2020
c5560c4
Fix GitHub tools leaving you in temporary directory
Oct 20, 2020
26d9115
Fix GitHub tools leaving you in temporary directory
Oct 20, 2020
7944c0a
See if starting in the right directory makes a difference
Oct 20, 2020
6e5be8d
Final fix on broken test
Oct 20, 2020
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
20 changes: 20 additions & 0 deletions easybuild/framework/easyconfig/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
from easybuild.tools.build_log import EasyBuildError, print_msg, print_warning
from easybuild.tools.config import build_option
from easybuild.tools.environment import restore_env
from easybuild.tools.filetools import copy_file, copy_files
from easybuild.tools.filetools import find_easyconfigs, is_patch_file, read_file, resolve_path, which, write_file
from easybuild.tools.github import fetch_easyconfigs_from_pr, download_repo
from easybuild.tools.multidiff import multidiff
Expand Down Expand Up @@ -728,3 +729,22 @@ def avail_easyblocks():
easyblock_mod_name, easyblocks[easyblock_mod_name]['loc'], path)

return easyblocks


def copy_ecs_to_target(determined_paths, target_path, prefix=False, target_is_dir=False):
"""
Copy list of easyconfigs to specified path

:param determined_paths: paths to ecs to copy
:param target_path: target to copy files to
:param prefix: include message prefix characters
:param target_is_dir: target is always a directory
"""
if len(determined_paths) == 1 and not target_is_dir:
copy_file(determined_paths[0], target_path)
print_msg("%s copied to %s" % (os.path.basename(determined_paths[0]), target_path), prefix=prefix)
elif determined_paths:
copy_files(determined_paths, target_path)
print_msg("%d file(s) copied to %s" % (len(determined_paths), target_path), prefix=prefix)
else:
raise EasyBuildError("One of more files to copy should be specified!")
61 changes: 43 additions & 18 deletions easybuild/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import os
import stat
import sys
import tempfile
import traceback

# IMPORTANT this has to be the first easybuild import as it customises the logging
Expand All @@ -50,17 +51,18 @@
from easybuild.framework.easyconfig.easyconfig import clean_up_easyconfigs
from easybuild.framework.easyconfig.easyconfig import fix_deprecated_easyconfigs, verify_easyconfig_filename
from easybuild.framework.easyconfig.style import cmdline_easyconfigs_style_check
from easybuild.framework.easyconfig.tools import categorize_files_by_type, dep_graph
from easybuild.framework.easyconfig.tools import categorize_files_by_type, copy_ecs_to_target, dep_graph
from easybuild.framework.easyconfig.tools import det_easyconfig_paths, dump_env_script, get_paths_for
from easybuild.framework.easyconfig.tools import parse_easyconfigs, review_pr, run_contrib_checks, skip_available
from easybuild.framework.easyconfig.tweak import obtain_ec_for, tweak
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, copy_file, copy_files, dump_index, load_index
from easybuild.tools.filetools import adjust_permissions, cleanup, dump_index, load_index
from easybuild.tools.filetools import read_file, register_lock_cleanup_signal_handlers, 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 check_github, close_pr, fetch_files_from_pr, find_easybuild_easyconfig
from easybuild.tools.github import install_github_token, list_prs, merge_pr, new_branch_github, new_pr
from easybuild.tools.github import new_pr_from_branch
from easybuild.tools.github import sync_branch_with_develop, sync_pr_with_develop, update_branch, update_pr
from easybuild.tools.hooks import START, END, load_hooks, run_hook
from easybuild.tools.modules import modules_tool
Expand Down Expand Up @@ -303,12 +305,16 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
eb_file = find_easybuild_easyconfig()
orig_paths.append(eb_file)

if len(orig_paths) == 1:
# if only one easyconfig file is specified, use current directory as target directory
# if only one easyconfig is specified, or if none are specified and we are using --from-pr,
# use current directory as target directory
if len(orig_paths) == 1 and not (options.copy_ec and options.from_pr):
target_path = os.getcwd()
elif orig_paths:
# 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
else:
# if no easyconfig files are specified and we are using --from-pr, use current directory as target directory
target_path = os.getcwd() if (options.copy_ec and options.from_pr) else None

categorized_paths = categorize_files_by_type(orig_paths)

Expand All @@ -321,17 +327,37 @@ 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.copy_ec and not tweaked_ecs_paths) or options.fix_deprecated_easyconfigs or options.show_ec:
# only copy easyconfigs here if we're not using --try-* (that's are handled below)
copy_ec = options.copy_ec and not tweaked_ecs_paths
if copy_ec or options.fix_deprecated_easyconfigs or options.show_ec:
if options.from_pr:
# pull in the paths to all the changed files in the PR (need to do this in a new temp dir)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ocaisa This whole code block below if options.from_pr should be moved to a separate function imho, blowing up the logic in main like this doesn't help with keeping things manageable...

Not sure what an appropriate function name would be, but since it's specific to --from-pr I would park it in easybuild.tools.github?

pr_paths = fetch_files_from_pr(pr=options.from_pr, path=tempfile.mktemp())
for pr_path in pr_paths:
# we assumed that the last argument from the command line was the target_path but if it appears in the
# PR file list then it was most likely intended to use the CWD and (also) copy that particular file
if target_path == os.path.basename(pr_path):
if not orig_paths:
# It should have been the only easyconfig selected
determined_paths = [pr_path]
else:
if os.path.basename(pr_path) not in [os.path.basename(path) for path in determined_paths]:
determined_paths.append(pr_path)
target_path = os.getcwd()
other_pr_paths = []
for ec_path in determined_paths:
for pr_path in pr_paths:
if os.path.basename(ec_path) == os.path.basename(pr_path):
# Search for any associated patches (they would have the same dirname)
for patch_path in pr_paths:
if pr_path != patch_path and os.path.dirname(pr_path) == os.path.dirname(patch_path):
# if it's an easyconfig, we already have it covered
if not patch_path.endswith('.eb') and patch_path not in other_pr_paths:
other_pr_paths.append(patch_path)
determined_paths += other_pr_paths

if options.copy_ec:
if len(determined_paths) == 1:
copy_file(determined_paths[0], target_path)
print_msg("%s copied to %s" % (os.path.basename(determined_paths[0]), target_path), prefix=False)
elif len(determined_paths) > 1:
copy_files(determined_paths, target_path)
print_msg("%d file(s) copied to %s" % (len(determined_paths), target_path), prefix=False)
else:
raise EasyBuildError("One of more files to copy should be specified!")
copy_ecs_to_target(determined_paths, target_path)

elif options.fix_deprecated_easyconfigs:
fix_deprecated_easyconfigs(determined_paths)
Expand Down Expand Up @@ -361,7 +387,7 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
if options.regtest or options.aggregate_regtest:
_log.info("Running regression test")
# fallback: easybuild-easyconfigs install path
regtest_ok = regtest([path[0] for path in paths] or easyconfigs_pkg_paths, modtool)
regtest_ok = regtest([x for (x, _) in paths] or easyconfigs_pkg_paths, modtool)
if not regtest_ok:
_log.info("Regression test failed (partially)!")
sys.exit(31) # exit -> 3x1t -> 31
Expand Down Expand Up @@ -429,8 +455,7 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
if tweaked_ecs_in_all_ecs:
# Clean them, then copy them
clean_up_easyconfigs(tweaked_ecs_in_all_ecs)
copy_files(tweaked_ecs_in_all_ecs, target_path)
print_msg("%d file(s) copied to %s" % (len(tweaked_ecs_in_all_ecs), target_path), prefix=False)
copy_ecs_to_target(tweaked_ecs_in_all_ecs, target_path, target_is_dir=True)

# creating/updating PRs
if pr_options:
Expand Down
4 changes: 4 additions & 0 deletions easybuild/tools/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ def download_repo(repo=GITHUB_EASYCONFIGS_REPO, branch='master', account=GITHUB_
_log.debug("%s downloaded to %s, extracting now" % (base_name, path))

base_dir = extract_file(target_path, path, forced=True, change_into_dir=False)
working_directory = os.getcwd()
change_dir(base_dir)
extracted_path = os.path.join(base_dir, extracted_dir_name)

Expand All @@ -373,6 +374,9 @@ def download_repo(repo=GITHUB_EASYCONFIGS_REPO, branch='master', account=GITHUB_

write_file(latest_sha_path, latest_commit_sha, forced=True)

# go back to previous working directory
change_dir(working_directory)

_log.debug("Repo %s at branch %s extracted into %s" % (repo, branch, extracted_path))
return extracted_path

Expand Down
63 changes: 61 additions & 2 deletions test/framework/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,7 @@ def check_copied_files():

check_copied_files()

# copying multiple easyconfig to an existing target file resuts in an error
# copying multiple easyconfig to an existing target file results 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]
Expand All @@ -1072,7 +1072,66 @@ def check_copied_files():
self.assertTrue(os.path.exists(copied_toy_cwd))
self.assertEqual(read_file(copied_toy_cwd), toy_ec_txt)

# --copy-ec without arguments results in a proper error
# Test --copy-ec coupled with --from-pr

test_working_dir = os.path.join(self.test_prefix, 'test_working_dir')
mkdir(test_working_dir)
test_target_dir = os.path.join(self.test_prefix, 'test_target_dir')
# Make sure the test target directory doesn't exist
remove_dir(test_target_dir)

all_ecs_pr8007 = [
'Arrow-0.7.1-intel-2017b-Python-3.6.3.eb',
'bat-0.3.3-fix-pyspark.patch',
'bat-0.3.3-intel-2017b-Python-3.6.3.eb',
]

# test use of `--copy-ec` with `--from-pr` to the cwd
change_dir(test_working_dir)
args = ['--copy-ec', '--from-pr', '8007']
stdout = mocked_main(args)
self.assertEqual(stdout, '3 file(s) copied to %s' % test_working_dir)
# check that the files exist
for pr_file in all_ecs_pr8007:
self.assertTrue(os.path.exists(os.path.join(test_working_dir, pr_file)))
remove_file(os.path.join(test_working_dir, pr_file))

# copying multiple easyconfig files to a non-existing target directory (which is created automatically)
args = ['--copy-ec', '--from-pr', '8007', test_target_dir]
stdout = mocked_main(args)
self.assertEqual(stdout, '3 file(s) copied to %s' % test_target_dir)
for pr_file in all_ecs_pr8007:
self.assertTrue(os.path.exists(os.path.join(test_target_dir, pr_file)))
remove_dir(test_target_dir)

# test where we select a single file from a PR but also has a patch file
args = ['--copy-ec', '--from-pr', '8007', 'bat-0.3.3-intel-2017b-Python-3.6.3.eb', test_target_dir]
stdout = mocked_main(args)
self.assertEqual(stdout, '2 file(s) copied to %s' % test_target_dir)
for pr_file in ['bat-0.3.3-fix-pyspark.patch', 'bat-0.3.3-intel-2017b-Python-3.6.3.eb']:
self.assertTrue(os.path.exists(os.path.join(test_target_dir, pr_file)))
remove_dir(test_target_dir)

# test the same thing but where we don't provide a target directory
change_dir(test_working_dir)
args = ['--copy-ec', '--from-pr', '8007', 'bat-0.3.3-intel-2017b-Python-3.6.3.eb']
stdout = mocked_main(args)
self.assertEqual(stdout, '2 file(s) copied to %s' % test_working_dir)
for pr_file in ['bat-0.3.3-fix-pyspark.patch', 'bat-0.3.3-intel-2017b-Python-3.6.3.eb']:
path = os.path.join(test_working_dir, pr_file)
self.assertTrue(os.path.exists(path))
remove_file(path)

# test with only one ec in the PR (final argument is taken as a filename)
test_ec = os.path.join(self.test_prefix, 'test.eb')
args = ['--copy-ec', '--from-pr', '11521', test_ec]
ec_pr11521 = "ExifTool-12.00-GCCcore-9.3.0.eb"
stdout = mocked_main(args)
self.assertEqual(stdout, '%s copied to %s' % (ec_pr11521, test_ec))
self.assertTrue(os.path.exists(test_ec))
remove_file(test_ec)

# --copy-ec without arguments (and no --from-pr) results in a proper error
args = ['--copy-ec']
error_pattern = "One of more files to copy should be specified!"
self.assertErrorRegex(EasyBuildError, error_pattern, self.eb_main, args, raise_error=True)
Expand Down